Code

dbf220cef4f26d718a505b8a9678812bbd0a1360
[sysdb.git] / t / unit / core / store_test.c
1 /*
2  * SysDB - t/unit/core/store_test.c
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif
32 #include "core/store.h"
33 #include "core/store-private.h"
34 #include "testutils.h"
36 #include <check.h>
37 #include <string.h>
38 #include <strings.h>
40 static void
41 populate(void)
42 {
43         sdb_data_t datum;
45         sdb_store_host("h1", 1);
46         sdb_store_host("h2", 3);
48         datum.type = SDB_TYPE_STRING;
49         datum.data.string = "v1";
50         sdb_store_attribute("h1", "k1", &datum, 1);
51         datum.data.string = "v2";
52         sdb_store_attribute("h1", "k2", &datum, 2);
53         datum.data.string = "v3";
54         sdb_store_attribute("h1", "k3", &datum, 2);
56         /* make sure that older updates don't overwrite existing values */
57         datum.data.string = "fail";
58         sdb_store_attribute("h1", "k2", &datum, 1);
59         sdb_store_attribute("h1", "k3", &datum, 2);
61         sdb_store_metric("h1", "m1", /* store */ NULL, 2);
62         sdb_store_metric("h1", "m2", /* store */ NULL, 1);
63         sdb_store_metric("h2", "m1", /* store */ NULL, 1);
65         sdb_store_service("h2", "s1", 1);
66         sdb_store_service("h2", "s2", 2);
68         datum.type = SDB_TYPE_INTEGER;
69         datum.data.integer = 42;
70         sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
72         datum.data.integer = 123;
73         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
74         datum.data.integer = 4711;
75         sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
77         /* don't overwrite k1 */
78         datum.data.integer = 666;
79         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
80 } /* populate */
82 START_TEST(test_store_host)
83 {
84         struct {
85                 const char *name;
86                 sdb_time_t  last_update;
87                 int         expected;
88         } golden_data[] = {
89                 { "a", 1, 0 },
90                 { "a", 2, 0 },
91                 { "a", 1, 1 },
92                 { "b", 1, 0 },
93                 { "b", 1, 1 },
94                 { "A", 1, 1 }, /* case-insensitive */
95                 { "A", 3, 0 },
96         };
98         struct {
99                 const char *name;
100                 _Bool       has;
101         } golden_hosts[] = {
102                 { "a", 1 == 1 },
103                 { "b", 1 == 1 },
104                 { "c", 0 == 1 },
105                 { "A", 1 == 1 },
106         };
108         size_t i;
110         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
111                 int status;
113                 status = sdb_store_host(golden_data[i].name,
114                                 golden_data[i].last_update);
115                 fail_unless(status == golden_data[i].expected,
116                                 "sdb_store_host(%s, %d) = %d; expected: %d",
117                                 golden_data[i].name, (int)golden_data[i].last_update,
118                                 status, golden_data[i].expected);
119         }
121         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
122                 _Bool has;
124                 has = sdb_store_has_host(golden_hosts[i].name);
125                 fail_unless(has == golden_hosts[i].has,
126                                 "sdb_store_has_host(%s) = %d; expected: %d",
127                                 golden_hosts[i].name, has, golden_hosts[i].has);
128         }
130 END_TEST
132 START_TEST(test_store_get_host)
134         char *golden_hosts[] = { "a", "b", "c" };
135         char *unknown_hosts[] = { "x", "y", "z" };
136         size_t i;
138         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
139                 int status = sdb_store_host(golden_hosts[i], 1);
140                 fail_unless(status >= 0,
141                                 "sdb_store_host(%s) = %d; expected: >=0",
142                                 golden_hosts[i], status);
143         }
145         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
146                 sdb_store_obj_t *sobj1, *sobj2;
147                 int ref_cnt;
149                 fail_unless(sdb_store_has_host(golden_hosts[i]),
150                                 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
151                                 golden_hosts[i]);
153                 sobj1 = sdb_store_get_host(golden_hosts[i]);
154                 fail_unless(sobj1 != NULL,
155                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
156                                 golden_hosts[i]);
157                 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
159                 fail_unless(ref_cnt > 1,
160                                 "sdb_store_get_host(%s) did not increment ref count: "
161                                 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
163                 sobj2 = sdb_store_get_host(golden_hosts[i]);
164                 fail_unless(sobj2 != NULL,
165                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
166                                 golden_hosts[i]);
168                 fail_unless(sobj1 == sobj2,
169                                 "sdb_store_get_host(%s) returned different objects "
170                                 "in successive calls", golden_hosts[i]);
171                 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
172                                 "sdb_store_get_hosts(%s) did not increment ref count "
173                                 "(first call: %d; second call: %d)",
174                                 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
176                 sdb_object_deref(SDB_OBJ(sobj1));
177                 sdb_object_deref(SDB_OBJ(sobj2));
178         }
179         for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
180                 sdb_store_obj_t *sobj;
182                 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
183                                 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
184                                 unknown_hosts[i]);
186                 sobj = sdb_store_get_host(unknown_hosts[i]);
187                 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
188                                 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
189         }
191 END_TEST
193 START_TEST(test_store_attr)
195         struct {
196                 const char *host;
197                 const char *key;
198                 char       *value;
199                 sdb_time_t  last_update;
200                 int         expected;
201         } golden_data[] = {
202                 { "k", "k",  "v",  1, -1 },
203                 { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
204                 { "l", "k1", "v1", 1,  0 },
205                 { "l", "k1", "v2", 2,  0 },
206                 { "l", "k1", "v3", 2,  1 },
207                 { "l", "k2", "v1", 1,  0 },
208                 { "m", "k",  "v1", 1,  0 },
209                 { "m", "k",  "v2", 1,  1 },
210         };
212         size_t i;
214         sdb_store_host("l", 1);
215         sdb_store_host("m", 1);
216         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
217                 sdb_data_t datum;
218                 int status;
220                 /* XXX: test other types as well */
221                 datum.type = SDB_TYPE_STRING;
222                 datum.data.string = golden_data[i].value;
224                 status = sdb_store_attribute(golden_data[i].host,
225                                 golden_data[i].key, &datum,
226                                 golden_data[i].last_update);
227                 fail_unless(status == golden_data[i].expected,
228                                 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
229                                 golden_data[i].host, golden_data[i].key, golden_data[i].value,
230                                 golden_data[i].last_update, status, golden_data[i].expected);
231         }
233 END_TEST
235 START_TEST(test_store_metric)
237         sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
238         sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
240         struct {
241                 const char *host;
242                 const char *metric;
243                 sdb_metric_store_t *store;
244                 sdb_time_t  last_update;
245                 int         expected;
246         } golden_data[] = {
247                 { "k", "m",  NULL,    1, -1 },
248                 { "k", "m",  NULL,    1, -1 }, /* retry to ensure the host is not created */
249                 { "k", "m",  &store1, 1, -1 },
250                 { "l", "m1", NULL,    1,  0 },
251                 { "l", "m1", &store1, 2,  0 },
252                 { "l", "m1", &store1, 3,  0 },
253                 { "l", "m1", NULL,    3,  1 },
254                 { "l", "m2", &store1, 1,  0 },
255                 { "l", "m2", &store2, 2,  0 },
256                 { "l", "m2", NULL,    3,  0 },
257                 { "m", "m",  &store1, 1,  0 },
258                 { "m", "m",  NULL,    2,  0 },
259                 { "m", "m",  NULL,    2,  1 },
260                 { "m", "m",  &store1, 3,  0 },
261                 { "m", "m",  &store2, 4,  0 },
262                 { "m", "m",  NULL,    5,  0 },
263         };
265         size_t i;
267         sdb_store_host("m", 1);
268         sdb_store_host("l", 1);
269         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
270                 int status;
272                 status = sdb_store_metric(golden_data[i].host,
273                                 golden_data[i].metric, golden_data[i].store,
274                                 golden_data[i].last_update);
275                 fail_unless(status == golden_data[i].expected,
276                                 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
277                                 golden_data[i].host, golden_data[i].metric,
278                                 golden_data[i].store, golden_data[i].last_update,
279                                 status, golden_data[i].expected);
280         }
282 END_TEST
284 START_TEST(test_store_metric_attr)
286         struct {
287                 const char *host;
288                 const char *metric;
289                 const char *attr;
290                 const sdb_data_t value;
291                 sdb_time_t  last_update;
292                 int expected;
293         } golden_data[] = {
294                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
295                 /* retry, it should still fail */
296                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
297                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
298                 /* retry, it should still fail */
299                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
300                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
301                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
302                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
303                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
304                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
305                 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
306                 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
307         };
309         size_t i;
311         sdb_store_host("m", 1);
312         sdb_store_host("l", 1);
313         sdb_store_metric("m", "m1", NULL, 1);
314         sdb_store_metric("l", "m1", NULL, 1);
315         sdb_store_metric("l", "m2", NULL, 1);
317         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
318                 int status;
320                 status = sdb_store_metric_attr(golden_data[i].host,
321                                 golden_data[i].metric, golden_data[i].attr,
322                                 &golden_data[i].value, golden_data[i].last_update);
323                 fail_unless(status == golden_data[i].expected,
324                                 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
325                                 "expected: %d", golden_data[i].host, golden_data[i].metric,
326                                 golden_data[i].attr, golden_data[i].value.data.integer,
327                                 golden_data[i].last_update, status, golden_data[i].expected);
328         }
330 END_TEST
332 START_TEST(test_store_service)
334         struct {
335                 const char *host;
336                 const char *svc;
337                 sdb_time_t  last_update;
338                 int         expected;
339         } golden_data[] = {
340                 { "k", "s",  1, -1 },
341                 { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
342                 { "l", "s1", 1,  0 },
343                 { "l", "s1", 2,  0 },
344                 { "l", "s1", 2,  1 },
345                 { "l", "s2", 1,  0 },
346                 { "m", "s",  1,  0 },
347                 { "m", "s",  1,  1 },
348         };
350         size_t i;
352         sdb_store_host("m", 1);
353         sdb_store_host("l", 1);
354         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
355                 int status;
357                 status = sdb_store_service(golden_data[i].host,
358                                 golden_data[i].svc, golden_data[i].last_update);
359                 fail_unless(status == golden_data[i].expected,
360                                 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
361                                 golden_data[i].host, golden_data[i].svc,
362                                 golden_data[i].last_update, status, golden_data[i].expected);
363         }
365 END_TEST
367 START_TEST(test_store_service_attr)
369         struct {
370                 const char *host;
371                 const char *svc;
372                 const char *attr;
373                 const sdb_data_t value;
374                 sdb_time_t  last_update;
375                 int expected;
376         } golden_data[] = {
377                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
378                 /* retry, it should still fail */
379                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
380                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
381                 /* retry, it should still fail */
382                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
383                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
384                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
385                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
386                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
387                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
388                 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
389                 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
390         };
392         size_t i;
394         sdb_store_host("m", 1);
395         sdb_store_host("l", 1);
396         sdb_store_service("m", "s1", 1);
397         sdb_store_service("l", "s1", 1);
398         sdb_store_service("l", "s2", 1);
400         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
401                 int status;
403                 status = sdb_store_service_attr(golden_data[i].host,
404                                 golden_data[i].svc, golden_data[i].attr,
405                                 &golden_data[i].value, golden_data[i].last_update);
406                 fail_unless(status == golden_data[i].expected,
407                                 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
408                                 "expected: %d", golden_data[i].host, golden_data[i].svc,
409                                 golden_data[i].attr, golden_data[i].value.data.integer,
410                                 golden_data[i].last_update, status, golden_data[i].expected);
411         }
413 END_TEST
415 static struct {
416         const char *hostname;
417         const char *attr; /* optional */
418         int field;
419         int expected;
420         sdb_data_t value;
421 } get_field_data[] = {
422         { NULL,   NULL, 0, -1, { SDB_TYPE_NULL, { 0 } } },
423         { NULL,   NULL,   SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
424         { NULL,   NULL,   SDB_FIELD_INTERVAL,    -1, { SDB_TYPE_NULL, { 0 } } },
425         { NULL,   NULL,   SDB_FIELD_AGE,         -1, { SDB_TYPE_NULL, { 0 } } },
426         { NULL,   NULL,   SDB_FIELD_NAME,        -1, { SDB_TYPE_NULL, { 0 } } },
427         { NULL,   NULL,   SDB_FIELD_BACKEND,     -1, { SDB_TYPE_NULL, { 0 } } },
428         { NULL,   NULL,   SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
429         { "host", NULL,   SDB_FIELD_LAST_UPDATE,  0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
430         { "host", NULL,   SDB_FIELD_INTERVAL,     0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
431         /* the test will handle AGE specially */
432         { "host", NULL,   SDB_FIELD_AGE,          0, { SDB_TYPE_NULL, { 0 } } },
433         { "host", NULL,   SDB_FIELD_NAME,         0, { SDB_TYPE_STRING, { .string = "host" } } },
434         { "host", NULL,   SDB_FIELD_BACKEND,      0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
435         { "host", NULL,   SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
436         { "host", "attr", SDB_FIELD_LAST_UPDATE,  0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
437         { "host", "attr", SDB_FIELD_INTERVAL,     0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
438         /* the test will handle AGE specially */
439         { "host", "attr", SDB_FIELD_AGE,          0, { SDB_TYPE_NULL, { 0 } } },
440         { "host", "attr", SDB_FIELD_NAME,         0, { SDB_TYPE_STRING, { .string = "attr" } } },
441         { "host", "attr", SDB_FIELD_BACKEND,      0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
442         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_INTEGER, { .integer = 1 } } },
443         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } } },
444         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_STRING, { .string = "foo" } } },
445         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_DATETIME, { .datetime = 1234567890L } } },
446         { "host", "a",    SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
447         { "host", "a",    SDB_FIELD_INTERVAL,    -1, { SDB_TYPE_NULL, { 0 } } },
448         { "host", "a",    SDB_FIELD_AGE,         -1, { SDB_TYPE_NULL, { 0 } } },
449         { "host", "a",    SDB_FIELD_NAME,        -1, { SDB_TYPE_NULL, { 0 } } },
450         { "host", "a",    SDB_FIELD_BACKEND,     -1, { SDB_TYPE_NULL, { 0 } } },
451         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
452         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
453         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
454         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
455 };
457 /* returns a tuple <type> <name> */
458 #define OBJ_NAME(obj) \
459         (obj) ? SDB_STORE_TYPE_TO_NAME(obj->type) : "NULL", \
460         (obj) ? SDB_OBJ(obj)->name : ""
461 START_TEST(test_get_field)
463         sdb_store_obj_t *obj = NULL;
464         sdb_data_t value = SDB_DATA_INIT;
465         char value_str[128], expected_value_str[128];
466         sdb_time_t now = sdb_gettime();
467         int check;
469         sdb_store_host("host", 10);
470         sdb_store_host("host", 20);
471         sdb_store_attribute("host", "attr", &get_field_data[_i].value, 10);
472         sdb_store_attribute("host", "attr", &get_field_data[_i].value, 20);
474         if (get_field_data[_i].hostname) {
475                 obj = sdb_store_get_host(get_field_data[_i].hostname);
476                 ck_assert(obj != NULL);
478                 if (get_field_data[_i].attr) {
479                         sdb_store_obj_t *tmp = sdb_store_get_child(obj,
480                                         SDB_ATTRIBUTE, get_field_data[_i].attr);
481                         sdb_object_deref(SDB_OBJ(obj));
482                         obj = tmp;
483                 }
484         }
486         check = sdb_store_get_field(obj, get_field_data[_i].field, NULL);
487         fail_unless(check == get_field_data[_i].expected,
488                         "sdb_store_get_field(%s %s, %s, NULL) = %d; expected: %d",
489                         OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
490                         check, get_field_data[_i].expected);
491         check = sdb_store_get_field(obj, get_field_data[_i].field, &value);
492         fail_unless(check == get_field_data[_i].expected,
493                         "sdb_store_get_field(%s %s, %s, <value>) = %d; expected: %d",
494                         OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
495                         check, get_field_data[_i].expected);
497         if (get_field_data[_i].expected) {
498                 sdb_object_deref(SDB_OBJ(obj));
499                 return;
500         }
502         if (get_field_data[_i].field == SDB_FIELD_AGE) {
503                 get_field_data[_i].value.type = SDB_TYPE_DATETIME;
504                 get_field_data[_i].value.data.datetime = now;
505         }
507         sdb_data_format(&value, value_str, sizeof(value_str), 0);
508         sdb_data_format(&get_field_data[_i].value, expected_value_str,
509                         sizeof(expected_value_str), 0);
511         if (get_field_data[_i].field == SDB_FIELD_AGE) {
512                 fail_unless((value.type == SDB_TYPE_DATETIME)
513                                 && (value.data.datetime >= now),
514                                 "sdb_store_get_field(%s %s, %s, <value>) "
515                                 "returned value %s; expected >=%s", OBJ_NAME(obj),
516                                 SDB_FIELD_TO_NAME(get_field_data[_i].field),
517                                 value_str, expected_value_str);
518         }
519         else {
520                 fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
521                                 "sdb_store_get_field(%s %s, %s, <value>) "
522                                 "returned value %s; expected %s", OBJ_NAME(obj),
523                                 SDB_FIELD_TO_NAME(get_field_data[_i].field),
524                                 value_str, expected_value_str);
525         }
526         sdb_data_free_datum(&value);
527         sdb_object_deref(SDB_OBJ(obj));
529 END_TEST
530 #undef OBJ_NAME
532 START_TEST(test_get_child)
534         struct {
535                 const char *host;
536                 const char *name;
537                 int type;
538                 int expected;
539         } golden_data[] = {
540                 { "h1", NULL, SDB_HOST,       0 },
541                 { "h1", NULL, SDB_SERVICE,   -1 },
542                 { "h1", NULL, SDB_METRIC,    -1 },
543                 { "h1", NULL, SDB_ATTRIBUTE, -1 },
544                 { "h2", NULL, SDB_HOST,       0 },
545                 { "h2", NULL, SDB_SERVICE,   -1 },
546                 { "h2", NULL, SDB_METRIC,    -1 },
547                 { "h2", NULL, SDB_ATTRIBUTE, -1 },
548                 { "h3", NULL, SDB_HOST,      -1 },
549                 { "h1", "k1", SDB_ATTRIBUTE,  0 },
550                 { "h1", "x1", SDB_ATTRIBUTE, -1 },
551                 { "h2", "k1", SDB_ATTRIBUTE, -1 },
552                 { "h1", "k1", SDB_SERVICE,   -1 },
553                 { "h1", "k1", SDB_METRIC,    -1 },
554                 { "h1", "s1", SDB_SERVICE,   -1 },
555                 { "h2", "s1", SDB_SERVICE,    0 },
556                 { "h1", "m2", SDB_METRIC,     0 },
557                 { "h2", "m2", SDB_METRIC,    -1 },
558         };
560         size_t i;
562         populate();
564         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
565                 sdb_store_obj_t *obj;
566                 const char *expected_name = golden_data[i].host;
568                 obj = sdb_store_get_host(golden_data[i].host);
569                 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
570                         fail_unless(obj == NULL,
571                                         "sdb_store_get_host(%s) = %p; expected: NULL",
572                                         golden_data[i].host, obj);
573                 else
574                         fail_unless(obj != NULL,
575                                         "sdb_store_get_host(%s) = NULL; expected: <host>",
576                                         golden_data[i].host);
578                 if (golden_data[i].type != SDB_HOST) {
579                         sdb_store_obj_t *tmp;
581                         expected_name = golden_data[i].name;
583                         tmp = sdb_store_get_child(obj,
584                                         golden_data[i].type, golden_data[i].name);
585                         if (golden_data[i].expected)
586                                 fail_unless(tmp == NULL,
587                                                 "sdb_store_get_child(<%s>, %s, %s) = %p; "
588                                                 "expected: NULL", golden_data[i].host,
589                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
590                                                 golden_data[i].name, tmp);
591                         else
592                                 fail_unless(tmp != NULL,
593                                                 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
594                                                 "expected: <obj>", golden_data[i].host,
595                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
596                                                 golden_data[i].name);
598                         sdb_object_deref(SDB_OBJ(obj));
599                         obj = tmp;
600                 }
602                 if (golden_data[i].expected)
603                         continue;
605                 fail_unless(obj->type == golden_data[i].type,
606                                 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
607                                 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
608                                 golden_data[i].host, golden_data[i].name, obj->type,
609                                 golden_data[i].type);
610                 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
611                                 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
612                                 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
613                                 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
614                                 expected_name);
616                 sdb_object_deref(SDB_OBJ(obj));
617         }
619 END_TEST
621 START_TEST(test_interval)
623         sdb_store_obj_t *host;
625         /* 10 us interval */
626         sdb_store_host("host", 10);
627         sdb_store_host("host", 20);
628         sdb_store_host("host", 30);
629         sdb_store_host("host", 40);
631         host = sdb_store_get_host("host");
632         fail_unless(host != NULL,
633                         "INTERNAL ERROR: store doesn't have host after adding it");
635         fail_unless(host->interval == 10,
636                         "sdb_store_host() did not calculate interval correctly: "
637                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
639         /* multiple updates for the same timestamp don't modify the interval */
640         sdb_store_host("host", 40);
641         sdb_store_host("host", 40);
642         sdb_store_host("host", 40);
643         sdb_store_host("host", 40);
645         fail_unless(host->interval == 10,
646                         "sdb_store_host() changed interval when doing multiple updates "
647                         "using the same timestamp; got: %"PRIsdbTIME"; "
648                         "expected: %"PRIsdbTIME, host->interval, 10);
650         /* multiple updates using an timestamp don't modify the interval */
651         sdb_store_host("host", 20);
652         sdb_store_host("host", 20);
653         sdb_store_host("host", 20);
654         sdb_store_host("host", 20);
656         fail_unless(host->interval == 10,
657                         "sdb_store_host() changed interval when doing multiple updates "
658                         "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
659                         host->interval, 10);
661         /* new interval: 20 us */
662         sdb_store_host("host", 60);
663         fail_unless(host->interval == 11,
664                         "sdb_store_host() did not calculate interval correctly: "
665                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
667         /* new interval: 40 us */
668         sdb_store_host("host", 100);
669         fail_unless(host->interval == 13,
670                         "sdb_store_host() did not calculate interval correctly: "
671                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
673         sdb_object_deref(SDB_OBJ(host));
675 END_TEST
677 static int
678 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
680         intptr_t *i = user_data;
682         if (! sdb_store_matcher_matches(filter, obj, NULL))
683                 return 0;
685         fail_unless(obj != NULL,
686                         "sdb_store_scan callback received NULL obj; expected: "
687                         "<store base obj>");
688         fail_unless(i != NULL,
689                         "sdb_store_scan callback received NULL user_data; "
690                         "expected: <pointer to data>");
692         ++(*i);
693         return 0;
694 } /* scan_count */
696 static int
697 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
699         intptr_t *i = user_data;
701         if (! sdb_store_matcher_matches(filter, obj, NULL))
702                 return 0;
704         fail_unless(obj != NULL,
705                         "sdb_store_scan callback received NULL obj; expected: "
706                         "<store base obj>");
707         fail_unless(i != NULL,
708                         "sdb_store_scan callback received NULL user_data; "
709                         "expected: <pointer to data>");
711         ++(*i);
712         return -1;
713 } /* scan_error */
715 START_TEST(test_scan)
717         intptr_t i = 0;
718         int check;
720         /* empty store */
721         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
722                         scan_count, &i);
723         fail_unless(check == 0,
724                         "sdb_store_scan(HOST), empty store = %d; expected: 0", check);
725         fail_unless(i == 0,
726                         "sdb_store_scan(HOST) called callback %d times; "
727                         "expected: 0", (int)i);
729         populate();
731         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
732                         scan_count, &i);
733         fail_unless(check == 0,
734                         "sdb_store_scan(HOST) = %d; expected: 0", check);
735         fail_unless(i == 2,
736                         "sdb_store_scan(HOST) called callback %d times; "
737                         "expected: 1", (int)i);
739         i = 0;
740         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
741                         scan_error, &i);
742         fail_unless(check == -1,
743                         "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
744         fail_unless(i == 1,
745                         "sdb_store_scan(HOST) called callback %d times "
746                         "(callback returned error); expected: 1", (int)i);
748         i = 0;
749         check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
750                         scan_count, &i);
751         fail_unless(check == 0,
752                         "sdb_store_scan(SERVICE) = %d; expected: 0", check);
753         fail_unless(i == 2,
754                         "sdb_store_scan(SERVICE) called callback %d times; "
755                         "expected: 2", (int)i);
757         i = 0;
758         check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
759                         scan_count, &i);
760         fail_unless(check == 0,
761                         "sdb_store_scan(METRIC) = %d; expected: 0", check);
762         fail_unless(i == 3,
763                         "sdb_store_scan(METRIC) called callback %d times; "
764                         "expected: 3", (int)i);
766 END_TEST
768 TEST_MAIN("core::store")
770         TCase *tc = tcase_create("core");
771         tcase_add_test(tc, test_store_host);
772         tcase_add_test(tc, test_store_get_host);
773         tcase_add_test(tc, test_store_attr);
774         tcase_add_test(tc, test_store_metric);
775         tcase_add_test(tc, test_store_metric_attr);
776         tcase_add_test(tc, test_store_service);
777         tcase_add_test(tc, test_store_service_attr);
778         TC_ADD_LOOP_TEST(tc, get_field);
779         tcase_add_test(tc, test_get_child);
780         tcase_add_test(tc, test_interval);
781         tcase_add_test(tc, test_scan);
782         tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
783         ADD_TCASE(tc);
785 TEST_MAIN_END
787 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */