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 }
124 }
125 END_TEST
127 START_TEST(test_store_get_host)
128 {
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 }
185 }
186 END_TEST
188 START_TEST(test_store_attr)
189 {
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 }
227 }
228 END_TEST
230 START_TEST(test_store_metric)
231 {
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 }
276 }
277 END_TEST
279 START_TEST(test_store_metric_attr)
280 {
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 }
324 }
325 END_TEST
327 START_TEST(test_store_service)
328 {
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 }
359 }
360 END_TEST
362 START_TEST(test_store_service_attr)
363 {
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 }
407 }
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)
413 {
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)
440 {
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);
716 }
717 END_TEST
719 START_TEST(test_get_field)
720 {
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);
810 }
811 END_TEST
813 START_TEST(test_interval)
814 {
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));
866 }
867 END_TEST
869 static int
870 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
871 {
872 intptr_t *i = user_data;
874 if (! sdb_store_matcher_matches(filter, obj, NULL))
875 return 0;
877 fail_unless(obj != NULL,
878 "sdb_store_scan callback received NULL obj; expected: "
879 "<store base obj>");
880 fail_unless(i != NULL,
881 "sdb_store_scan callback received NULL user_data; "
882 "expected: <pointer to data>");
884 ++(*i);
885 return 0;
886 } /* scan_count */
888 static int
889 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
890 {
891 intptr_t *i = user_data;
893 if (! sdb_store_matcher_matches(filter, obj, NULL))
894 return 0;
896 fail_unless(obj != NULL,
897 "sdb_store_scan callback received NULL obj; expected: "
898 "<store base obj>");
899 fail_unless(i != NULL,
900 "sdb_store_scan callback received NULL user_data; "
901 "expected: <pointer to data>");
903 ++(*i);
904 return -1;
905 } /* scan_error */
907 START_TEST(test_scan)
908 {
909 intptr_t i = 0;
910 int check;
912 /* empty store */
913 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
914 scan_count, &i);
915 fail_unless(check == -1,
916 "sdb_store_scan(HOST), empty store = %d; expected: -1", check);
917 fail_unless(i == 0,
918 "sdb_store_scan(HOST) called callback %d times; "
919 "expected: 0", (int)i);
921 populate();
923 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
924 scan_count, &i);
925 fail_unless(check == 0,
926 "sdb_store_scan(HOST) = %d; expected: 0", check);
927 fail_unless(i == 2,
928 "sdb_store_scan(HOST) called callback %d times; "
929 "expected: 1", (int)i);
931 i = 0;
932 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
933 scan_error, &i);
934 fail_unless(check == -1,
935 "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
936 fail_unless(i == 1,
937 "sdb_store_scan(HOST) called callback %d times "
938 "(callback returned error); expected: 1", (int)i);
940 i = 0;
941 check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
942 scan_count, &i);
943 fail_unless(check == 0,
944 "sdb_store_scan(SERVICE) = %d; expected: 0", check);
945 fail_unless(i == 2,
946 "sdb_store_scan(SERVICE) called callback %d times; "
947 "expected: 2", (int)i);
949 i = 0;
950 check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
951 scan_count, &i);
952 fail_unless(check == 0,
953 "sdb_store_scan(METRIC) = %d; expected: 0", check);
954 fail_unless(i == 3,
955 "sdb_store_scan(METRIC) called callback %d times; "
956 "expected: 3", (int)i);
957 }
958 END_TEST
960 Suite *
961 core_store_suite(void)
962 {
963 Suite *s = suite_create("core::store");
964 TCase *tc;
966 tc = tcase_create("core");
967 tcase_add_test(tc, test_store_tojson);
968 tcase_add_test(tc, test_store_host);
969 tcase_add_test(tc, test_store_get_host);
970 tcase_add_test(tc, test_store_attr);
971 tcase_add_test(tc, test_store_metric);
972 tcase_add_test(tc, test_store_metric_attr);
973 tcase_add_test(tc, test_store_service);
974 tcase_add_test(tc, test_store_service_attr);
975 tcase_add_test(tc, test_get_field);
976 tcase_add_test(tc, test_interval);
977 tcase_add_test(tc, test_scan);
978 tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
979 suite_add_tcase(s, tc);
981 return s;
982 } /* core_store_suite */
984 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */