Code

ed6f5d9b149944e31c4412c4c6103dd9a9f25320
[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/plugin.h"
33 #include "core/store.h"
34 #include "core/store-private.h"
35 #include "testutils.h"
37 #include <check.h>
38 #include <string.h>
39 #include <strings.h>
41 static void
42 init(void)
43 {
44         sdb_store_init();
45 }
47 static void
48 populate(void)
49 {
50         sdb_data_t datum;
52         sdb_plugin_store_host("h1", 1);
53         sdb_plugin_store_host("h2", 3);
55         datum.type = SDB_TYPE_STRING;
56         datum.data.string = "v1";
57         sdb_plugin_store_attribute("h1", "k1", &datum, 1);
58         datum.data.string = "v2";
59         sdb_plugin_store_attribute("h1", "k2", &datum, 2);
60         datum.data.string = "v3";
61         sdb_plugin_store_attribute("h1", "k3", &datum, 2);
63         /* make sure that older updates don't overwrite existing values */
64         datum.data.string = "fail";
65         sdb_plugin_store_attribute("h1", "k2", &datum, 1);
66         sdb_plugin_store_attribute("h1", "k3", &datum, 2);
68         sdb_plugin_store_metric("h1", "m1", /* store */ NULL, 2);
69         sdb_plugin_store_metric("h1", "m2", /* store */ NULL, 1);
70         sdb_plugin_store_metric("h2", "m1", /* store */ NULL, 1);
72         sdb_plugin_store_service("h2", "s1", 1);
73         sdb_plugin_store_service("h2", "s2", 2);
75         datum.type = SDB_TYPE_INTEGER;
76         datum.data.integer = 42;
77         sdb_plugin_store_metric_attribute("h1", "m1", "k3", &datum, 2);
79         datum.data.integer = 123;
80         sdb_plugin_store_service_attribute("h2", "s2", "k1", &datum, 2);
81         datum.data.integer = 4711;
82         sdb_plugin_store_service_attribute("h2", "s2", "k2", &datum, 1);
84         /* don't overwrite k1 */
85         datum.data.integer = 666;
86         sdb_plugin_store_service_attribute("h2", "s2", "k1", &datum, 2);
87 } /* populate */
89 START_TEST(test_store_host)
90 {
91         struct {
92                 const char *name;
93                 sdb_time_t  last_update;
94                 int         expected;
95         } golden_data[] = {
96                 { "a", 1, 0 },
97                 { "a", 2, 0 },
98                 { "a", 1, 1 },
99                 { "b", 1, 0 },
100                 { "b", 1, 1 },
101                 { "A", 1, 1 }, /* case-insensitive */
102                 { "A", 3, 0 },
103         };
105         struct {
106                 const char *name;
107                 _Bool       has;
108         } golden_hosts[] = {
109                 { "a", 1 == 1 },
110                 { "b", 1 == 1 },
111                 { "c", 0 == 1 },
112                 { "A", 1 == 1 },
113         };
115         size_t i;
117         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
118                 int status;
120                 status = sdb_plugin_store_host(golden_data[i].name,
121                                 golden_data[i].last_update);
122                 fail_unless(status == golden_data[i].expected,
123                                 "sdb_plugin_store_host(%s, %d) = %d; expected: %d",
124                                 golden_data[i].name, (int)golden_data[i].last_update,
125                                 status, golden_data[i].expected);
126         }
128         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
129                 _Bool has;
131                 has = sdb_store_has_host(golden_hosts[i].name);
132                 fail_unless(has == golden_hosts[i].has,
133                                 "sdb_store_has_host(%s) = %d; expected: %d",
134                                 golden_hosts[i].name, has, golden_hosts[i].has);
135         }
137 END_TEST
139 START_TEST(test_store_get_host)
141         char *golden_hosts[] = { "a", "b", "c" };
142         char *unknown_hosts[] = { "x", "y", "z" };
143         size_t i;
145         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
146                 int status = sdb_plugin_store_host(golden_hosts[i], 1);
147                 fail_unless(status >= 0,
148                                 "sdb_plugin_store_host(%s) = %d; expected: >=0",
149                                 golden_hosts[i], status);
150         }
152         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
153                 sdb_store_obj_t *sobj1, *sobj2;
154                 int ref_cnt;
156                 fail_unless(sdb_store_has_host(golden_hosts[i]),
157                                 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
158                                 golden_hosts[i]);
160                 sobj1 = sdb_store_get_host(golden_hosts[i]);
161                 fail_unless(sobj1 != NULL,
162                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
163                                 golden_hosts[i]);
164                 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
166                 fail_unless(ref_cnt > 1,
167                                 "sdb_store_get_host(%s) did not increment ref count: "
168                                 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
170                 sobj2 = sdb_store_get_host(golden_hosts[i]);
171                 fail_unless(sobj2 != NULL,
172                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
173                                 golden_hosts[i]);
175                 fail_unless(sobj1 == sobj2,
176                                 "sdb_store_get_host(%s) returned different objects "
177                                 "in successive calls", golden_hosts[i]);
178                 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
179                                 "sdb_store_get_hosts(%s) did not increment ref count "
180                                 "(first call: %d; second call: %d)",
181                                 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
183                 sdb_object_deref(SDB_OBJ(sobj1));
184                 sdb_object_deref(SDB_OBJ(sobj2));
185         }
186         for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
187                 sdb_store_obj_t *sobj;
189                 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
190                                 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
191                                 unknown_hosts[i]);
193                 sobj = sdb_store_get_host(unknown_hosts[i]);
194                 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
195                                 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
196         }
198 END_TEST
200 START_TEST(test_store_attr)
202         struct {
203                 const char *host;
204                 const char *key;
205                 char       *value;
206                 sdb_time_t  last_update;
207                 int         expected;
208         } golden_data[] = {
209                 { "k", "k",  "v",  1, -1 },
210                 { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
211                 { "l", "k1", "v1", 1,  0 },
212                 { "l", "k1", "v2", 2,  0 },
213                 { "l", "k1", "v3", 2,  1 },
214                 { "l", "k2", "v1", 1,  0 },
215                 { "m", "k",  "v1", 1,  0 },
216                 { "m", "k",  "v2", 1,  1 },
217         };
219         size_t i;
221         sdb_plugin_store_host("l", 1);
222         sdb_plugin_store_host("m", 1);
223         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
224                 sdb_data_t datum;
225                 int status;
227                 /* XXX: test other types as well */
228                 datum.type = SDB_TYPE_STRING;
229                 datum.data.string = golden_data[i].value;
231                 status = sdb_plugin_store_attribute(golden_data[i].host,
232                                 golden_data[i].key, &datum,
233                                 golden_data[i].last_update);
234                 fail_unless(status == golden_data[i].expected,
235                                 "sdb_plugin_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
236                                 golden_data[i].host, golden_data[i].key, golden_data[i].value,
237                                 golden_data[i].last_update, status, golden_data[i].expected);
238         }
240 END_TEST
242 START_TEST(test_store_metric)
244         sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
245         sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
247         struct {
248                 const char *host;
249                 const char *metric;
250                 sdb_metric_store_t *store;
251                 sdb_time_t  last_update;
252                 int         expected;
253         } golden_data[] = {
254                 { "k", "m",  NULL,    1, -1 },
255                 { "k", "m",  NULL,    1, -1 }, /* retry to ensure the host is not created */
256                 { "k", "m",  &store1, 1, -1 },
257                 { "l", "m1", NULL,    1,  0 },
258                 { "l", "m1", &store1, 2,  0 },
259                 { "l", "m1", &store1, 3,  0 },
260                 { "l", "m1", NULL,    3,  1 },
261                 { "l", "m2", &store1, 1,  0 },
262                 { "l", "m2", &store2, 2,  0 },
263                 { "l", "m2", NULL,    3,  0 },
264                 { "m", "m",  &store1, 1,  0 },
265                 { "m", "m",  NULL,    2,  0 },
266                 { "m", "m",  NULL,    2,  1 },
267                 { "m", "m",  &store1, 3,  0 },
268                 { "m", "m",  &store2, 4,  0 },
269                 { "m", "m",  NULL,    5,  0 },
270         };
272         size_t i;
274         sdb_plugin_store_host("m", 1);
275         sdb_plugin_store_host("l", 1);
276         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
277                 int status;
279                 status = sdb_plugin_store_metric(golden_data[i].host,
280                                 golden_data[i].metric, golden_data[i].store,
281                                 golden_data[i].last_update);
282                 fail_unless(status == golden_data[i].expected,
283                                 "sdb_plugin_store_metric(%s, %s, %p, %d) = %d; expected: %d",
284                                 golden_data[i].host, golden_data[i].metric,
285                                 golden_data[i].store, golden_data[i].last_update,
286                                 status, golden_data[i].expected);
287         }
289 END_TEST
291 START_TEST(test_store_metric_attr)
293         struct {
294                 const char *host;
295                 const char *metric;
296                 const char *attr;
297                 const sdb_data_t value;
298                 sdb_time_t  last_update;
299                 int expected;
300         } golden_data[] = {
301                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
302                 /* retry, it should still fail */
303                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
304                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
305                 /* retry, it should still fail */
306                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
307                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
308                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
309                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
310                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
311                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
312                 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
313                 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
314         };
316         size_t i;
318         sdb_plugin_store_host("m", 1);
319         sdb_plugin_store_host("l", 1);
320         sdb_plugin_store_metric("m", "m1", NULL, 1);
321         sdb_plugin_store_metric("l", "m1", NULL, 1);
322         sdb_plugin_store_metric("l", "m2", NULL, 1);
324         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
325                 int status;
327                 status = sdb_plugin_store_metric_attribute(golden_data[i].host,
328                                 golden_data[i].metric, golden_data[i].attr,
329                                 &golden_data[i].value, golden_data[i].last_update);
330                 fail_unless(status == golden_data[i].expected,
331                                 "sdb_plugin_store_metric_attribute(%s, %s, %s, %d, %d) = %d; "
332                                 "expected: %d", golden_data[i].host, golden_data[i].metric,
333                                 golden_data[i].attr, golden_data[i].value.data.integer,
334                                 golden_data[i].last_update, status, golden_data[i].expected);
335         }
337 END_TEST
339 START_TEST(test_store_service)
341         struct {
342                 const char *host;
343                 const char *svc;
344                 sdb_time_t  last_update;
345                 int         expected;
346         } golden_data[] = {
347                 { "k", "s",  1, -1 },
348                 { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
349                 { "l", "s1", 1,  0 },
350                 { "l", "s1", 2,  0 },
351                 { "l", "s1", 2,  1 },
352                 { "l", "s2", 1,  0 },
353                 { "m", "s",  1,  0 },
354                 { "m", "s",  1,  1 },
355         };
357         size_t i;
359         sdb_plugin_store_host("m", 1);
360         sdb_plugin_store_host("l", 1);
361         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
362                 int status;
364                 status = sdb_plugin_store_service(golden_data[i].host,
365                                 golden_data[i].svc, golden_data[i].last_update);
366                 fail_unless(status == golden_data[i].expected,
367                                 "sdb_plugin_store_service(%s, %s, %d) = %d; expected: %d",
368                                 golden_data[i].host, golden_data[i].svc,
369                                 golden_data[i].last_update, status, golden_data[i].expected);
370         }
372 END_TEST
374 START_TEST(test_store_service_attr)
376         struct {
377                 const char *host;
378                 const char *svc;
379                 const char *attr;
380                 const sdb_data_t value;
381                 sdb_time_t  last_update;
382                 int expected;
383         } golden_data[] = {
384                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
385                 /* retry, it should still fail */
386                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
387                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
388                 /* retry, it should still fail */
389                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
390                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
391                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
392                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
393                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
394                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
395                 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
396                 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
397         };
399         size_t i;
401         sdb_plugin_store_host("m", 1);
402         sdb_plugin_store_host("l", 1);
403         sdb_plugin_store_service("m", "s1", 1);
404         sdb_plugin_store_service("l", "s1", 1);
405         sdb_plugin_store_service("l", "s2", 1);
407         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
408                 int status;
410                 status = sdb_plugin_store_service_attribute(golden_data[i].host,
411                                 golden_data[i].svc, golden_data[i].attr,
412                                 &golden_data[i].value, golden_data[i].last_update);
413                 fail_unless(status == golden_data[i].expected,
414                                 "sdb_plugin_store_service_attribute(%s, %s, %s, %d, %d) = %d; "
415                                 "expected: %d", golden_data[i].host, golden_data[i].svc,
416                                 golden_data[i].attr, golden_data[i].value.data.integer,
417                                 golden_data[i].last_update, status, golden_data[i].expected);
418         }
420 END_TEST
422 static struct {
423         const char *hostname;
424         const char *attr; /* optional */
425         int field;
426         int expected;
427         sdb_data_t value;
428 } get_field_data[] = {
429         { NULL,   NULL, 0, -1, { SDB_TYPE_NULL, { 0 } } },
430         { NULL,   NULL,   SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
431         { NULL,   NULL,   SDB_FIELD_INTERVAL,    -1, { SDB_TYPE_NULL, { 0 } } },
432         { NULL,   NULL,   SDB_FIELD_AGE,         -1, { SDB_TYPE_NULL, { 0 } } },
433         { NULL,   NULL,   SDB_FIELD_NAME,        -1, { SDB_TYPE_NULL, { 0 } } },
434         { NULL,   NULL,   SDB_FIELD_BACKEND,     -1, { SDB_TYPE_NULL, { 0 } } },
435         { NULL,   NULL,   SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
436         { "host", NULL,   SDB_FIELD_LAST_UPDATE,  0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
437         { "host", NULL,   SDB_FIELD_INTERVAL,     0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
438         /* the test will handle AGE specially */
439         { "host", NULL,   SDB_FIELD_AGE,          0, { SDB_TYPE_NULL, { 0 } } },
440         { "host", NULL,   SDB_FIELD_NAME,         0, { SDB_TYPE_STRING, { .string = "host" } } },
441         { "host", NULL,   SDB_FIELD_BACKEND,      0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
442         { "host", NULL,   SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
443         { "host", "attr", SDB_FIELD_LAST_UPDATE,  0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
444         { "host", "attr", SDB_FIELD_INTERVAL,     0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
445         /* the test will handle AGE specially */
446         { "host", "attr", SDB_FIELD_AGE,          0, { SDB_TYPE_NULL, { 0 } } },
447         { "host", "attr", SDB_FIELD_NAME,         0, { SDB_TYPE_STRING, { .string = "attr" } } },
448         { "host", "attr", SDB_FIELD_BACKEND,      0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
449         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_INTEGER, { .integer = 1 } } },
450         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } } },
451         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_STRING, { .string = "foo" } } },
452         { "host", "attr", SDB_FIELD_VALUE,        0, { SDB_TYPE_DATETIME, { .datetime = 1234567890L } } },
453         { "host", "a",    SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
454         { "host", "a",    SDB_FIELD_INTERVAL,    -1, { SDB_TYPE_NULL, { 0 } } },
455         { "host", "a",    SDB_FIELD_AGE,         -1, { SDB_TYPE_NULL, { 0 } } },
456         { "host", "a",    SDB_FIELD_NAME,        -1, { SDB_TYPE_NULL, { 0 } } },
457         { "host", "a",    SDB_FIELD_BACKEND,     -1, { SDB_TYPE_NULL, { 0 } } },
458         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
459         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
460         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
461         { "host", "a",    SDB_FIELD_VALUE,       -1, { SDB_TYPE_NULL, { 0 } } },
462 };
464 /* returns a tuple <type> <name> */
465 #define OBJ_NAME(obj) \
466         (obj) ? SDB_STORE_TYPE_TO_NAME(obj->type) : "NULL", \
467         (obj) ? SDB_OBJ(obj)->name : ""
468 START_TEST(test_get_field)
470         sdb_store_obj_t *obj = NULL;
471         sdb_data_t value = SDB_DATA_INIT;
472         char value_str[128], expected_value_str[128];
473         sdb_time_t now = sdb_gettime();
474         int check;
476         sdb_plugin_store_host("host", 10);
477         sdb_plugin_store_host("host", 20);
478         sdb_plugin_store_attribute("host", "attr", &get_field_data[_i].value, 10);
479         sdb_plugin_store_attribute("host", "attr", &get_field_data[_i].value, 20);
481         if (get_field_data[_i].hostname) {
482                 obj = sdb_store_get_host(get_field_data[_i].hostname);
483                 ck_assert(obj != NULL);
485                 if (get_field_data[_i].attr) {
486                         sdb_store_obj_t *tmp = sdb_store_get_child(obj,
487                                         SDB_ATTRIBUTE, get_field_data[_i].attr);
488                         sdb_object_deref(SDB_OBJ(obj));
489                         obj = tmp;
490                 }
491         }
493         check = sdb_store_get_field(obj, get_field_data[_i].field, NULL);
494         fail_unless(check == get_field_data[_i].expected,
495                         "sdb_store_get_field(%s %s, %s, NULL) = %d; expected: %d",
496                         OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
497                         check, get_field_data[_i].expected);
498         check = sdb_store_get_field(obj, get_field_data[_i].field, &value);
499         fail_unless(check == get_field_data[_i].expected,
500                         "sdb_store_get_field(%s %s, %s, <value>) = %d; expected: %d",
501                         OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
502                         check, get_field_data[_i].expected);
504         if (get_field_data[_i].expected) {
505                 sdb_object_deref(SDB_OBJ(obj));
506                 return;
507         }
509         if (get_field_data[_i].field == SDB_FIELD_AGE) {
510                 get_field_data[_i].value.type = SDB_TYPE_DATETIME;
511                 get_field_data[_i].value.data.datetime = now;
512         }
514         sdb_data_format(&value, value_str, sizeof(value_str), 0);
515         sdb_data_format(&get_field_data[_i].value, expected_value_str,
516                         sizeof(expected_value_str), 0);
518         if (get_field_data[_i].field == SDB_FIELD_AGE) {
519                 fail_unless((value.type == SDB_TYPE_DATETIME)
520                                 && (value.data.datetime >= now),
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         else {
527                 fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
528                                 "sdb_store_get_field(%s %s, %s, <value>) "
529                                 "returned value %s; expected %s", OBJ_NAME(obj),
530                                 SDB_FIELD_TO_NAME(get_field_data[_i].field),
531                                 value_str, expected_value_str);
532         }
533         sdb_data_free_datum(&value);
534         sdb_object_deref(SDB_OBJ(obj));
536 END_TEST
537 #undef OBJ_NAME
539 START_TEST(test_get_child)
541         struct {
542                 const char *host;
543                 const char *name;
544                 int type;
545                 int expected;
546         } golden_data[] = {
547                 { "h1", NULL, SDB_HOST,       0 },
548                 { "h1", NULL, SDB_SERVICE,   -1 },
549                 { "h1", NULL, SDB_METRIC,    -1 },
550                 { "h1", NULL, SDB_ATTRIBUTE, -1 },
551                 { "h2", NULL, SDB_HOST,       0 },
552                 { "h2", NULL, SDB_SERVICE,   -1 },
553                 { "h2", NULL, SDB_METRIC,    -1 },
554                 { "h2", NULL, SDB_ATTRIBUTE, -1 },
555                 { "h3", NULL, SDB_HOST,      -1 },
556                 { "h1", "k1", SDB_ATTRIBUTE,  0 },
557                 { "h1", "x1", SDB_ATTRIBUTE, -1 },
558                 { "h2", "k1", SDB_ATTRIBUTE, -1 },
559                 { "h1", "k1", SDB_SERVICE,   -1 },
560                 { "h1", "k1", SDB_METRIC,    -1 },
561                 { "h1", "s1", SDB_SERVICE,   -1 },
562                 { "h2", "s1", SDB_SERVICE,    0 },
563                 { "h1", "m2", SDB_METRIC,     0 },
564                 { "h2", "m2", SDB_METRIC,    -1 },
565         };
567         size_t i;
569         populate();
571         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
572                 sdb_store_obj_t *obj;
573                 const char *expected_name = golden_data[i].host;
575                 obj = sdb_store_get_host(golden_data[i].host);
576                 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
577                         fail_unless(obj == NULL,
578                                         "sdb_store_get_host(%s) = %p; expected: NULL",
579                                         golden_data[i].host, obj);
580                 else
581                         fail_unless(obj != NULL,
582                                         "sdb_store_get_host(%s) = NULL; expected: <host>",
583                                         golden_data[i].host);
585                 if (golden_data[i].type != SDB_HOST) {
586                         sdb_store_obj_t *tmp;
588                         expected_name = golden_data[i].name;
590                         tmp = sdb_store_get_child(obj,
591                                         golden_data[i].type, golden_data[i].name);
592                         if (golden_data[i].expected)
593                                 fail_unless(tmp == NULL,
594                                                 "sdb_store_get_child(<%s>, %s, %s) = %p; "
595                                                 "expected: NULL", golden_data[i].host,
596                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
597                                                 golden_data[i].name, tmp);
598                         else
599                                 fail_unless(tmp != NULL,
600                                                 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
601                                                 "expected: <obj>", golden_data[i].host,
602                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
603                                                 golden_data[i].name);
605                         sdb_object_deref(SDB_OBJ(obj));
606                         obj = tmp;
607                 }
609                 if (golden_data[i].expected)
610                         continue;
612                 fail_unless(obj->type == golden_data[i].type,
613                                 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
614                                 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
615                                 golden_data[i].host, golden_data[i].name, obj->type,
616                                 golden_data[i].type);
617                 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
618                                 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
619                                 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
620                                 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
621                                 expected_name);
623                 sdb_object_deref(SDB_OBJ(obj));
624         }
626 END_TEST
628 START_TEST(test_interval)
630         sdb_store_obj_t *host;
632         /* 10 us interval */
633         sdb_plugin_store_host("host", 10);
634         sdb_plugin_store_host("host", 20);
635         sdb_plugin_store_host("host", 30);
636         sdb_plugin_store_host("host", 40);
638         host = sdb_store_get_host("host");
639         fail_unless(host != NULL,
640                         "INTERNAL ERROR: store doesn't have host after adding it");
642         fail_unless(host->interval == 10,
643                         "sdb_plugin_store_host() did not calculate interval correctly: "
644                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
646         /* multiple updates for the same timestamp don't modify the interval */
647         sdb_plugin_store_host("host", 40);
648         sdb_plugin_store_host("host", 40);
649         sdb_plugin_store_host("host", 40);
650         sdb_plugin_store_host("host", 40);
652         fail_unless(host->interval == 10,
653                         "sdb_plugin_store_host() changed interval when doing multiple updates "
654                         "using the same timestamp; got: %"PRIsdbTIME"; "
655                         "expected: %"PRIsdbTIME, host->interval, 10);
657         /* multiple updates using an timestamp don't modify the interval */
658         sdb_plugin_store_host("host", 20);
659         sdb_plugin_store_host("host", 20);
660         sdb_plugin_store_host("host", 20);
661         sdb_plugin_store_host("host", 20);
663         fail_unless(host->interval == 10,
664                         "sdb_plugin_store_host() changed interval when doing multiple updates "
665                         "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
666                         host->interval, 10);
668         /* new interval: 20 us */
669         sdb_plugin_store_host("host", 60);
670         fail_unless(host->interval == 11,
671                         "sdb_plugin_store_host() did not calculate interval correctly: "
672                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
674         /* new interval: 40 us */
675         sdb_plugin_store_host("host", 100);
676         fail_unless(host->interval == 13,
677                         "sdb_plugin_store_host() did not calculate interval correctly: "
678                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
680         sdb_object_deref(SDB_OBJ(host));
682 END_TEST
684 static int
685 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
687         intptr_t *i = user_data;
689         if (! sdb_store_matcher_matches(filter, obj, NULL))
690                 return 0;
692         fail_unless(obj != NULL,
693                         "sdb_store_scan callback received NULL obj; expected: "
694                         "<store base obj>");
695         fail_unless(i != NULL,
696                         "sdb_store_scan callback received NULL user_data; "
697                         "expected: <pointer to data>");
699         ++(*i);
700         return 0;
701 } /* scan_count */
703 static int
704 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
706         intptr_t *i = user_data;
708         if (! sdb_store_matcher_matches(filter, obj, NULL))
709                 return 0;
711         fail_unless(obj != NULL,
712                         "sdb_store_scan callback received NULL obj; expected: "
713                         "<store base obj>");
714         fail_unless(i != NULL,
715                         "sdb_store_scan callback received NULL user_data; "
716                         "expected: <pointer to data>");
718         ++(*i);
719         return -1;
720 } /* scan_error */
722 START_TEST(test_scan)
724         intptr_t i = 0;
725         int check;
727         /* empty store */
728         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
729                         scan_count, &i);
730         fail_unless(check == 0,
731                         "sdb_store_scan(HOST), empty store = %d; expected: 0", check);
732         fail_unless(i == 0,
733                         "sdb_store_scan(HOST) called callback %d times; "
734                         "expected: 0", (int)i);
736         populate();
738         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
739                         scan_count, &i);
740         fail_unless(check == 0,
741                         "sdb_store_scan(HOST) = %d; expected: 0", check);
742         fail_unless(i == 2,
743                         "sdb_store_scan(HOST) called callback %d times; "
744                         "expected: 1", (int)i);
746         i = 0;
747         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
748                         scan_error, &i);
749         fail_unless(check == -1,
750                         "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
751         fail_unless(i == 1,
752                         "sdb_store_scan(HOST) called callback %d times "
753                         "(callback returned error); expected: 1", (int)i);
755         i = 0;
756         check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
757                         scan_count, &i);
758         fail_unless(check == 0,
759                         "sdb_store_scan(SERVICE) = %d; expected: 0", check);
760         fail_unless(i == 2,
761                         "sdb_store_scan(SERVICE) called callback %d times; "
762                         "expected: 2", (int)i);
764         i = 0;
765         check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
766                         scan_count, &i);
767         fail_unless(check == 0,
768                         "sdb_store_scan(METRIC) = %d; expected: 0", check);
769         fail_unless(i == 3,
770                         "sdb_store_scan(METRIC) called callback %d times; "
771                         "expected: 3", (int)i);
773 END_TEST
775 TEST_MAIN("core::store")
777         TCase *tc = tcase_create("core");
778         tcase_add_test(tc, test_store_host);
779         tcase_add_test(tc, test_store_get_host);
780         tcase_add_test(tc, test_store_attr);
781         tcase_add_test(tc, test_store_metric);
782         tcase_add_test(tc, test_store_metric_attr);
783         tcase_add_test(tc, test_store_service);
784         tcase_add_test(tc, test_store_service_attr);
785         TC_ADD_LOOP_TEST(tc, get_field);
786         tcase_add_test(tc, test_get_child);
787         tcase_add_test(tc, test_interval);
788         tcase_add_test(tc, test_scan);
789         tcase_add_unchecked_fixture(tc, init, sdb_store_clear);
790         ADD_TCASE(tc);
792 TEST_MAIN_END
794 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */