Code

store: Merged sdb_store_iterate() into sdb_store_scan().
[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);
59         sdb_store_service("h2", "s1", 1);
60         sdb_store_service("h2", "s2", 2);
62         datum.type = SDB_TYPE_INTEGER;
63         datum.data.integer = 42;
64         sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
66         datum.data.integer = 123;
67         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
68         datum.data.integer = 4711;
69         sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
71         /* don't overwrite k1 */
72         datum.data.integer = 666;
73         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
74 } /* populate */
76 START_TEST(test_store_host)
77 {
78         struct {
79                 const char *name;
80                 sdb_time_t  last_update;
81                 int         expected;
82         } golden_data[] = {
83                 { "a", 1, 0 },
84                 { "a", 2, 0 },
85                 { "a", 1, 1 },
86                 { "b", 1, 0 },
87                 { "b", 1, 1 },
88                 { "A", 1, 1 }, /* case-insensitive */
89                 { "A", 3, 0 },
90         };
92         struct {
93                 const char *name;
94                 _Bool       has;
95         } golden_hosts[] = {
96                 { "a", 1 == 1 },
97                 { "b", 1 == 1 },
98                 { "c", 0 == 1 },
99                 { "A", 1 == 1 },
100         };
102         size_t i;
104         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
105                 int status;
107                 status = sdb_store_host(golden_data[i].name,
108                                 golden_data[i].last_update);
109                 fail_unless(status == golden_data[i].expected,
110                                 "sdb_store_host(%s, %d) = %d; expected: %d",
111                                 golden_data[i].name, (int)golden_data[i].last_update,
112                                 status, golden_data[i].expected);
113         }
115         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
116                 _Bool has;
118                 has = sdb_store_has_host(golden_hosts[i].name);
119                 fail_unless(has == golden_hosts[i].has,
120                                 "sdb_store_has_host(%s) = %d; expected: %d",
121                                 golden_hosts[i].name, has, golden_hosts[i].has);
122         }
124 END_TEST
126 START_TEST(test_store_get_host)
128         char *golden_hosts[] = { "a", "b", "c" };
129         char *unknown_hosts[] = { "x", "y", "z" };
130         size_t i;
132         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
133                 int status = sdb_store_host(golden_hosts[i], 1);
134                 fail_unless(status >= 0,
135                                 "sdb_store_host(%s) = %d; expected: >=0",
136                                 golden_hosts[i], status);
137         }
139         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
140                 sdb_store_obj_t *sobj1, *sobj2;
141                 int ref_cnt;
143                 fail_unless(sdb_store_has_host(golden_hosts[i]),
144                                 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
145                                 golden_hosts[i]);
147                 sobj1 = sdb_store_get_host(golden_hosts[i]);
148                 fail_unless(sobj1 != NULL,
149                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
150                                 golden_hosts[i]);
151                 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
153                 fail_unless(ref_cnt > 1,
154                                 "sdb_store_get_host(%s) did not increment ref count: "
155                                 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
157                 sobj2 = sdb_store_get_host(golden_hosts[i]);
158                 fail_unless(sobj2 != NULL,
159                                 "sdb_store_get_host(%s) = NULL; expected: <host>",
160                                 golden_hosts[i]);
162                 fail_unless(sobj1 == sobj2,
163                                 "sdb_store_get_host(%s) returned different objects "
164                                 "in successive calls", golden_hosts[i]);
165                 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
166                                 "sdb_store_get_hosts(%s) did not increment ref count "
167                                 "(first call: %d; second call: %d)",
168                                 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
170                 sdb_object_deref(SDB_OBJ(sobj1));
171                 sdb_object_deref(SDB_OBJ(sobj2));
172         }
173         for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
174                 sdb_store_obj_t *sobj;
176                 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
177                                 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
178                                 unknown_hosts[i]);
180                 sobj = sdb_store_get_host(unknown_hosts[i]);
181                 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
182                                 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
183         }
185 END_TEST
187 START_TEST(test_store_attr)
189         struct {
190                 const char *host;
191                 const char *key;
192                 char       *value;
193                 sdb_time_t  last_update;
194                 int         expected;
195         } golden_data[] = {
196                 { "k", "k",  "v",  1, -1 },
197                 { "k", "k",  "v",  1, -1 }, /* retry to ensure the host is not created */
198                 { "l", "k1", "v1", 1,  0 },
199                 { "l", "k1", "v2", 2,  0 },
200                 { "l", "k1", "v3", 2,  1 },
201                 { "l", "k2", "v1", 1,  0 },
202                 { "m", "k",  "v1", 1,  0 },
203                 { "m", "k",  "v2", 1,  1 },
204         };
206         size_t i;
208         sdb_store_host("l", 1);
209         sdb_store_host("m", 1);
210         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
211                 sdb_data_t datum;
212                 int status;
214                 /* XXX: test other types as well */
215                 datum.type = SDB_TYPE_STRING;
216                 datum.data.string = golden_data[i].value;
218                 status = sdb_store_attribute(golden_data[i].host,
219                                 golden_data[i].key, &datum,
220                                 golden_data[i].last_update);
221                 fail_unless(status == golden_data[i].expected,
222                                 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
223                                 golden_data[i].host, golden_data[i].key, golden_data[i].value,
224                                 golden_data[i].last_update, status, golden_data[i].expected);
225         }
227 END_TEST
229 START_TEST(test_store_metric)
231         sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
232         sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
234         struct {
235                 const char *host;
236                 const char *metric;
237                 sdb_metric_store_t *store;
238                 sdb_time_t  last_update;
239                 int         expected;
240         } golden_data[] = {
241                 { "k", "m",  NULL,    1, -1 },
242                 { "k", "m",  NULL,    1, -1 }, /* retry to ensure the host is not created */
243                 { "k", "m",  &store1, 1, -1 },
244                 { "l", "m1", NULL,    1,  0 },
245                 { "l", "m1", &store1, 2,  0 },
246                 { "l", "m1", &store1, 3,  0 },
247                 { "l", "m1", NULL,    3,  1 },
248                 { "l", "m2", &store1, 1,  0 },
249                 { "l", "m2", &store2, 2,  0 },
250                 { "l", "m2", NULL,    3,  0 },
251                 { "m", "m",  &store1, 1,  0 },
252                 { "m", "m",  NULL,    2,  0 },
253                 { "m", "m",  NULL,    2,  1 },
254                 { "m", "m",  &store1, 3,  0 },
255                 { "m", "m",  &store2, 4,  0 },
256                 { "m", "m",  NULL,    5,  0 },
257         };
259         size_t i;
261         sdb_store_host("m", 1);
262         sdb_store_host("l", 1);
263         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
264                 int status;
266                 status = sdb_store_metric(golden_data[i].host,
267                                 golden_data[i].metric, golden_data[i].store,
268                                 golden_data[i].last_update);
269                 fail_unless(status == golden_data[i].expected,
270                                 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
271                                 golden_data[i].host, golden_data[i].metric,
272                                 golden_data[i].store, golden_data[i].last_update,
273                                 status, golden_data[i].expected);
274         }
276 END_TEST
278 START_TEST(test_store_metric_attr)
280         struct {
281                 const char *host;
282                 const char *metric;
283                 const char *attr;
284                 const sdb_data_t value;
285                 sdb_time_t  last_update;
286                 int expected;
287         } golden_data[] = {
288                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
289                 /* retry, it should still fail */
290                 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
291                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
292                 /* retry, it should still fail */
293                 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
294                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
295                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
296                 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
297                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
298                 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
299                 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
300                 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
301         };
303         size_t i;
305         sdb_store_host("m", 1);
306         sdb_store_host("l", 1);
307         sdb_store_metric("m", "m1", NULL, 1);
308         sdb_store_metric("l", "m1", NULL, 1);
309         sdb_store_metric("l", "m2", NULL, 1);
311         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
312                 int status;
314                 status = sdb_store_metric_attr(golden_data[i].host,
315                                 golden_data[i].metric, golden_data[i].attr,
316                                 &golden_data[i].value, golden_data[i].last_update);
317                 fail_unless(status == golden_data[i].expected,
318                                 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
319                                 "expected: %d", golden_data[i].host, golden_data[i].metric,
320                                 golden_data[i].attr, golden_data[i].value.data.integer,
321                                 golden_data[i].last_update, status, golden_data[i].expected);
322         }
324 END_TEST
326 START_TEST(test_store_service)
328         struct {
329                 const char *host;
330                 const char *svc;
331                 sdb_time_t  last_update;
332                 int         expected;
333         } golden_data[] = {
334                 { "k", "s",  1, -1 },
335                 { "k", "s",  1, -1 }, /* retry to ensure the host is not created */
336                 { "l", "s1", 1,  0 },
337                 { "l", "s1", 2,  0 },
338                 { "l", "s1", 2,  1 },
339                 { "l", "s2", 1,  0 },
340                 { "m", "s",  1,  0 },
341                 { "m", "s",  1,  1 },
342         };
344         size_t i;
346         sdb_store_host("m", 1);
347         sdb_store_host("l", 1);
348         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
349                 int status;
351                 status = sdb_store_service(golden_data[i].host,
352                                 golden_data[i].svc, golden_data[i].last_update);
353                 fail_unless(status == golden_data[i].expected,
354                                 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
355                                 golden_data[i].host, golden_data[i].svc,
356                                 golden_data[i].last_update, status, golden_data[i].expected);
357         }
359 END_TEST
361 START_TEST(test_store_service_attr)
363         struct {
364                 const char *host;
365                 const char *svc;
366                 const char *attr;
367                 const sdb_data_t value;
368                 sdb_time_t  last_update;
369                 int expected;
370         } golden_data[] = {
371                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
372                 /* retry, it should still fail */
373                 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
374                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
375                 /* retry, it should still fail */
376                 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
377                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
378                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
379                 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2,  0 },
380                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
381                 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  1 },
382                 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
383                 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1,  0 },
384         };
386         size_t i;
388         sdb_store_host("m", 1);
389         sdb_store_host("l", 1);
390         sdb_store_service("m", "s1", 1);
391         sdb_store_service("l", "s1", 1);
392         sdb_store_service("l", "s2", 1);
394         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
395                 int status;
397                 status = sdb_store_service_attr(golden_data[i].host,
398                                 golden_data[i].svc, golden_data[i].attr,
399                                 &golden_data[i].value, golden_data[i].last_update);
400                 fail_unless(status == golden_data[i].expected,
401                                 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
402                                 "expected: %d", golden_data[i].host, golden_data[i].svc,
403                                 golden_data[i].attr, golden_data[i].value.data.integer,
404                                 golden_data[i].last_update, status, golden_data[i].expected);
405         }
407 END_TEST
409 static void
410 verify_json_output(sdb_strbuf_t *buf, const char *expected,
411                 sdb_store_matcher_t *filter, int flags)
413         int pos;
414         size_t len1, len2;
415         size_t i;
417         len1 = strlen(sdb_strbuf_string(buf));
418         len2 = strlen(expected);
420         pos = -1;
421         if (len1 != len2)
422                 pos = (int)(len1 <= len2 ? len1 : len2);
424         for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
425                 if (sdb_strbuf_string(buf)[i] != expected[i]) {
426                         pos = (int)i;
427                         break;
428                 }
429         }
431         fail_unless(pos == -1,
432                         "sdb_store_tojson(<buf>, %p, %x) returned unexpected result\n"
433                         "         got: %s\n              %*s\n    expected: %s",
434                         filter, flags, sdb_strbuf_string(buf), pos + 1, "^",
435                         expected);
436 } /* verify_json_output */
438 START_TEST(test_store_tojson)
440         sdb_strbuf_t *buf;
441         size_t i;
443         struct {
444                 struct {
445                         sdb_store_matcher_t *(*m)(sdb_store_expr_t *,
446                                         sdb_store_expr_t *);
447                         int field;
448                         sdb_data_t value;
449                 } filter;
450                 int flags;
451                 const char *expected;
452         } golden_data[] = {
453                 { { NULL, 0, SDB_DATA_INIT }, 0,
454                         "["
455                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
456                                         "\"update_interval\": \"0s\", \"backends\": [], "
457                                         "\"attributes\": ["
458                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
459                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
460                                                         "\"update_interval\": \"0s\", \"backends\": []},"
461                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
462                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
463                                                         "\"update_interval\": \"0s\", \"backends\": []},"
464                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
465                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
466                                                         "\"update_interval\": \"0s\", \"backends\": []}"
467                                         "], "
468                                         "\"metrics\": ["
469                                                 "{\"name\": \"m1\", "
470                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
471                                                         "\"update_interval\": \"0s\", \"backends\": [], "
472                                                         "\"attributes\": ["
473                                                                 "{\"name\": \"k3\", \"value\": 42, "
474                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
475                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
476                                                         "]},"
477                                                 "{\"name\": \"m2\", "
478                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
479                                                         "\"update_interval\": \"0s\", \"backends\": [], "
480                                                         "\"attributes\": []}"
481                                         "], "
482                                         "\"services\": []},"
483                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
484                                         "\"update_interval\": \"0s\", \"backends\": [], "
485                                         "\"attributes\": [], "
486                                         "\"metrics\": [], "
487                                         "\"services\": ["
488                                                 "{\"name\": \"s1\", "
489                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
490                                                         "\"update_interval\": \"0s\", \"backends\": [], "
491                                                         "\"attributes\": []},"
492                                                 "{\"name\": \"s2\", "
493                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
494                                                         "\"update_interval\": \"0s\", \"backends\": [], "
495                                                         "\"attributes\": ["
496                                                                 "{\"name\": \"k1\", \"value\": 123, "
497                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
498                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
499                                                                 "{\"name\": \"k2\", \"value\": 4711, "
500                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
501                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
502                                                         "]}"
503                                         "]}"
504                         "]" },
505                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_SERVICES,
506                         "["
507                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
508                                         "\"update_interval\": \"0s\", \"backends\": [], "
509                                         "\"attributes\": ["
510                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
511                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
512                                                         "\"update_interval\": \"0s\", \"backends\": []},"
513                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
514                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
515                                                         "\"update_interval\": \"0s\", \"backends\": []},"
516                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
517                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
518                                                         "\"update_interval\": \"0s\", \"backends\": []}"
519                                         "], "
520                                         "\"metrics\": ["
521                                                 "{\"name\": \"m1\", "
522                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
523                                                         "\"update_interval\": \"0s\", \"backends\": [], "
524                                                         "\"attributes\": ["
525                                                                 "{\"name\": \"k3\", \"value\": 42, "
526                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
527                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
528                                                         "]},"
529                                                 "{\"name\": \"m2\", "
530                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
531                                                         "\"update_interval\": \"0s\", \"backends\": [], "
532                                                         "\"attributes\": []}"
533                                         "]},"
534                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
535                                         "\"update_interval\": \"0s\", \"backends\": [], "
536                                         "\"attributes\": [], "
537                                         "\"metrics\": []}"
538                         "]" },
539                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_METRICS,
540                         "["
541                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
542                                         "\"update_interval\": \"0s\", \"backends\": [], "
543                                         "\"attributes\": ["
544                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
545                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
546                                                         "\"update_interval\": \"0s\", \"backends\": []},"
547                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
548                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
549                                                         "\"update_interval\": \"0s\", \"backends\": []},"
550                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
551                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
552                                                         "\"update_interval\": \"0s\", \"backends\": []}"
553                                         "], "
554                                         "\"services\": []},"
555                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
556                                         "\"update_interval\": \"0s\", \"backends\": [], "
557                                         "\"attributes\": [], "
558                                         "\"services\": ["
559                                                 "{\"name\": \"s1\", "
560                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
561                                                         "\"update_interval\": \"0s\", \"backends\": [], "
562                                                         "\"attributes\": []},"
563                                                 "{\"name\": \"s2\", "
564                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
565                                                         "\"update_interval\": \"0s\", \"backends\": [], "
566                                                         "\"attributes\": ["
567                                                                 "{\"name\": \"k1\", \"value\": 123, "
568                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
569                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
570                                                                 "{\"name\": \"k2\", \"value\": 4711, "
571                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
572                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
573                                                         "]}"
574                                         "]}"
575                         "]" },
576                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ATTRIBUTES,
577                         "["
578                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
579                                         "\"update_interval\": \"0s\", \"backends\": [], "
580                                         "\"metrics\": ["
581                                                 "{\"name\": \"m1\", "
582                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
583                                                         "\"update_interval\": \"0s\", \"backends\": []},"
584                                                 "{\"name\": \"m2\", "
585                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
586                                                         "\"update_interval\": \"0s\", \"backends\": []}"
587                                         "], "
588                                         "\"services\": []},"
589                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
590                                         "\"update_interval\": \"0s\", \"backends\": [], "
591                                         "\"metrics\": [], "
592                                         "\"services\": ["
593                                                 "{\"name\": \"s1\", "
594                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
595                                                         "\"update_interval\": \"0s\", \"backends\": []},"
596                                                 "{\"name\": \"s2\", "
597                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
598                                                         "\"update_interval\": \"0s\", \"backends\": []}"
599                                         "]}"
600                         "]" },
601                 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ALL,
602                         "["
603                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
604                                         "\"update_interval\": \"0s\", \"backends\": []},"
605                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
606                                         "\"update_interval\": \"0s\", \"backends\": []}"
607                         "]" },
608                 { { sdb_store_eq_matcher, SDB_FIELD_NAME,
609                                 { SDB_TYPE_STRING, { .string = "h1" } } }, 0,
610                         "["
611                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
612                                         "\"update_interval\": \"0s\", \"backends\": [], "
613                                         "\"attributes\": [], \"metrics\": [], \"services\": []}"
614                         "]" },
615                 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
616                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
617                         "["
618                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
619                                         "\"update_interval\": \"0s\", \"backends\": [], "
620                                         "\"attributes\": [], "
621                                         "\"metrics\": [], "
622                                         "\"services\": ["
623                                                 "{\"name\": \"s2\", "
624                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
625                                                         "\"update_interval\": \"0s\", \"backends\": [], "
626                                                         "\"attributes\": ["
627                                                                 "{\"name\": \"k1\", \"value\": 123, "
628                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
629                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
630                                                         "]}"
631                                         "]}"
632                         "]" },
633                 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
634                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
635                         "["
636                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
637                                         "\"update_interval\": \"0s\", \"backends\": [], "
638                                         "\"attributes\": ["
639                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
640                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
641                                                         "\"update_interval\": \"0s\", \"backends\": []},"
642                                         "], "
643                                         "\"metrics\": ["
644                                                 "{\"name\": \"m2\", "
645                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
646                                                         "\"update_interval\": \"0s\", \"backends\": [], "
647                                                         "\"attributes\": []}"
648                                         "], "
649                                         "\"services\": []}"
650                         "]" },
651                 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
652                                 { SDB_TYPE_DATETIME, { .datetime = 3 } } }, 0,
653                         "["
654                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
655                                         "\"update_interval\": \"0s\", \"backends\": [], "
656                                         "\"attributes\": [], "
657                                         "\"metrics\": [], "
658                                         "\"services\": []}"
659                         "]" },
660         };
662         buf = sdb_strbuf_create(0);
663         fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
664         populate();
666         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
667                 sdb_store_matcher_t *filter = NULL;
668                 int status;
670                 sdb_strbuf_clear(buf);
672                 if (golden_data[i].filter.m) {
673                         sdb_store_expr_t *field;
674                         sdb_store_expr_t *value;
676                         field = sdb_store_expr_fieldvalue(golden_data[i].filter.field);
677                         fail_unless(field != NULL,
678                                         "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
679                         value = sdb_store_expr_constvalue(&golden_data[i].filter.value);
680                         fail_unless(value != NULL,
681                                         "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
683                         filter = golden_data[i].filter.m(field, value);
684                         fail_unless(filter != NULL,
685                                         "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
687                         sdb_object_deref(SDB_OBJ(field));
688                         sdb_object_deref(SDB_OBJ(value));
689                 }
691                 status = sdb_store_tojson(buf, filter, golden_data[i].flags);
692                 fail_unless(status == 0,
693                                 "sdb_store_tojson(<buf>, %p, %x) = %d; expected: 0",
694                                 filter, golden_data[i].flags, status);
696                 verify_json_output(buf, golden_data[i].expected,
697                                 filter, golden_data[i].flags);
698                 sdb_object_deref(SDB_OBJ(filter));
699         }
700         sdb_strbuf_destroy(buf);
702 END_TEST
704 START_TEST(test_get_field)
706         sdb_store_obj_t *host;
707         sdb_data_t value = SDB_DATA_INIT;
708         int check;
710         sdb_store_host("host", 10);
711         sdb_store_host("host", 20);
713         host = sdb_store_get_host("host");
714         fail_unless(host != NULL,
715                         "INTERNAL ERROR: store doesn't have host after adding it");
717         check = sdb_store_get_field(NULL, 0, NULL);
718         fail_unless(check < 0,
719                         "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
720         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
721         fail_unless(check < 0,
722                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
723                         "expected: <0");
724         check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
725         fail_unless(check < 0,
726                         "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
727                         "expected: <0");
729         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
730         fail_unless(check == 0,
731                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
732                         "expected: 0");
733         /* 'name' is dynamically allocated; make sure it's not leaked even
734          * if there is no result parameter */
735         check = sdb_store_get_field(host, SDB_FIELD_NAME, NULL);
736         fail_unless(check == 0,
737                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
738                         "expected: 0");
740         check = sdb_store_get_field(host, SDB_FIELD_NAME, &value);
741         fail_unless(check == 0,
742                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) = "
743                         "%d; expected: 0");
744         fail_unless((value.type == SDB_TYPE_STRING)
745                         && (! strcmp(value.data.string, "host")),
746                         "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) "
747                         "returned value {%d, %s}; expected {%d, host}",
748                         value.type, value.data.string, SDB_TYPE_STRING);
749         sdb_data_free_datum(&value);
751         check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
752         fail_unless(check == 0,
753                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
754                         "%d; expected: 0");
755         fail_unless((value.type == SDB_TYPE_DATETIME)
756                         && (value.data.datetime == 20),
757                         "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
758                         "returned value {%d, %lu}; expected {%d, 20}",
759                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
761         check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
762         fail_unless(check == 0,
763                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
764                         "%d; expected: 0");
765         /* let's assume we're at least in year 1980 ;-) */
766         fail_unless((value.type == SDB_TYPE_DATETIME)
767                         && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
768                         "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
769                         "returned value {%d, %lu}; expected {%d, >%lu}",
770                         value.type, value.data.datetime,
771                         SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
773         check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
774         fail_unless(check == 0,
775                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
776                         "%d; expected: 0");
777         fail_unless((value.type == SDB_TYPE_DATETIME)
778                         && (value.data.datetime == 10),
779                         "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
780                         "returned value {%d, %lu}; expected {%d, 10}",
781                         value.type, value.data.datetime, SDB_TYPE_DATETIME);
783         check = sdb_store_get_field(host, SDB_FIELD_BACKEND, &value);
784         fail_unless(check == 0,
785                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) = "
786                         "%d; expected: 0");
787         /* there are no backends in this test */
788         fail_unless((value.type == (SDB_TYPE_ARRAY | SDB_TYPE_STRING))
789                         && (value.data.array.length == 0)
790                         && (value.data.array.values == NULL),
791                         "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) "
792                         "returned value {%d, %lu, %p}; expected {%d, 0, NULL}",
793                         value.type, value.data.array.length, value.data.array.values,
794                         SDB_TYPE_ARRAY | SDB_TYPE_STRING);
796 END_TEST
798 START_TEST(test_interval)
800         sdb_store_obj_t *host;
802         /* 10 us interval */
803         sdb_store_host("host", 10);
804         sdb_store_host("host", 20);
805         sdb_store_host("host", 30);
806         sdb_store_host("host", 40);
808         host = sdb_store_get_host("host");
809         fail_unless(host != NULL,
810                         "INTERNAL ERROR: store doesn't have host after adding it");
812         fail_unless(host->interval == 10,
813                         "sdb_store_host() did not calculate interval correctly: "
814                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
816         /* multiple updates for the same timestamp don't modify the interval */
817         sdb_store_host("host", 40);
818         sdb_store_host("host", 40);
819         sdb_store_host("host", 40);
820         sdb_store_host("host", 40);
822         fail_unless(host->interval == 10,
823                         "sdb_store_host() changed interval when doing multiple updates "
824                         "using the same timestamp; got: %"PRIsdbTIME"; "
825                         "expected: %"PRIsdbTIME, host->interval, 10);
827         /* multiple updates using an timestamp don't modify the interval */
828         sdb_store_host("host", 20);
829         sdb_store_host("host", 20);
830         sdb_store_host("host", 20);
831         sdb_store_host("host", 20);
833         fail_unless(host->interval == 10,
834                         "sdb_store_host() changed interval when doing multiple updates "
835                         "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
836                         host->interval, 10);
838         /* new interval: 20 us */
839         sdb_store_host("host", 60);
840         fail_unless(host->interval == 11,
841                         "sdb_store_host() did not calculate interval correctly: "
842                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
844         /* new interval: 40 us */
845         sdb_store_host("host", 100);
846         fail_unless(host->interval == 13,
847                         "sdb_store_host() did not calculate interval correctly: "
848                         "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
850         sdb_object_deref(SDB_OBJ(host));
852 END_TEST
854 static int
855 scan_incr(sdb_store_obj_t *obj, void *user_data)
857         intptr_t *i = user_data;
859         fail_unless(obj != NULL,
860                         "sdb_store_scan callback received NULL obj; expected: "
861                         "<store base obj>");
862         fail_unless(i != NULL,
863                         "sdb_store_scan callback received NULL user_data; "
864                         "expected: <pointer to data>");
866         ++(*i);
867         return 0;
868 } /* scan_incr */
870 static int
871 scan_error(sdb_store_obj_t *obj, void *user_data)
873         intptr_t *i = user_data;
875         fail_unless(obj != NULL,
876                         "sdb_store_scan callback received NULL obj; expected: "
877                         "<store base obj>");
878         fail_unless(i != NULL,
879                         "sdb_store_scan callback received NULL user_data; "
880                         "expected: <pointer to data>");
882         ++(*i);
883         return -1;
884 } /* scan_error */
886 START_TEST(test_scan)
888         intptr_t i = 0;
889         int check;
891         /* empty store */
892         check = sdb_store_scan(/* m, filter = */ NULL, NULL, scan_incr, &i);
893         fail_unless(check == -1,
894                         "sdb_store_scan(), empty store = %d; expected: -1", check);
895         fail_unless(i == 0,
896                         "sdb_store_scan called callback %d times; expected: 0", (int)i);
898         populate();
900         check = sdb_store_scan(/* m, filter = */ NULL, NULL, scan_incr, &i);
901         fail_unless(check == 0,
902                         "sdb_store_scan() = %d; expected: 0", check);
903         fail_unless(i == 2,
904                         "sdb_store_scan called callback %d times; expected: 1", (int)i);
906         i = 0;
907         check = sdb_store_scan(/* m, filter = */ NULL, NULL, scan_error, &i);
908         fail_unless(check == -1,
909                         "sdb_store_scan(), error callback = %d; expected: -1", check);
910         fail_unless(i == 1,
911                         "sdb_store_scan called callback %d times "
912                         "(callback returned error); expected: 1", (int)i);
914 END_TEST
916 Suite *
917 core_store_suite(void)
919         Suite *s = suite_create("core::store");
920         TCase *tc;
922         tc = tcase_create("core");
923         tcase_add_test(tc, test_store_tojson);
924         tcase_add_test(tc, test_store_host);
925         tcase_add_test(tc, test_store_get_host);
926         tcase_add_test(tc, test_store_attr);
927         tcase_add_test(tc, test_store_metric);
928         tcase_add_test(tc, test_store_metric_attr);
929         tcase_add_test(tc, test_store_service);
930         tcase_add_test(tc, test_store_service_attr);
931         tcase_add_test(tc, test_get_field);
932         tcase_add_test(tc, test_interval);
933         tcase_add_test(tc, test_scan);
934         tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
935         suite_add_tcase(s, tc);
937         return s;
938 } /* core_store_suite */
940 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */