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", 2);
57 sdb_store_metric("h1", "m2", 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 struct {
232 const char *host;
233 const char *metric;
234 sdb_time_t last_update;
235 int expected;
236 } golden_data[] = {
237 { "k", "m", 1, -1 },
238 { "k", "m", 1, -1 }, /* retry to ensure the host is not created */
239 { "l", "m1", 1, 0 },
240 { "l", "m1", 2, 0 },
241 { "l", "m1", 2, 1 },
242 { "l", "m2", 1, 0 },
243 { "m", "m", 1, 0 },
244 { "m", "m", 1, 1 },
245 };
247 size_t i;
249 sdb_store_host("m", 1);
250 sdb_store_host("l", 1);
251 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
252 int status;
254 status = sdb_store_metric(golden_data[i].host,
255 golden_data[i].metric, golden_data[i].last_update);
256 fail_unless(status == golden_data[i].expected,
257 "sdb_store_metric(%s, %s, %d) = %d; expected: %d",
258 golden_data[i].host, golden_data[i].metric,
259 golden_data[i].last_update, status, golden_data[i].expected);
260 }
261 }
262 END_TEST
264 START_TEST(test_store_metric_attr)
265 {
266 struct {
267 const char *host;
268 const char *metric;
269 const char *attr;
270 const sdb_data_t value;
271 sdb_time_t last_update;
272 int expected;
273 } golden_data[] = {
274 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
275 /* retry, it should still fail */
276 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
277 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
278 /* retry, it should still fail */
279 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
280 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
281 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
282 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
283 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
284 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
285 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
286 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
287 };
289 size_t i;
291 sdb_store_host("m", 1);
292 sdb_store_host("l", 1);
293 sdb_store_metric("m", "m1", 1);
294 sdb_store_metric("l", "m1", 1);
295 sdb_store_metric("l", "m2", 1);
297 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
298 int status;
300 status = sdb_store_metric_attr(golden_data[i].host,
301 golden_data[i].metric, golden_data[i].attr,
302 &golden_data[i].value, golden_data[i].last_update);
303 fail_unless(status == golden_data[i].expected,
304 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
305 "expected: %d", golden_data[i].host, golden_data[i].metric,
306 golden_data[i].attr, golden_data[i].value.data.integer,
307 golden_data[i].last_update, status, golden_data[i].expected);
308 }
309 }
310 END_TEST
312 START_TEST(test_store_service)
313 {
314 struct {
315 const char *host;
316 const char *svc;
317 sdb_time_t last_update;
318 int expected;
319 } golden_data[] = {
320 { "k", "s", 1, -1 },
321 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
322 { "l", "s1", 1, 0 },
323 { "l", "s1", 2, 0 },
324 { "l", "s1", 2, 1 },
325 { "l", "s2", 1, 0 },
326 { "m", "s", 1, 0 },
327 { "m", "s", 1, 1 },
328 };
330 size_t i;
332 sdb_store_host("m", 1);
333 sdb_store_host("l", 1);
334 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
335 int status;
337 status = sdb_store_service(golden_data[i].host,
338 golden_data[i].svc, golden_data[i].last_update);
339 fail_unless(status == golden_data[i].expected,
340 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
341 golden_data[i].host, golden_data[i].svc,
342 golden_data[i].last_update, status, golden_data[i].expected);
343 }
344 }
345 END_TEST
347 START_TEST(test_store_service_attr)
348 {
349 struct {
350 const char *host;
351 const char *svc;
352 const char *attr;
353 const sdb_data_t value;
354 sdb_time_t last_update;
355 int expected;
356 } golden_data[] = {
357 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
358 /* retry, it should still fail */
359 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
360 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
361 /* retry, it should still fail */
362 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
363 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
364 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
365 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
366 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
367 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
368 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
369 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
370 };
372 size_t i;
374 sdb_store_host("m", 1);
375 sdb_store_host("l", 1);
376 sdb_store_service("m", "s1", 1);
377 sdb_store_service("l", "s1", 1);
378 sdb_store_service("l", "s2", 1);
380 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
381 int status;
383 status = sdb_store_service_attr(golden_data[i].host,
384 golden_data[i].svc, golden_data[i].attr,
385 &golden_data[i].value, golden_data[i].last_update);
386 fail_unless(status == golden_data[i].expected,
387 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
388 "expected: %d", golden_data[i].host, golden_data[i].svc,
389 golden_data[i].attr, golden_data[i].value.data.integer,
390 golden_data[i].last_update, status, golden_data[i].expected);
391 }
392 }
393 END_TEST
395 static void
396 verify_json_output(sdb_strbuf_t *buf, const char *expected,
397 const char *filter_str, int flags)
398 {
399 int pos;
400 size_t len1, len2;
401 size_t i;
403 len1 = strlen(sdb_strbuf_string(buf));
404 len2 = strlen(expected);
406 pos = -1;
407 if (len1 != len2)
408 pos = (int)(len1 <= len2 ? len1 : len2);
410 for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
411 if (sdb_strbuf_string(buf)[i] != expected[i]) {
412 pos = (int)i;
413 break;
414 }
415 }
417 fail_unless(pos == -1,
418 "sdb_store_tojson(<buf>, %s, %x) returned unexpected result\n"
419 " got: %s\n %*s\n expected: %s",
420 filter_str, flags, sdb_strbuf_string(buf), pos + 1, "^",
421 expected);
422 } /* verify_json_output */
424 START_TEST(test_store_tojson)
425 {
426 sdb_strbuf_t *buf;
427 size_t i;
429 struct {
430 struct {
431 sdb_store_matcher_t *(*m)(sdb_store_cond_t *);
432 int field;
433 sdb_data_t value;
434 } filter;
435 int flags;
436 const char *expected;
437 } golden_data[] = {
438 { { NULL, 0, SDB_DATA_INIT }, 0,
439 "{\"hosts\":["
440 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
441 "\"update_interval\": \"0s\", \"backends\": [], "
442 "\"attributes\": ["
443 "{\"name\": \"k1\", \"value\": \"v1\", "
444 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
445 "\"update_interval\": \"0s\", \"backends\": []},"
446 "{\"name\": \"k2\", \"value\": \"v2\", "
447 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
448 "\"update_interval\": \"0s\", \"backends\": []},"
449 "{\"name\": \"k3\", \"value\": \"v3\", "
450 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
451 "\"update_interval\": \"0s\", \"backends\": []}"
452 "], "
453 "\"metrics\": ["
454 "{\"name\": \"m1\", "
455 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
456 "\"update_interval\": \"0s\", \"backends\": [], "
457 "\"attributes\": ["
458 "{\"name\": \"k3\", \"value\": 42, "
459 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
460 "\"update_interval\": \"0s\", \"backends\": []}"
461 "]},"
462 "{\"name\": \"m2\", "
463 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
464 "\"update_interval\": \"0s\", \"backends\": [], "
465 "\"attributes\": []}"
466 "], "
467 "\"services\": []},"
468 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
469 "\"update_interval\": \"0s\", \"backends\": [], "
470 "\"attributes\": [], "
471 "\"metrics\": [], "
472 "\"services\": ["
473 "{\"name\": \"s1\", "
474 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
475 "\"update_interval\": \"0s\", \"backends\": [], "
476 "\"attributes\": []},"
477 "{\"name\": \"s2\", "
478 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
479 "\"update_interval\": \"0s\", \"backends\": [], "
480 "\"attributes\": ["
481 "{\"name\": \"k1\", \"value\": 123, "
482 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
483 "\"update_interval\": \"0s\", \"backends\": []},"
484 "{\"name\": \"k2\", \"value\": 4711, "
485 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
486 "\"update_interval\": \"0s\", \"backends\": []}"
487 "]}"
488 "]}"
489 "]}" },
490 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_SERVICES,
491 "{\"hosts\":["
492 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
493 "\"update_interval\": \"0s\", \"backends\": [], "
494 "\"attributes\": ["
495 "{\"name\": \"k1\", \"value\": \"v1\", "
496 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
497 "\"update_interval\": \"0s\", \"backends\": []},"
498 "{\"name\": \"k2\", \"value\": \"v2\", "
499 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
500 "\"update_interval\": \"0s\", \"backends\": []},"
501 "{\"name\": \"k3\", \"value\": \"v3\", "
502 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
503 "\"update_interval\": \"0s\", \"backends\": []}"
504 "], "
505 "\"metrics\": ["
506 "{\"name\": \"m1\", "
507 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
508 "\"update_interval\": \"0s\", \"backends\": [], "
509 "\"attributes\": ["
510 "{\"name\": \"k3\", \"value\": 42, "
511 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
512 "\"update_interval\": \"0s\", \"backends\": []}"
513 "]},"
514 "{\"name\": \"m2\", "
515 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
516 "\"update_interval\": \"0s\", \"backends\": [], "
517 "\"attributes\": []}"
518 "]},"
519 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
520 "\"update_interval\": \"0s\", \"backends\": [], "
521 "\"attributes\": [], "
522 "\"metrics\": []}"
523 "]}" },
524 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_METRICS,
525 "{\"hosts\":["
526 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
527 "\"update_interval\": \"0s\", \"backends\": [], "
528 "\"attributes\": ["
529 "{\"name\": \"k1\", \"value\": \"v1\", "
530 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
531 "\"update_interval\": \"0s\", \"backends\": []},"
532 "{\"name\": \"k2\", \"value\": \"v2\", "
533 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
534 "\"update_interval\": \"0s\", \"backends\": []},"
535 "{\"name\": \"k3\", \"value\": \"v3\", "
536 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
537 "\"update_interval\": \"0s\", \"backends\": []}"
538 "], "
539 "\"services\": []},"
540 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
541 "\"update_interval\": \"0s\", \"backends\": [], "
542 "\"attributes\": [], "
543 "\"services\": ["
544 "{\"name\": \"s1\", "
545 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
546 "\"update_interval\": \"0s\", \"backends\": [], "
547 "\"attributes\": []},"
548 "{\"name\": \"s2\", "
549 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
550 "\"update_interval\": \"0s\", \"backends\": [], "
551 "\"attributes\": ["
552 "{\"name\": \"k1\", \"value\": 123, "
553 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
554 "\"update_interval\": \"0s\", \"backends\": []},"
555 "{\"name\": \"k2\", \"value\": 4711, "
556 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
557 "\"update_interval\": \"0s\", \"backends\": []}"
558 "]}"
559 "]}"
560 "]}" },
561 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ATTRIBUTES,
562 "{\"hosts\":["
563 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
564 "\"update_interval\": \"0s\", \"backends\": [], "
565 "\"metrics\": ["
566 "{\"name\": \"m1\", "
567 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
568 "\"update_interval\": \"0s\", \"backends\": []},"
569 "{\"name\": \"m2\", "
570 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
571 "\"update_interval\": \"0s\", \"backends\": []}"
572 "], "
573 "\"services\": []},"
574 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
575 "\"update_interval\": \"0s\", \"backends\": [], "
576 "\"metrics\": [], "
577 "\"services\": ["
578 "{\"name\": \"s1\", "
579 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
580 "\"update_interval\": \"0s\", \"backends\": []},"
581 "{\"name\": \"s2\", "
582 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
583 "\"update_interval\": \"0s\", \"backends\": []}"
584 "]}"
585 "]}" },
586 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ALL,
587 "{\"hosts\":["
588 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
589 "\"update_interval\": \"0s\", \"backends\": []},"
590 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
591 "\"update_interval\": \"0s\", \"backends\": []}"
592 "]}" },
593 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
594 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
595 "{\"hosts\":["
596 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
597 "\"update_interval\": \"0s\", \"backends\": [], "
598 "\"attributes\": [], "
599 "\"metrics\": [], "
600 "\"services\": ["
601 "{\"name\": \"s2\", "
602 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
603 "\"update_interval\": \"0s\", \"backends\": [], "
604 "\"attributes\": ["
605 "{\"name\": \"k1\", \"value\": 123, "
606 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
607 "\"update_interval\": \"0s\", \"backends\": []},"
608 "]}"
609 "]}"
610 "]}" },
611 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
612 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
613 "{\"hosts\":["
614 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
615 "\"update_interval\": \"0s\", \"backends\": [], "
616 "\"attributes\": ["
617 "{\"name\": \"k1\", \"value\": \"v1\", "
618 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
619 "\"update_interval\": \"0s\", \"backends\": []},"
620 "], "
621 "\"metrics\": ["
622 "{\"name\": \"m2\", "
623 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
624 "\"update_interval\": \"0s\", \"backends\": [], "
625 "\"attributes\": []}"
626 "], "
627 "\"services\": []}"
628 "]}" },
629 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
630 { SDB_TYPE_DATETIME, { .datetime = 3 } } }, 0,
631 "{\"hosts\":["
632 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
633 "\"update_interval\": \"0s\", \"backends\": [], "
634 "\"attributes\": [], "
635 "\"metrics\": [], "
636 "\"services\": []}"
637 "]}" },
638 };
640 buf = sdb_strbuf_create(0);
641 fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
642 populate();
644 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
645 sdb_store_matcher_t *filter = NULL;
646 char filter_str[1024] = "<none>";
647 int status;
649 sdb_strbuf_clear(buf);
651 if (golden_data[i].filter.m) {
652 sdb_store_expr_t *expr;
653 sdb_store_cond_t *c = NULL;
655 expr = sdb_store_expr_constvalue(&golden_data[i].filter.value);
656 fail_unless(expr != NULL,
657 "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
658 c = sdb_store_obj_cond(golden_data[i].filter.field, expr);
659 sdb_object_deref(SDB_OBJ(expr));
660 fail_unless(c != NULL,
661 "INTERNAL ERROR: sdb_store_obj_cond() = NULL");
662 filter = golden_data[i].filter.m(c);
663 sdb_object_deref(SDB_OBJ(c));
664 fail_unless(filter != NULL,
665 "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
667 if (sdb_store_matcher_tostring(filter,
668 filter_str, sizeof(filter_str)))
669 snprintf(filter_str, sizeof(filter_str), "ERR");
670 }
672 status = sdb_store_tojson(buf, filter, golden_data[i].flags);
673 fail_unless(status == 0,
674 "sdb_store_tojson(<buf>, %s, %x) = %d; expected: 0",
675 filter_str, golden_data[i].flags, status);
677 verify_json_output(buf, golden_data[i].expected,
678 filter_str, golden_data[i].flags);
679 sdb_object_deref(SDB_OBJ(filter));
680 }
681 sdb_strbuf_destroy(buf);
682 }
683 END_TEST
685 START_TEST(test_get_field)
686 {
687 sdb_store_obj_t *host;
688 sdb_data_t value = SDB_DATA_INIT;
689 int check;
691 sdb_store_host("host", 10);
692 sdb_store_host("host", 20);
694 host = sdb_store_get_host("host");
695 fail_unless(host != NULL,
696 "INTERNAL ERROR: store doesn't have host after adding it");
698 check = sdb_store_get_field(NULL, 0, NULL);
699 fail_unless(check < 0,
700 "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
701 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
702 fail_unless(check < 0,
703 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
704 "expected: <0");
705 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
706 fail_unless(check < 0,
707 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
708 "expected: <0");
709 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
710 fail_unless(check < 0,
711 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
712 "expected: <0");
714 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
715 fail_unless(check == 0,
716 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
717 "%d; expected: 0");
718 fail_unless((value.type == SDB_TYPE_DATETIME)
719 && (value.data.datetime == 20),
720 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
721 "returned value {%d, %lu}; expected {%d, 20}",
722 value.type, value.data.datetime, SDB_TYPE_DATETIME);
724 check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
725 fail_unless(check == 0,
726 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
727 "%d; expected: 0");
728 /* let's assume we're at least in year 1980 ;-) */
729 fail_unless((value.type == SDB_TYPE_DATETIME)
730 && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
731 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
732 "returned value {%d, %lu}; expected {%d, >%lu}",
733 value.type, value.data.datetime,
734 SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
736 check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
737 fail_unless(check == 0,
738 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
739 "%d; expected: 0");
740 fail_unless((value.type == SDB_TYPE_DATETIME)
741 && (value.data.datetime == 10),
742 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
743 "returned value {%d, %lu}; expected {%d, 10}",
744 value.type, value.data.datetime, SDB_TYPE_DATETIME);
745 }
746 END_TEST
748 START_TEST(test_interval)
749 {
750 sdb_store_obj_t *host;
752 /* 10 us interval */
753 sdb_store_host("host", 10);
754 sdb_store_host("host", 20);
755 sdb_store_host("host", 30);
756 sdb_store_host("host", 40);
758 host = sdb_store_get_host("host");
759 fail_unless(host != NULL,
760 "INTERNAL ERROR: store doesn't have host after adding it");
762 fail_unless(host->interval == 10,
763 "sdb_store_host() did not calculate interval correctly: "
764 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
766 /* multiple updates for the same timestamp don't modify the interval */
767 sdb_store_host("host", 40);
768 sdb_store_host("host", 40);
769 sdb_store_host("host", 40);
770 sdb_store_host("host", 40);
772 fail_unless(host->interval == 10,
773 "sdb_store_host() changed interval when doing multiple updates "
774 "using the same timestamp; got: %"PRIsdbTIME"; "
775 "expected: %"PRIsdbTIME, host->interval, 10);
777 /* multiple updates using an timestamp don't modify the interval */
778 sdb_store_host("host", 20);
779 sdb_store_host("host", 20);
780 sdb_store_host("host", 20);
781 sdb_store_host("host", 20);
783 fail_unless(host->interval == 10,
784 "sdb_store_host() changed interval when doing multiple updates "
785 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
786 host->interval, 10);
788 /* new interval: 20 us */
789 sdb_store_host("host", 60);
790 fail_unless(host->interval == 11,
791 "sdb_store_host() did not calculate interval correctly: "
792 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
794 /* new interval: 40 us */
795 sdb_store_host("host", 100);
796 fail_unless(host->interval == 13,
797 "sdb_store_host() did not calculate interval correctly: "
798 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
800 sdb_object_deref(SDB_OBJ(host));
801 }
802 END_TEST
804 static int
805 iter_incr(sdb_store_obj_t *obj, void *user_data)
806 {
807 intptr_t *i = user_data;
809 fail_unless(obj != NULL,
810 "sdb_store_iterate callback received NULL obj; expected: "
811 "<store base obj>");
812 fail_unless(i != NULL,
813 "sdb_store_iterate callback received NULL user_data; "
814 "expected: <pointer to data>");
816 ++(*i);
817 return 0;
818 } /* iter_incr */
820 static int
821 iter_error(sdb_store_obj_t *obj, void *user_data)
822 {
823 intptr_t *i = user_data;
825 fail_unless(obj != NULL,
826 "sdb_store_iterate callback received NULL obj; expected: "
827 "<store base obj>");
828 fail_unless(i != NULL,
829 "sdb_store_iterate callback received NULL user_data; "
830 "expected: <pointer to data>");
832 ++(*i);
833 return -1;
834 } /* iter_error */
836 START_TEST(test_iterate)
837 {
838 intptr_t i = 0;
839 int check;
841 /* empty store */
842 check = sdb_store_iterate(iter_incr, &i);
843 fail_unless(check == -1,
844 "sdb_store_iterate(), empty store = %d; expected: -1", check);
845 fail_unless(i == 0,
846 "sdb_store_iterate called callback %d times; expected: 0", (int)i);
848 populate();
850 check = sdb_store_iterate(iter_incr, &i);
851 fail_unless(check == 0,
852 "sdb_store_iterate() = %d; expected: 0", check);
853 fail_unless(i == 2,
854 "sdb_store_iterate called callback %d times; expected: 1", (int)i);
856 i = 0;
857 check = sdb_store_iterate(iter_error, &i);
858 fail_unless(check == -1,
859 "sdb_store_iterate(), error callback = %d; expected: -1", check);
860 fail_unless(i == 1,
861 "sdb_store_iterate called callback %d times "
862 "(callback returned error); expected: 1", (int)i);
863 }
864 END_TEST
866 Suite *
867 core_store_suite(void)
868 {
869 Suite *s = suite_create("core::store");
870 TCase *tc;
872 tc = tcase_create("core");
873 tcase_add_test(tc, test_store_tojson);
874 tcase_add_test(tc, test_store_host);
875 tcase_add_test(tc, test_store_get_host);
876 tcase_add_test(tc, test_store_attr);
877 tcase_add_test(tc, test_store_metric);
878 tcase_add_test(tc, test_store_metric_attr);
879 tcase_add_test(tc, test_store_service);
880 tcase_add_test(tc, test_store_service_attr);
881 tcase_add_test(tc, test_get_field);
882 tcase_add_test(tc, test_interval);
883 tcase_add_test(tc, test_iterate);
884 tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
885 suite_add_tcase(s, tc);
887 return s;
888 } /* core_store_suite */
890 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */