Code

store: Let sdb_store_scan() support other object types besides hosts.
[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>
35 static void
36 populate(void)
37 {
38         sdb_data_t datum;
40         sdb_store_host("h1", 1);
41         sdb_store_host("h2", 3);
43         datum.type = SDB_TYPE_STRING;
44         datum.data.string = "v1";
45         sdb_store_attribute("h1", "k1", &datum, 1);
46         datum.data.string = "v2";
47         sdb_store_attribute("h1", "k2", &datum, 2);
48         datum.data.string = "v3";
49         sdb_store_attribute("h1", "k3", &datum, 2);
51         /* make sure that older updates don't overwrite existing values */
52         datum.data.string = "fail";
53         sdb_store_attribute("h1", "k2", &datum, 1);
54         sdb_store_attribute("h1", "k3", &datum, 2);
56         sdb_store_metric("h1", "m1", /* store */ NULL, 2);
57         sdb_store_metric("h1", "m2", /* store */ NULL, 1);
58         sdb_store_metric("h2", "m1", /* store */ NULL, 1);
60         sdb_store_service("h2", "s1", 1);
61         sdb_store_service("h2", "s2", 2);
63         datum.type = SDB_TYPE_INTEGER;
64         datum.data.integer = 42;
65         sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
67         datum.data.integer = 123;
68         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
69         datum.data.integer = 4711;
70         sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
72         /* don't overwrite k1 */
73         datum.data.integer = 666;
74         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
75 } /* populate */
77 START_TEST(test_store_host)
78 {
79         struct {
80                 const char *name;
81                 sdb_time_t  last_update;
82                 int         expected;
83         } golden_data[] = {
84                 { "a", 1, 0 },
85                 { "a", 2, 0 },
86                 { "a", 1, 1 },
87                 { "b", 1, 0 },
88                 { "b", 1, 1 },
89                 { "A", 1, 1 }, /* case-insensitive */
90                 { "A", 3, 0 },
91         };
93         struct {
94                 const char *name;
95                 _Bool       has;
96         } golden_hosts[] = {
97                 { "a", 1 == 1 },
98                 { "b", 1 == 1 },
99                 { "c", 0 == 1 },
100                 { "A", 1 == 1 },
101         };
103         size_t i;
105         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
106                 int status;
108                 status = sdb_store_host(golden_data[i].name,
109                                 golden_data[i].last_update);
110                 fail_unless(status == golden_data[i].expected,
111                                 "sdb_store_host(%s, %d) = %d; expected: %d",
112                                 golden_data[i].name, (int)golden_data[i].last_update,
113                                 status, golden_data[i].expected);
114         }
116         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
117                 _Bool has;
119                 has = sdb_store_has_host(golden_hosts[i].name);
120                 fail_unless(has == golden_hosts[i].has,
121                                 "sdb_store_has_host(%s) = %d; expected: %d",
122                                 golden_hosts[i].name, has, golden_hosts[i].has);
123         }
125 END_TEST
127 START_TEST(test_store_get_host)
129         char *golden_hosts[] = { "a", "b", "c" };
130         char *unknown_hosts[] = { "x", "y", "z" };
131         size_t i;
133         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
134                 int status = sdb_store_host(golden_hosts[i], 1);
135                 fail_unless(status >= 0,
136                                 "sdb_store_host(%s) = %d; expected: >=0",
137                                 golden_hosts[i], status);
138         }
140         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
141                 sdb_store_obj_t *sobj1, *sobj2;
142                 int ref_cnt;
144                 fail_unless(sdb_store_has_host(golden_hosts[i]),
145                                 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
146                                 golden_hosts[i]);
148                 sobj1 = sdb_store_get_host(golden_hosts[i]);
149                 fail_unless(sobj1 != NULL,
150                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
151                                 golden_hosts[i]);
152                 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
154                 fail_unless(ref_cnt > 1,
155                                 "sdb_store_get_host(%s) did not increment ref count: "
156                                 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
158                 sobj2 = sdb_store_get_host(golden_hosts[i]);
159                 fail_unless(sobj2 != NULL,
160                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
161                                 golden_hosts[i]);
163                 fail_unless(sobj1 == sobj2,
164                                 "sdb_store_get_host(%s) returned different objects "
165                                 "in successive calls", golden_hosts[i]);
166                 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
167                                 "sdb_store_get_hosts(%s) did not increment ref count "
168                                 "(first call: %d; second call: %d)",
169                                 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
171                 sdb_object_deref(SDB_OBJ(sobj1));
172                 sdb_object_deref(SDB_OBJ(sobj2));
173         }
174         for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
175                 sdb_store_obj_t *sobj;
177                 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
178                                 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
179                                 unknown_hosts[i]);
181                 sobj = sdb_store_get_host(unknown_hosts[i]);
182                 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
183                                 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
184         }
186 END_TEST
188 START_TEST(test_store_attr)
190         struct {
191                 const char *host;
192                 const char *key;
193                 char       *value;
194                 sdb_time_t  last_update;
195                 int         expected;
196         } golden_data[] = {
197                 { "k", "k",  "v",  1, -1 },
198                 { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
199                 { "l", "k1", "v1", 1,  0 },
200                 { "l", "k1", "v2", 2,  0 },
201                 { "l", "k1", "v3", 2,  1 },
202                 { "l", "k2", "v1", 1,  0 },
203                 { "m", "k",  "v1", 1,  0 },
204                 { "m", "k",  "v2", 1,  1 },
205         };
207         size_t i;
209         sdb_store_host("l", 1);
210         sdb_store_host("m", 1);
211         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
212                 sdb_data_t datum;
213                 int status;
215                 /* XXX: test other types as well */
216                 datum.type = SDB_TYPE_STRING;
217                 datum.data.string = golden_data[i].value;
219                 status = sdb_store_attribute(golden_data[i].host,
220                                 golden_data[i].key, &datum,
221                                 golden_data[i].last_update);
222                 fail_unless(status == golden_data[i].expected,
223                                 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
224                                 golden_data[i].host, golden_data[i].key, golden_data[i].value,
225                                 golden_data[i].last_update, status, golden_data[i].expected);
226         }
228 END_TEST
230 START_TEST(test_store_metric)
232         sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
233         sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
235         struct {
236                 const char *host;
237                 const char *metric;
238                 sdb_metric_store_t *store;
239                 sdb_time_t  last_update;
240                 int         expected;
241         } golden_data[] = {
242                 { "k", "m",  NULL,    1, -1 },
243                 { "k", "m",  NULL,    1, -1 }, /* retry to ensure the host is not created */
244                 { "k", "m",  &store1, 1, -1 },
245                 { "l", "m1", NULL,    1,  0 },
246                 { "l", "m1", &store1, 2,  0 },
247                 { "l", "m1", &store1, 3,  0 },
248                 { "l", "m1", NULL,    3,  1 },
249                 { "l", "m2", &store1, 1,  0 },
250                 { "l", "m2", &store2, 2,  0 },
251                 { "l", "m2", NULL,    3,  0 },
252                 { "m", "m",  &store1, 1,  0 },
253                 { "m", "m",  NULL,    2,  0 },
254                 { "m", "m",  NULL,    2,  1 },
255                 { "m", "m",  &store1, 3,  0 },
256                 { "m", "m",  &store2, 4,  0 },
257                 { "m", "m",  NULL,    5,  0 },
258         };
260         size_t i;
262         sdb_store_host("m", 1);
263         sdb_store_host("l", 1);
264         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
265                 int status;
267                 status = sdb_store_metric(golden_data[i].host,
268                                 golden_data[i].metric, golden_data[i].store,
269                                 golden_data[i].last_update);
270                 fail_unless(status == golden_data[i].expected,
271                                 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
272                                 golden_data[i].host, golden_data[i].metric,
273                                 golden_data[i].store, golden_data[i].last_update,
274                                 status, golden_data[i].expected);
275         }
277 END_TEST
279 START_TEST(test_store_metric_attr)
281         struct {
282                 const char *host;
283                 const char *metric;
284                 const char *attr;
285                 const sdb_data_t value;
286                 sdb_time_t  last_update;
287                 int expected;
288         } golden_data[] = {
289                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
290                 /* retry, it should still fail */
291                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
292                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
293                 /* retry, it should still fail */
294                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
295                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
296                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
297                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
298                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
299                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
300                 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
301                 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
302         };
304         size_t i;
306         sdb_store_host("m", 1);
307         sdb_store_host("l", 1);
308         sdb_store_metric("m", "m1", NULL, 1);
309         sdb_store_metric("l", "m1", NULL, 1);
310         sdb_store_metric("l", "m2", NULL, 1);
312         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
313                 int status;
315                 status = sdb_store_metric_attr(golden_data[i].host,
316                                 golden_data[i].metric, golden_data[i].attr,
317                                 &golden_data[i].value, golden_data[i].last_update);
318                 fail_unless(status == golden_data[i].expected,
319                                 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
320                                 "expected: %d", golden_data[i].host, golden_data[i].metric,
321                                 golden_data[i].attr, golden_data[i].value.data.integer,
322                                 golden_data[i].last_update, status, golden_data[i].expected);
323         }
325 END_TEST
327 START_TEST(test_store_service)
329         struct {
330                 const char *host;
331                 const char *svc;
332                 sdb_time_t  last_update;
333                 int         expected;
334         } golden_data[] = {
335                 { "k", "s",  1, -1 },
336                 { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
337                 { "l", "s1", 1,  0 },
338                 { "l", "s1", 2,  0 },
339                 { "l", "s1", 2,  1 },
340                 { "l", "s2", 1,  0 },
341                 { "m", "s",  1,  0 },
342                 { "m", "s",  1,  1 },
343         };
345         size_t i;
347         sdb_store_host("m", 1);
348         sdb_store_host("l", 1);
349         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
350                 int status;
352                 status = sdb_store_service(golden_data[i].host,
353                                 golden_data[i].svc, golden_data[i].last_update);
354                 fail_unless(status == golden_data[i].expected,
355                                 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
356                                 golden_data[i].host, golden_data[i].svc,
357                                 golden_data[i].last_update, status, golden_data[i].expected);
358         }
360 END_TEST
362 START_TEST(test_store_service_attr)
364         struct {
365                 const char *host;
366                 const char *svc;
367                 const char *attr;
368                 const sdb_data_t value;
369                 sdb_time_t  last_update;
370                 int expected;
371         } golden_data[] = {
372                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
373                 /* retry, it should still fail */
374                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
375                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
376                 /* retry, it should still fail */
377                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
378                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
379                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
380                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
381                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
382                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
383                 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
384                 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
385         };
387         size_t i;
389         sdb_store_host("m", 1);
390         sdb_store_host("l", 1);
391         sdb_store_service("m", "s1", 1);
392         sdb_store_service("l", "s1", 1);
393         sdb_store_service("l", "s2", 1);
395         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
396                 int status;
398                 status = sdb_store_service_attr(golden_data[i].host,
399                                 golden_data[i].svc, golden_data[i].attr,
400                                 &golden_data[i].value, golden_data[i].last_update);
401                 fail_unless(status == golden_data[i].expected,
402                                 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
403                                 "expected: %d", golden_data[i].host, golden_data[i].svc,
404                                 golden_data[i].attr, golden_data[i].value.data.integer,
405                                 golden_data[i].last_update, status, golden_data[i].expected);
406         }
408 END_TEST
410 static void
411 verify_json_output(sdb_strbuf_t *buf, const char *expected,
412                 sdb_store_matcher_t *filter, int flags)
414         int pos;
415         size_t len1, len2;
416         size_t i;
418         len1 = strlen(sdb_strbuf_string(buf));
419         len2 = strlen(expected);
421         pos = -1;
422         if (len1 != len2)
423                 pos = (int)(len1 <= len2 ? len1 : len2);
425         for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
426                 if (sdb_strbuf_string(buf)[i] != expected[i]) {
427                         pos = (int)i;
428                         break;
429                 }
430         }
432         fail_unless(pos == -1,
433                         "sdb_store_tojson(<buf>, %p, %x) returned unexpected result\n"
434                         "         got: %s\n              %*s\n    expected: %s",
435                         filter, flags, sdb_strbuf_string(buf), pos + 1, "^",
436                         expected);
437 } /* verify_json_output */
439 START_TEST(test_store_tojson)
441         sdb_strbuf_t *buf;
442         size_t i;
444         struct {
445                 struct {
446                         sdb_store_matcher_t *(*m)(sdb_store_expr_t *,
447                                         sdb_store_expr_t *);
448                         int field;
449                         sdb_data_t value;
450                 } filter;
451                 int flags;
452                 const char *expected;
453         } golden_data[] = {
454                 { { NULL, 0, SDB_DATA_INIT }, 0,
455                         "["
456                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
457                                         "\"update_interval\": \"0s\", \"backends\": [], "
458                                         "\"attributes\": ["
459                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
460                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
461                                                         "\"update_interval\": \"0s\", \"backends\": []},"
462                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
463                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
464                                                         "\"update_interval\": \"0s\", \"backends\": []},"
465                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
466                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
467                                                         "\"update_interval\": \"0s\", \"backends\": []}"
468                                         "], "
469                                         "\"metrics\": ["
470                                                 "{\"name\": \"m1\", "
471                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
472                                                         "\"update_interval\": \"0s\", \"backends\": [], "
473                                                         "\"attributes\": ["
474                                                                 "{\"name\": \"k3\", \"value\": 42, "
475                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
476                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
477                                                         "]},"
478                                                 "{\"name\": \"m2\", "
479                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
480                                                         "\"update_interval\": \"0s\", \"backends\": [], "
481                                                         "\"attributes\": []}"
482                                         "], "
483                                         "\"services\": []},"
484                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
485                                         "\"update_interval\": \"0s\", \"backends\": [], "
486                                         "\"attributes\": [], "
487                                         "\"metrics\": ["
488                                                 "{\"name\": \"m1\", "
489                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
490                                                         "\"update_interval\": \"0s\", \"backends\": [], "
491                                                         "\"attributes\": []}"
492                                         "], "
493                                         "\"services\": ["
494                                                 "{\"name\": \"s1\", "
495                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
496                                                         "\"update_interval\": \"0s\", \"backends\": [], "
497                                                         "\"attributes\": []},"
498                                                 "{\"name\": \"s2\", "
499                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
500                                                         "\"update_interval\": \"0s\", \"backends\": [], "
501                                                         "\"attributes\": ["
502                                                                 "{\"name\": \"k1\", \"value\": 123, "
503                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
504                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
505                                                                 "{\"name\": \"k2\", \"value\": 4711, "
506                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
507                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
508                                                         "]}"
509                                         "]}"
510                         "]" },
511                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_SERVICES,
512                         "["
513                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
514                                         "\"update_interval\": \"0s\", \"backends\": [], "
515                                         "\"attributes\": ["
516                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
517                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
518                                                         "\"update_interval\": \"0s\", \"backends\": []},"
519                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
520                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
521                                                         "\"update_interval\": \"0s\", \"backends\": []},"
522                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
523                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
524                                                         "\"update_interval\": \"0s\", \"backends\": []}"
525                                         "], "
526                                         "\"metrics\": ["
527                                                 "{\"name\": \"m1\", "
528                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
529                                                         "\"update_interval\": \"0s\", \"backends\": [], "
530                                                         "\"attributes\": ["
531                                                                 "{\"name\": \"k3\", \"value\": 42, "
532                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
533                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
534                                                         "]},"
535                                                 "{\"name\": \"m2\", "
536                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
537                                                         "\"update_interval\": \"0s\", \"backends\": [], "
538                                                         "\"attributes\": []}"
539                                         "]},"
540                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
541                                         "\"update_interval\": \"0s\", \"backends\": [], "
542                                         "\"attributes\": [], "
543                                         "\"metrics\": ["
544                                                 "{\"name\": \"m1\", "
545                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
546                                                         "\"update_interval\": \"0s\", \"backends\": [], "
547                                                         "\"attributes\": []}"
548                                         "]}"
549                         "]" },
550                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_METRICS,
551                         "["
552                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
553                                         "\"update_interval\": \"0s\", \"backends\": [], "
554                                         "\"attributes\": ["
555                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
556                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
557                                                         "\"update_interval\": \"0s\", \"backends\": []},"
558                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
559                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
560                                                         "\"update_interval\": \"0s\", \"backends\": []},"
561                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
562                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
563                                                         "\"update_interval\": \"0s\", \"backends\": []}"
564                                         "], "
565                                         "\"services\": []},"
566                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
567                                         "\"update_interval\": \"0s\", \"backends\": [], "
568                                         "\"attributes\": [], "
569                                         "\"services\": ["
570                                                 "{\"name\": \"s1\", "
571                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
572                                                         "\"update_interval\": \"0s\", \"backends\": [], "
573                                                         "\"attributes\": []},"
574                                                 "{\"name\": \"s2\", "
575                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
576                                                         "\"update_interval\": \"0s\", \"backends\": [], "
577                                                         "\"attributes\": ["
578                                                                 "{\"name\": \"k1\", \"value\": 123, "
579                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
580                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
581                                                                 "{\"name\": \"k2\", \"value\": 4711, "
582                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
583                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
584                                                         "]}"
585                                         "]}"
586                         "]" },
587                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ATTRIBUTES,
588                         "["
589                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
590                                         "\"update_interval\": \"0s\", \"backends\": [], "
591                                         "\"metrics\": ["
592                                                 "{\"name\": \"m1\", "
593                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
594                                                         "\"update_interval\": \"0s\", \"backends\": []},"
595                                                 "{\"name\": \"m2\", "
596                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
597                                                         "\"update_interval\": \"0s\", \"backends\": []}"
598                                         "], "
599                                         "\"services\": []},"
600                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
601                                         "\"update_interval\": \"0s\", \"backends\": [], "
602                                         "\"metrics\": ["
603                                                 "{\"name\": \"m1\", "
604                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
605                                                         "\"update_interval\": \"0s\", \"backends\": []}"
606                                         "], "
607                                         "\"services\": ["
608                                                 "{\"name\": \"s1\", "
609                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
610                                                         "\"update_interval\": \"0s\", \"backends\": []},"
611                                                 "{\"name\": \"s2\", "
612                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
613                                                         "\"update_interval\": \"0s\", \"backends\": []}"
614                                         "]}"
615                         "]" },
616                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ALL,
617                         "["
618                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
619                                         "\"update_interval\": \"0s\", \"backends\": []},"
620                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
621                                         "\"update_interval\": \"0s\", \"backends\": []}"
622                         "]" },
623                 { { sdb_store_eq_matcher, SDB_FIELD_NAME,
624                                 { SDB_TYPE_STRING, { .string = "h1" } } }, 0,
625                         "["
626                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
627                                         "\"update_interval\": \"0s\", \"backends\": [], "
628                                         "\"attributes\": [], \"metrics\": [], \"services\": []}"
629                         "]" },
630                 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
631                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
632                         "["
633                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
634                                         "\"update_interval\": \"0s\", \"backends\": [], "
635                                         "\"attributes\": [], "
636                                         "\"metrics\": [], "
637                                         "\"services\": ["
638                                                 "{\"name\": \"s2\", "
639                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
640                                                         "\"update_interval\": \"0s\", \"backends\": [], "
641                                                         "\"attributes\": ["
642                                                                 "{\"name\": \"k1\", \"value\": 123, "
643                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
644                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
645                                                         "]}"
646                                         "]}"
647                         "]" },
648                 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
649                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
650                         "["
651                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
652                                         "\"update_interval\": \"0s\", \"backends\": [], "
653                                         "\"attributes\": ["
654                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
655                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
656                                                         "\"update_interval\": \"0s\", \"backends\": []},"
657                                         "], "
658                                         "\"metrics\": ["
659                                                 "{\"name\": \"m2\", "
660                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
661                                                         "\"update_interval\": \"0s\", \"backends\": [], "
662                                                         "\"attributes\": []}"
663                                         "], "
664                                         "\"services\": []}"
665                         "]" },
666                 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
667                                 { SDB_TYPE_DATETIME, { .datetime = 3 } } }, 0,
668                         "["
669                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
670                                         "\"update_interval\": \"0s\", \"backends\": [], "
671                                         "\"attributes\": [], "
672                                         "\"metrics\": [], "
673                                         "\"services\": []}"
674                         "]" },
675         };
677         buf = sdb_strbuf_create(0);
678         fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
679         populate();
681         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
682                 sdb_store_matcher_t *filter = NULL;
683                 int status;
685                 sdb_strbuf_clear(buf);
687                 if (golden_data[i].filter.m) {
688                         sdb_store_expr_t *field;
689                         sdb_store_expr_t *value;
691                         field = sdb_store_expr_fieldvalue(golden_data[i].filter.field);
692                         fail_unless(field != NULL,
693                                         "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
694                         value = sdb_store_expr_constvalue(&golden_data[i].filter.value);
695                         fail_unless(value != NULL,
696                                         "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
698                         filter = golden_data[i].filter.m(field, value);
699                         fail_unless(filter != NULL,
700                                         "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
702                         sdb_object_deref(SDB_OBJ(field));
703                         sdb_object_deref(SDB_OBJ(value));
704                 }
706                 status = sdb_store_tojson(buf, filter, golden_data[i].flags);
707                 fail_unless(status == 0,
708                                 "sdb_store_tojson(<buf>, %p, %x) = %d; expected: 0",
709                                 filter, golden_data[i].flags, status);
711                 verify_json_output(buf, golden_data[i].expected,
712                                 filter, golden_data[i].flags);
713                 sdb_object_deref(SDB_OBJ(filter));
714         }
715         sdb_strbuf_destroy(buf);
717 END_TEST
719 START_TEST(test_get_field)
721         sdb_store_obj_t *host;
722         sdb_data_t value = SDB_DATA_INIT;
723         int check;
725         sdb_store_host("host", 10);
726         sdb_store_host("host", 20);
728         host = sdb_store_get_host("host");
729         fail_unless(host != NULL,
730                         "INTERNAL ERROR: store doesn't have host after adding it");
732         check = sdb_store_get_field(NULL, 0, NULL);
733         fail_unless(check < 0,
734                         "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
735         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
736         fail_unless(check < 0,
737                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
738                         "expected: <0");
739         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
740         fail_unless(check < 0,
741                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
742                         "expected: <0");
744         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
745         fail_unless(check == 0,
746                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
747                         "expected: 0");
748         /* 'name' is dynamically allocated; make sure it's not leaked even
749          * if there is no result parameter */
750         check = sdb_store_get_field(host, SDB_FIELD_NAME, NULL);
751         fail_unless(check == 0,
752                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
753                         "expected: 0");
755         check = sdb_store_get_field(host, SDB_FIELD_NAME, &value);
756         fail_unless(check == 0,
757                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) = "
758                         "%d; expected: 0");
759         fail_unless((value.type == SDB_TYPE_STRING)
760                         && (! strcmp(value.data.string, "host")),
761                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) "
762                         "returned value {%d, %s}; expected {%d, host}",
763                         value.type, value.data.string, SDB_TYPE_STRING);
764         sdb_data_free_datum(&value);
766         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
767         fail_unless(check == 0,
768                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
769                         "%d; expected: 0");
770         fail_unless((value.type == SDB_TYPE_DATETIME)
771                         && (value.data.datetime == 20),
772                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
773                         "returned value {%d, %lu}; expected {%d, 20}",
774                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
776         check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
777         fail_unless(check == 0,
778                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
779                         "%d; expected: 0");
780         /* let's assume we're at least in year 1980 ;-) */
781         fail_unless((value.type == SDB_TYPE_DATETIME)
782                         && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
783                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
784                         "returned value {%d, %lu}; expected {%d, >%lu}",
785                         value.type, value.data.datetime,
786                         SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
788         check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
789         fail_unless(check == 0,
790                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
791                         "%d; expected: 0");
792         fail_unless((value.type == SDB_TYPE_DATETIME)
793                         && (value.data.datetime == 10),
794                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
795                         "returned value {%d, %lu}; expected {%d, 10}",
796                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
798         check = sdb_store_get_field(host, SDB_FIELD_BACKEND, &value);
799         fail_unless(check == 0,
800                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) = "
801                         "%d; expected: 0");
802         /* there are no backends in this test */
803         fail_unless((value.type == (SDB_TYPE_ARRAY | SDB_TYPE_STRING))
804                         && (value.data.array.length == 0)
805                         && (value.data.array.values == NULL),
806                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) "
807                         "returned value {%d, %lu, %p}; expected {%d, 0, NULL}",
808                         value.type, value.data.array.length, value.data.array.values,
809                         SDB_TYPE_ARRAY | SDB_TYPE_STRING);
811 END_TEST
813 START_TEST(test_interval)
815         sdb_store_obj_t *host;
817         /* 10 us interval */
818         sdb_store_host("host", 10);
819         sdb_store_host("host", 20);
820         sdb_store_host("host", 30);
821         sdb_store_host("host", 40);
823         host = sdb_store_get_host("host");
824         fail_unless(host != NULL,
825                         "INTERNAL ERROR: store doesn't have host after adding it");
827         fail_unless(host->interval == 10,
828                         "sdb_store_host() did not calculate interval correctly: "
829                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
831         /* multiple updates for the same timestamp don't modify the interval */
832         sdb_store_host("host", 40);
833         sdb_store_host("host", 40);
834         sdb_store_host("host", 40);
835         sdb_store_host("host", 40);
837         fail_unless(host->interval == 10,
838                         "sdb_store_host() changed interval when doing multiple updates "
839                         "using the same timestamp; got: %"PRIsdbTIME"; "
840                         "expected: %"PRIsdbTIME, host->interval, 10);
842         /* multiple updates using an timestamp don't modify the interval */
843         sdb_store_host("host", 20);
844         sdb_store_host("host", 20);
845         sdb_store_host("host", 20);
846         sdb_store_host("host", 20);
848         fail_unless(host->interval == 10,
849                         "sdb_store_host() changed interval when doing multiple updates "
850                         "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
851                         host->interval, 10);
853         /* new interval: 20 us */
854         sdb_store_host("host", 60);
855         fail_unless(host->interval == 11,
856                         "sdb_store_host() did not calculate interval correctly: "
857                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
859         /* new interval: 40 us */
860         sdb_store_host("host", 100);
861         fail_unless(host->interval == 13,
862                         "sdb_store_host() did not calculate interval correctly: "
863                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
865         sdb_object_deref(SDB_OBJ(host));
867 END_TEST
869 static int
870 scan_count(sdb_store_obj_t *obj, void *user_data)
872         intptr_t *i = user_data;
874         fail_unless(obj != NULL,
875                         "sdb_store_scan callback received NULL obj; expected: "
876                         "<store base obj>");
877         fail_unless(i != NULL,
878                         "sdb_store_scan callback received NULL user_data; "
879                         "expected: <pointer to data>");
881         ++(*i);
882         return 0;
883 } /* scan_count */
885 static int
886 scan_error(sdb_store_obj_t *obj, void *user_data)
888         intptr_t *i = user_data;
890         fail_unless(obj != NULL,
891                         "sdb_store_scan callback received NULL obj; expected: "
892                         "<store base obj>");
893         fail_unless(i != NULL,
894                         "sdb_store_scan callback received NULL user_data; "
895                         "expected: <pointer to data>");
897         ++(*i);
898         return -1;
899 } /* scan_error */
901 START_TEST(test_scan)
903         intptr_t i = 0;
904         int check;
906         /* empty store */
907         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
908                         scan_count, &i);
909         fail_unless(check == -1,
910                         "sdb_store_scan(HOST), empty store = %d; expected: -1", check);
911         fail_unless(i == 0,
912                         "sdb_store_scan(HOST) called callback %d times; "
913                         "expected: 0", (int)i);
915         populate();
917         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
918                         scan_count, &i);
919         fail_unless(check == 0,
920                         "sdb_store_scan(HOST) = %d; expected: 0", check);
921         fail_unless(i == 2,
922                         "sdb_store_scan(HOST) called callback %d times; "
923                         "expected: 1", (int)i);
925         i = 0;
926         check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
927                         scan_error, &i);
928         fail_unless(check == -1,
929                         "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
930         fail_unless(i == 1,
931                         "sdb_store_scan(HOST) called callback %d times "
932                         "(callback returned error); expected: 1", (int)i);
934         i = 0;
935         check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
936                         scan_count, &i);
937         fail_unless(check == 0,
938                         "sdb_store_scan(SERVICE) = %d; expected: 0", check);
939         fail_unless(i == 2,
940                         "sdb_store_scan(SERVICE) called callback %d times; "
941                         "expected: 2", (int)i);
943         i = 0;
944         check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
945                         scan_count, &i);
946         fail_unless(check == 0,
947                         "sdb_store_scan(METRIC) = %d; expected: 0", check);
948         fail_unless(i == 3,
949                         "sdb_store_scan(METRIC) called callback %d times; "
950                         "expected: 3", (int)i);
952 END_TEST
954 Suite *
955 core_store_suite(void)
957         Suite *s = suite_create("core::store");
958         TCase *tc;
960         tc = tcase_create("core");
961         tcase_add_test(tc, test_store_tojson);
962         tcase_add_test(tc, test_store_host);
963         tcase_add_test(tc, test_store_get_host);
964         tcase_add_test(tc, test_store_attr);
965         tcase_add_test(tc, test_store_metric);
966         tcase_add_test(tc, test_store_metric_attr);
967         tcase_add_test(tc, test_store_service);
968         tcase_add_test(tc, test_store_service_attr);
969         tcase_add_test(tc, test_get_field);
970         tcase_add_test(tc, test_interval);
971         tcase_add_test(tc, test_scan);
972         tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
973         suite_add_tcase(s, tc);
975         return s;
976 } /* core_store_suite */
978 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */