Code

store: Added sdb_store_get_child().
[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 #include "core/store.h"
29 #include "core/store-private.h"
30 #include "libsysdb_test.h"
32 #include <check.h>
33 #include <string.h>
34 #include <strings.h>
36 static void
37 populate(void)
38 {
39         sdb_data_t datum;
41         sdb_store_host("h1", 1);
42         sdb_store_host("h2", 3);
44         datum.type = SDB_TYPE_STRING;
45         datum.data.string = "v1";
46         sdb_store_attribute("h1", "k1", &datum, 1);
47         datum.data.string = "v2";
48         sdb_store_attribute("h1", "k2", &datum, 2);
49         datum.data.string = "v3";
50         sdb_store_attribute("h1", "k3", &datum, 2);
52         /* make sure that older updates don't overwrite existing values */
53         datum.data.string = "fail";
54         sdb_store_attribute("h1", "k2", &datum, 1);
55         sdb_store_attribute("h1", "k3", &datum, 2);
57         sdb_store_metric("h1", "m1", /* store */ NULL, 2);
58         sdb_store_metric("h1", "m2", /* store */ NULL, 1);
59         sdb_store_metric("h2", "m1", /* store */ NULL, 1);
61         sdb_store_service("h2", "s1", 1);
62         sdb_store_service("h2", "s2", 2);
64         datum.type = SDB_TYPE_INTEGER;
65         datum.data.integer = 42;
66         sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
68         datum.data.integer = 123;
69         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
70         datum.data.integer = 4711;
71         sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
73         /* don't overwrite k1 */
74         datum.data.integer = 666;
75         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
76 } /* populate */
78 START_TEST(test_store_host)
79 {
80         struct {
81                 const char *name;
82                 sdb_time_t  last_update;
83                 int         expected;
84         } golden_data[] = {
85                 { "a", 1, 0 },
86                 { "a", 2, 0 },
87                 { "a", 1, 1 },
88                 { "b", 1, 0 },
89                 { "b", 1, 1 },
90                 { "A", 1, 1 }, /* case-insensitive */
91                 { "A", 3, 0 },
92         };
94         struct {
95                 const char *name;
96                 _Bool       has;
97         } golden_hosts[] = {
98                 { "a", 1 == 1 },
99                 { "b", 1 == 1 },
100                 { "c", 0 == 1 },
101                 { "A", 1 == 1 },
102         };
104         size_t i;
106         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
107                 int status;
109                 status = sdb_store_host(golden_data[i].name,
110                                 golden_data[i].last_update);
111                 fail_unless(status == golden_data[i].expected,
112                                 "sdb_store_host(%s, %d) = %d; expected: %d",
113                                 golden_data[i].name, (int)golden_data[i].last_update,
114                                 status, golden_data[i].expected);
115         }
117         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
118                 _Bool has;
120                 has = sdb_store_has_host(golden_hosts[i].name);
121                 fail_unless(has == golden_hosts[i].has,
122                                 "sdb_store_has_host(%s) = %d; expected: %d",
123                                 golden_hosts[i].name, has, golden_hosts[i].has);
124         }
126 END_TEST
128 START_TEST(test_store_get_host)
130         char *golden_hosts[] = { "a", "b", "c" };
131         char *unknown_hosts[] = { "x", "y", "z" };
132         size_t i;
134         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
135                 int status = sdb_store_host(golden_hosts[i], 1);
136                 fail_unless(status >= 0,
137                                 "sdb_store_host(%s) = %d; expected: >=0",
138                                 golden_hosts[i], status);
139         }
141         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
142                 sdb_store_obj_t *sobj1, *sobj2;
143                 int ref_cnt;
145                 fail_unless(sdb_store_has_host(golden_hosts[i]),
146                                 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
147                                 golden_hosts[i]);
149                 sobj1 = sdb_store_get_host(golden_hosts[i]);
150                 fail_unless(sobj1 != NULL,
151                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
152                                 golden_hosts[i]);
153                 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
155                 fail_unless(ref_cnt > 1,
156                                 "sdb_store_get_host(%s) did not increment ref count: "
157                                 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
159                 sobj2 = sdb_store_get_host(golden_hosts[i]);
160                 fail_unless(sobj2 != NULL,
161                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
162                                 golden_hosts[i]);
164                 fail_unless(sobj1 == sobj2,
165                                 "sdb_store_get_host(%s) returned different objects "
166                                 "in successive calls", golden_hosts[i]);
167                 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
168                                 "sdb_store_get_hosts(%s) did not increment ref count "
169                                 "(first call: %d; second call: %d)",
170                                 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
172                 sdb_object_deref(SDB_OBJ(sobj1));
173                 sdb_object_deref(SDB_OBJ(sobj2));
174         }
175         for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
176                 sdb_store_obj_t *sobj;
178                 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
179                                 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
180                                 unknown_hosts[i]);
182                 sobj = sdb_store_get_host(unknown_hosts[i]);
183                 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
184                                 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
185         }
187 END_TEST
189 START_TEST(test_store_attr)
191         struct {
192                 const char *host;
193                 const char *key;
194                 char       *value;
195                 sdb_time_t  last_update;
196                 int         expected;
197         } golden_data[] = {
198                 { "k", "k",  "v",  1, -1 },
199                 { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
200                 { "l", "k1", "v1", 1,  0 },
201                 { "l", "k1", "v2", 2,  0 },
202                 { "l", "k1", "v3", 2,  1 },
203                 { "l", "k2", "v1", 1,  0 },
204                 { "m", "k",  "v1", 1,  0 },
205                 { "m", "k",  "v2", 1,  1 },
206         };
208         size_t i;
210         sdb_store_host("l", 1);
211         sdb_store_host("m", 1);
212         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
213                 sdb_data_t datum;
214                 int status;
216                 /* XXX: test other types as well */
217                 datum.type = SDB_TYPE_STRING;
218                 datum.data.string = golden_data[i].value;
220                 status = sdb_store_attribute(golden_data[i].host,
221                                 golden_data[i].key, &datum,
222                                 golden_data[i].last_update);
223                 fail_unless(status == golden_data[i].expected,
224                                 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
225                                 golden_data[i].host, golden_data[i].key, golden_data[i].value,
226                                 golden_data[i].last_update, status, golden_data[i].expected);
227         }
229 END_TEST
231 START_TEST(test_store_metric)
233         sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
234         sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
236         struct {
237                 const char *host;
238                 const char *metric;
239                 sdb_metric_store_t *store;
240                 sdb_time_t  last_update;
241                 int         expected;
242         } golden_data[] = {
243                 { "k", "m",  NULL,    1, -1 },
244                 { "k", "m",  NULL,    1, -1 }, /* retry to ensure the host is not created */
245                 { "k", "m",  &store1, 1, -1 },
246                 { "l", "m1", NULL,    1,  0 },
247                 { "l", "m1", &store1, 2,  0 },
248                 { "l", "m1", &store1, 3,  0 },
249                 { "l", "m1", NULL,    3,  1 },
250                 { "l", "m2", &store1, 1,  0 },
251                 { "l", "m2", &store2, 2,  0 },
252                 { "l", "m2", NULL,    3,  0 },
253                 { "m", "m",  &store1, 1,  0 },
254                 { "m", "m",  NULL,    2,  0 },
255                 { "m", "m",  NULL,    2,  1 },
256                 { "m", "m",  &store1, 3,  0 },
257                 { "m", "m",  &store2, 4,  0 },
258                 { "m", "m",  NULL,    5,  0 },
259         };
261         size_t i;
263         sdb_store_host("m", 1);
264         sdb_store_host("l", 1);
265         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
266                 int status;
268                 status = sdb_store_metric(golden_data[i].host,
269                                 golden_data[i].metric, golden_data[i].store,
270                                 golden_data[i].last_update);
271                 fail_unless(status == golden_data[i].expected,
272                                 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
273                                 golden_data[i].host, golden_data[i].metric,
274                                 golden_data[i].store, golden_data[i].last_update,
275                                 status, golden_data[i].expected);
276         }
278 END_TEST
280 START_TEST(test_store_metric_attr)
282         struct {
283                 const char *host;
284                 const char *metric;
285                 const char *attr;
286                 const sdb_data_t value;
287                 sdb_time_t  last_update;
288                 int expected;
289         } golden_data[] = {
290                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
291                 /* retry, it should still fail */
292                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
293                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
294                 /* retry, it should still fail */
295                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
296                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
297                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
298                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
299                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
300                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
301                 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
302                 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
303         };
305         size_t i;
307         sdb_store_host("m", 1);
308         sdb_store_host("l", 1);
309         sdb_store_metric("m", "m1", NULL, 1);
310         sdb_store_metric("l", "m1", NULL, 1);
311         sdb_store_metric("l", "m2", NULL, 1);
313         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
314                 int status;
316                 status = sdb_store_metric_attr(golden_data[i].host,
317                                 golden_data[i].metric, golden_data[i].attr,
318                                 &golden_data[i].value, golden_data[i].last_update);
319                 fail_unless(status == golden_data[i].expected,
320                                 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
321                                 "expected: %d", golden_data[i].host, golden_data[i].metric,
322                                 golden_data[i].attr, golden_data[i].value.data.integer,
323                                 golden_data[i].last_update, status, golden_data[i].expected);
324         }
326 END_TEST
328 START_TEST(test_store_service)
330         struct {
331                 const char *host;
332                 const char *svc;
333                 sdb_time_t  last_update;
334                 int         expected;
335         } golden_data[] = {
336                 { "k", "s",  1, -1 },
337                 { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
338                 { "l", "s1", 1,  0 },
339                 { "l", "s1", 2,  0 },
340                 { "l", "s1", 2,  1 },
341                 { "l", "s2", 1,  0 },
342                 { "m", "s",  1,  0 },
343                 { "m", "s",  1,  1 },
344         };
346         size_t i;
348         sdb_store_host("m", 1);
349         sdb_store_host("l", 1);
350         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
351                 int status;
353                 status = sdb_store_service(golden_data[i].host,
354                                 golden_data[i].svc, golden_data[i].last_update);
355                 fail_unless(status == golden_data[i].expected,
356                                 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
357                                 golden_data[i].host, golden_data[i].svc,
358                                 golden_data[i].last_update, status, golden_data[i].expected);
359         }
361 END_TEST
363 START_TEST(test_store_service_attr)
365         struct {
366                 const char *host;
367                 const char *svc;
368                 const char *attr;
369                 const sdb_data_t value;
370                 sdb_time_t  last_update;
371                 int expected;
372         } golden_data[] = {
373                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
374                 /* retry, it should still fail */
375                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
376                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
377                 /* retry, it should still fail */
378                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
379                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
380                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
381                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
382                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
383                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
384                 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
385                 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
386         };
388         size_t i;
390         sdb_store_host("m", 1);
391         sdb_store_host("l", 1);
392         sdb_store_service("m", "s1", 1);
393         sdb_store_service("l", "s1", 1);
394         sdb_store_service("l", "s2", 1);
396         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
397                 int status;
399                 status = sdb_store_service_attr(golden_data[i].host,
400                                 golden_data[i].svc, golden_data[i].attr,
401                                 &golden_data[i].value, golden_data[i].last_update);
402                 fail_unless(status == golden_data[i].expected,
403                                 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
404                                 "expected: %d", golden_data[i].host, golden_data[i].svc,
405                                 golden_data[i].attr, golden_data[i].value.data.integer,
406                                 golden_data[i].last_update, status, golden_data[i].expected);
407         }
409 END_TEST
411 START_TEST(test_get_field)
413         sdb_store_obj_t *host;
414         sdb_data_t value = SDB_DATA_INIT;
415         int check;
417         sdb_store_host("host", 10);
418         sdb_store_host("host", 20);
420         host = sdb_store_get_host("host");
421         fail_unless(host != NULL,
422                         "INTERNAL ERROR: store doesn't have host after adding it");
424         check = sdb_store_get_field(NULL, 0, NULL);
425         fail_unless(check < 0,
426                         "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
427         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
428         fail_unless(check < 0,
429                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
430                         "expected: <0");
431         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
432         fail_unless(check < 0,
433                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
434                         "expected: <0");
436         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
437         fail_unless(check == 0,
438                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
439                         "expected: 0");
440         /* 'name' is dynamically allocated; make sure it's not leaked even
441          * if there is no result parameter */
442         check = sdb_store_get_field(host, SDB_FIELD_NAME, NULL);
443         fail_unless(check == 0,
444                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
445                         "expected: 0");
447         check = sdb_store_get_field(host, SDB_FIELD_NAME, &value);
448         fail_unless(check == 0,
449                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) = "
450                         "%d; expected: 0");
451         fail_unless((value.type == SDB_TYPE_STRING)
452                         && (! strcmp(value.data.string, "host")),
453                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) "
454                         "returned value {%d, %s}; expected {%d, host}",
455                         value.type, value.data.string, SDB_TYPE_STRING);
456         sdb_data_free_datum(&value);
458         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
459         fail_unless(check == 0,
460                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
461                         "%d; expected: 0");
462         fail_unless((value.type == SDB_TYPE_DATETIME)
463                         && (value.data.datetime == 20),
464                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
465                         "returned value {%d, %lu}; expected {%d, 20}",
466                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
468         check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
469         fail_unless(check == 0,
470                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
471                         "%d; expected: 0");
472         /* let's assume we're at least in year 1980 ;-) */
473         fail_unless((value.type == SDB_TYPE_DATETIME)
474                         && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
475                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
476                         "returned value {%d, %lu}; expected {%d, >%lu}",
477                         value.type, value.data.datetime,
478                         SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
480         check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
481         fail_unless(check == 0,
482                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
483                         "%d; expected: 0");
484         fail_unless((value.type == SDB_TYPE_DATETIME)
485                         && (value.data.datetime == 10),
486                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
487                         "returned value {%d, %lu}; expected {%d, 10}",
488                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
490         check = sdb_store_get_field(host, SDB_FIELD_BACKEND, &value);
491         fail_unless(check == 0,
492                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) = "
493                         "%d; expected: 0");
494         /* there are no backends in this test */
495         fail_unless((value.type == (SDB_TYPE_ARRAY | SDB_TYPE_STRING))
496                         && (value.data.array.length == 0)
497                         && (value.data.array.values == NULL),
498                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) "
499                         "returned value {%d, %lu, %p}; expected {%d, 0, NULL}",
500                         value.type, value.data.array.length, value.data.array.values,
501                         SDB_TYPE_ARRAY | SDB_TYPE_STRING);
503 END_TEST
505 START_TEST(test_get_child)
507         struct {
508                 const char *host;
509                 const char *name;
510                 int type;
511                 int expected;
512         } golden_data[] = {
513                 { "h1", NULL, SDB_HOST,       0 },
514                 { "h1", NULL, SDB_SERVICE,   -1 },
515                 { "h1", NULL, SDB_METRIC,    -1 },
516                 { "h1", NULL, SDB_ATTRIBUTE, -1 },
517                 { "h2", NULL, SDB_HOST,       0 },
518                 { "h2", NULL, SDB_SERVICE,   -1 },
519                 { "h2", NULL, SDB_METRIC,    -1 },
520                 { "h2", NULL, SDB_ATTRIBUTE, -1 },
521                 { "h3", NULL, SDB_HOST,      -1 },
522                 { "h1", "k1", SDB_ATTRIBUTE,  0 },
523                 { "h1", "x1", SDB_ATTRIBUTE, -1 },
524                 { "h2", "k1", SDB_ATTRIBUTE, -1 },
525                 { "h1", "k1", SDB_SERVICE,   -1 },
526                 { "h1", "k1", SDB_METRIC,    -1 },
527                 { "h1", "s1", SDB_SERVICE,   -1 },
528                 { "h2", "s1", SDB_SERVICE,    0 },
529                 { "h1", "m2", SDB_METRIC,     0 },
530                 { "h2", "m2", SDB_METRIC,    -1 },
531         };
533         size_t i;
535         populate();
537         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
538                 sdb_store_obj_t *obj;
539                 const char *expected_name = golden_data[i].host;
541                 obj = sdb_store_get_host(golden_data[i].host);
542                 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
543                         fail_unless(obj == NULL,
544                                         "sdb_store_get_host(%s) = %p; expected: NULL",
545                                         golden_data[i].host, obj);
546                 else
547                         fail_unless(obj != NULL,
548                                         "sdb_store_get_host(%s) = NULL; expected: <host>",
549                                         golden_data[i].host);
551                 if (golden_data[i].type != SDB_HOST) {
552                         sdb_store_obj_t *tmp;
554                         expected_name = golden_data[i].name;
556                         tmp = sdb_store_get_child(obj,
557                                         golden_data[i].type, golden_data[i].name);
558                         if (golden_data[i].expected)
559                                 fail_unless(tmp == NULL,
560                                                 "sdb_store_get_child(<%s>, %s, %s) = %p; "
561                                                 "expected: NULL", golden_data[i].host,
562                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
563                                                 golden_data[i].name, tmp);
564                         else
565                                 fail_unless(tmp != NULL,
566                                                 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
567                                                 "expected: <obj>", golden_data[i].host,
568                                                 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
569                                                 golden_data[i].name);
571                         sdb_object_deref(SDB_OBJ(obj));
572                         obj = tmp;
573                 }
575                 if (golden_data[i].expected)
576                         continue;
578                 fail_unless(obj->type == golden_data[i].type,
579                                 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
580                                 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
581                                 golden_data[i].host, golden_data[i].name, obj->type,
582                                 golden_data[i].type);
583                 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
584                                 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
585                                 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
586                                 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
587                                 expected_name);
589                 sdb_object_deref(SDB_OBJ(obj));
590         }
592 END_TEST
594 START_TEST(test_interval)
596         sdb_store_obj_t *host;
598         /* 10 us interval */
599         sdb_store_host("host", 10);
600         sdb_store_host("host", 20);
601         sdb_store_host("host", 30);
602         sdb_store_host("host", 40);
604         host = sdb_store_get_host("host");
605         fail_unless(host != NULL,
606                         "INTERNAL ERROR: store doesn't have host after adding it");
608         fail_unless(host->interval == 10,
609                         "sdb_store_host() did not calculate interval correctly: "
610                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
612         /* multiple updates for the same timestamp don't modify the interval */
613         sdb_store_host("host", 40);
614         sdb_store_host("host", 40);
615         sdb_store_host("host", 40);
616         sdb_store_host("host", 40);
618         fail_unless(host->interval == 10,
619                         "sdb_store_host() changed interval when doing multiple updates "
620                         "using the same timestamp; got: %"PRIsdbTIME"; "
621                         "expected: %"PRIsdbTIME, host->interval, 10);
623         /* multiple updates using an timestamp don't modify the interval */
624         sdb_store_host("host", 20);
625         sdb_store_host("host", 20);
626         sdb_store_host("host", 20);
627         sdb_store_host("host", 20);
629         fail_unless(host->interval == 10,
630                         "sdb_store_host() changed interval when doing multiple updates "
631                         "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
632                         host->interval, 10);
634         /* new interval: 20 us */
635         sdb_store_host("host", 60);
636         fail_unless(host->interval == 11,
637                         "sdb_store_host() did not calculate interval correctly: "
638                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
640         /* new interval: 40 us */
641         sdb_store_host("host", 100);
642         fail_unless(host->interval == 13,
643                         "sdb_store_host() did not calculate interval correctly: "
644                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
646         sdb_object_deref(SDB_OBJ(host));
648 END_TEST
650 static int
651 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
653         intptr_t *i = user_data;
655         if (! sdb_store_matcher_matches(filter, obj, NULL))
656                 return 0;
658         fail_unless(obj != NULL,
659                         "sdb_store_scan callback received NULL obj; expected: "
660                         "<store base obj>");
661         fail_unless(i != NULL,
662                         "sdb_store_scan callback received NULL user_data; "
663                         "expected: <pointer to data>");
665         ++(*i);
666         return 0;
667 } /* scan_count */
669 static int
670 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
672         intptr_t *i = user_data;
674         if (! sdb_store_matcher_matches(filter, obj, NULL))
675                 return 0;
677         fail_unless(obj != NULL,
678                         "sdb_store_scan callback received NULL obj; expected: "
679                         "<store base obj>");
680         fail_unless(i != NULL,
681                         "sdb_store_scan callback received NULL user_data; "
682                         "expected: <pointer to data>");
684         ++(*i);
685         return -1;
686 } /* scan_error */
688 START_TEST(test_scan)
690         intptr_t i = 0;
691         int check;
693         /* empty store */
694         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
695                         scan_count, &i);
696         fail_unless(check == -1,
697                         "sdb_store_scan(HOST), empty store = %d; expected: -1", check);
698         fail_unless(i == 0,
699                         "sdb_store_scan(HOST) called callback %d times; "
700                         "expected: 0", (int)i);
702         populate();
704         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
705                         scan_count, &i);
706         fail_unless(check == 0,
707                         "sdb_store_scan(HOST) = %d; expected: 0", check);
708         fail_unless(i == 2,
709                         "sdb_store_scan(HOST) called callback %d times; "
710                         "expected: 1", (int)i);
712         i = 0;
713         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
714                         scan_error, &i);
715         fail_unless(check == -1,
716                         "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
717         fail_unless(i == 1,
718                         "sdb_store_scan(HOST) called callback %d times "
719                         "(callback returned error); expected: 1", (int)i);
721         i = 0;
722         check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
723                         scan_count, &i);
724         fail_unless(check == 0,
725                         "sdb_store_scan(SERVICE) = %d; expected: 0", check);
726         fail_unless(i == 2,
727                         "sdb_store_scan(SERVICE) called callback %d times; "
728                         "expected: 2", (int)i);
730         i = 0;
731         check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
732                         scan_count, &i);
733         fail_unless(check == 0,
734                         "sdb_store_scan(METRIC) = %d; expected: 0", check);
735         fail_unless(i == 3,
736                         "sdb_store_scan(METRIC) called callback %d times; "
737                         "expected: 3", (int)i);
739 END_TEST
741 Suite *
742 core_store_suite(void)
744         Suite *s = suite_create("core::store");
745         TCase *tc;
747         tc = tcase_create("core");
748         tcase_add_test(tc, test_store_host);
749         tcase_add_test(tc, test_store_get_host);
750         tcase_add_test(tc, test_store_attr);
751         tcase_add_test(tc, test_store_metric);
752         tcase_add_test(tc, test_store_metric_attr);
753         tcase_add_test(tc, test_store_service);
754         tcase_add_test(tc, test_store_service_attr);
755         tcase_add_test(tc, test_get_field);
756         tcase_add_test(tc, test_get_child);
757         tcase_add_test(tc, test_interval);
758         tcase_add_test(tc, test_scan);
759         tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
760         suite_add_tcase(s, tc);
762         return s;
763 } /* core_store_suite */
765 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */