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 }
123 }
124 END_TEST
126 START_TEST(test_store_get_host)
127 {
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 }
184 }
185 END_TEST
187 START_TEST(test_store_attr)
188 {
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 }
226 }
227 END_TEST
229 START_TEST(test_store_metric)
230 {
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 }
275 }
276 END_TEST
278 START_TEST(test_store_metric_attr)
279 {
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 }
323 }
324 END_TEST
326 START_TEST(test_store_service)
327 {
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 }
358 }
359 END_TEST
361 START_TEST(test_store_service_attr)
362 {
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 }
406 }
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)
412 {
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)
439 {
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);
701 }
702 END_TEST
704 START_TEST(test_get_field)
705 {
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);
795 }
796 END_TEST
798 START_TEST(test_interval)
799 {
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));
851 }
852 END_TEST
854 static int
855 iter_incr(sdb_store_obj_t *obj, void *user_data)
856 {
857 intptr_t *i = user_data;
859 fail_unless(obj != NULL,
860 "sdb_store_iterate callback received NULL obj; expected: "
861 "<store base obj>");
862 fail_unless(i != NULL,
863 "sdb_store_iterate callback received NULL user_data; "
864 "expected: <pointer to data>");
866 ++(*i);
867 return 0;
868 } /* iter_incr */
870 static int
871 iter_error(sdb_store_obj_t *obj, void *user_data)
872 {
873 intptr_t *i = user_data;
875 fail_unless(obj != NULL,
876 "sdb_store_iterate callback received NULL obj; expected: "
877 "<store base obj>");
878 fail_unless(i != NULL,
879 "sdb_store_iterate callback received NULL user_data; "
880 "expected: <pointer to data>");
882 ++(*i);
883 return -1;
884 } /* iter_error */
886 START_TEST(test_iterate)
887 {
888 intptr_t i = 0;
889 int check;
891 /* empty store */
892 check = sdb_store_iterate(iter_incr, &i);
893 fail_unless(check == -1,
894 "sdb_store_iterate(), empty store = %d; expected: -1", check);
895 fail_unless(i == 0,
896 "sdb_store_iterate called callback %d times; expected: 0", (int)i);
898 populate();
900 check = sdb_store_iterate(iter_incr, &i);
901 fail_unless(check == 0,
902 "sdb_store_iterate() = %d; expected: 0", check);
903 fail_unless(i == 2,
904 "sdb_store_iterate called callback %d times; expected: 1", (int)i);
906 i = 0;
907 check = sdb_store_iterate(iter_error, &i);
908 fail_unless(check == -1,
909 "sdb_store_iterate(), error callback = %d; expected: -1", check);
910 fail_unless(i == 1,
911 "sdb_store_iterate called callback %d times "
912 "(callback returned error); expected: 1", (int)i);
913 }
914 END_TEST
916 Suite *
917 core_store_suite(void)
918 {
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_iterate);
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 : */