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_service("h2", "s1", 1);
57 sdb_store_service("h2", "s2", 2);
59 datum.type = SDB_TYPE_INTEGER;
60 datum.data.integer = 123;
61 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
62 datum.data.integer = 4711;
63 sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
65 /* don't overwrite k1 */
66 datum.data.integer = 666;
67 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
68 } /* populate */
70 START_TEST(test_store_host)
71 {
72 struct {
73 const char *name;
74 sdb_time_t last_update;
75 int expected;
76 } golden_data[] = {
77 { "a", 1, 0 },
78 { "a", 2, 0 },
79 { "a", 1, 1 },
80 { "b", 1, 0 },
81 { "b", 1, 1 },
82 { "A", 1, 1 }, /* case-insensitive */
83 { "A", 3, 0 },
84 };
86 struct {
87 const char *name;
88 _Bool has;
89 } golden_hosts[] = {
90 { "a", 1 == 1 },
91 { "b", 1 == 1 },
92 { "c", 0 == 1 },
93 { "A", 1 == 1 },
94 };
96 size_t i;
98 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
99 int status;
101 status = sdb_store_host(golden_data[i].name,
102 golden_data[i].last_update);
103 fail_unless(status == golden_data[i].expected,
104 "sdb_store_host(%s, %d) = %d; expected: %d",
105 golden_data[i].name, (int)golden_data[i].last_update,
106 status, golden_data[i].expected);
107 }
109 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
110 _Bool has;
112 has = sdb_store_has_host(golden_hosts[i].name);
113 fail_unless(has == golden_hosts[i].has,
114 "sdb_store_has_host(%s) = %d; expected: %d",
115 golden_hosts[i].name, has, golden_hosts[i].has);
116 }
117 }
118 END_TEST
120 START_TEST(test_store_get_host)
121 {
122 char *golden_hosts[] = { "a", "b", "c" };
123 char *unknown_hosts[] = { "x", "y", "z" };
124 size_t i;
126 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
127 int status = sdb_store_host(golden_hosts[i], 1);
128 fail_unless(status >= 0,
129 "sdb_store_host(%s) = %d; expected: >=0",
130 golden_hosts[i], status);
131 }
133 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
134 sdb_store_obj_t *sobj1, *sobj2;
135 int ref_cnt;
137 fail_unless(sdb_store_has_host(golden_hosts[i]),
138 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
139 golden_hosts[i]);
141 sobj1 = sdb_store_get_host(golden_hosts[i]);
142 fail_unless(sobj1 != NULL,
143 "sdb_store_get_host(%s) = NULL; expected: <host>",
144 golden_hosts[i]);
145 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
147 fail_unless(ref_cnt > 1,
148 "sdb_store_get_host(%s) did not increment ref count: "
149 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
151 sobj2 = sdb_store_get_host(golden_hosts[i]);
152 fail_unless(sobj2 != NULL,
153 "sdb_store_get_host(%s) = NULL; expected: <host>",
154 golden_hosts[i]);
156 fail_unless(sobj1 == sobj2,
157 "sdb_store_get_host(%s) returned different objects "
158 "in successive calls", golden_hosts[i]);
159 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
160 "sdb_store_get_hosts(%s) did not increment ref count "
161 "(first call: %d; second call: %d)",
162 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
164 sdb_object_deref(SDB_OBJ(sobj1));
165 sdb_object_deref(SDB_OBJ(sobj2));
166 }
167 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
168 sdb_store_obj_t *sobj;
170 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
171 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
172 unknown_hosts[i]);
174 sobj = sdb_store_get_host(unknown_hosts[i]);
175 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
176 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
177 }
178 }
179 END_TEST
181 START_TEST(test_store_attr)
182 {
183 struct {
184 const char *host;
185 const char *key;
186 char *value;
187 sdb_time_t last_update;
188 int expected;
189 } golden_data[] = {
190 { "k", "k", "v", 1, -1 },
191 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
192 { "l", "k1", "v1", 1, 0 },
193 { "l", "k1", "v2", 2, 0 },
194 { "l", "k1", "v3", 2, 1 },
195 { "l", "k2", "v1", 1, 0 },
196 { "m", "k", "v1", 1, 0 },
197 { "m", "k", "v2", 1, 1 },
198 };
200 size_t i;
202 sdb_store_host("l", 1);
203 sdb_store_host("m", 1);
204 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
205 sdb_data_t datum;
206 int status;
208 /* XXX: test other types as well */
209 datum.type = SDB_TYPE_STRING;
210 datum.data.string = golden_data[i].value;
212 status = sdb_store_attribute(golden_data[i].host,
213 golden_data[i].key, &datum,
214 golden_data[i].last_update);
215 fail_unless(status == golden_data[i].expected,
216 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
217 golden_data[i].host, golden_data[i].key, golden_data[i].value,
218 golden_data[i].last_update, status, golden_data[i].expected);
219 }
220 }
221 END_TEST
223 START_TEST(test_store_service)
224 {
225 struct {
226 const char *host;
227 const char *svc;
228 sdb_time_t last_update;
229 int expected;
230 } golden_data[] = {
231 { "k", "s", 1, -1 },
232 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
233 { "l", "s1", 1, 0 },
234 { "l", "s1", 2, 0 },
235 { "l", "s1", 2, 1 },
236 { "l", "s2", 1, 0 },
237 { "m", "s", 1, 0 },
238 { "m", "s", 1, 1 },
239 };
241 size_t i;
243 sdb_store_host("m", 1);
244 sdb_store_host("l", 1);
245 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
246 int status;
248 status = sdb_store_service(golden_data[i].host,
249 golden_data[i].svc, golden_data[i].last_update);
250 fail_unless(status == golden_data[i].expected,
251 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
252 golden_data[i].host, golden_data[i].svc,
253 golden_data[i].last_update, status, golden_data[i].expected);
254 }
255 }
256 END_TEST
258 START_TEST(test_store_service_attr)
259 {
260 struct {
261 const char *host;
262 const char *svc;
263 const char *attr;
264 const sdb_data_t value;
265 sdb_time_t last_update;
266 int expected;
267 } golden_data[] = {
268 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
269 /* retry, it should still fail */
270 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
271 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
272 /* retry, it should still fail */
273 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
274 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
275 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
276 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
277 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
278 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
279 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
280 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
281 };
283 size_t i;
285 sdb_store_host("m", 1);
286 sdb_store_host("l", 1);
287 sdb_store_service("m", "s1", 1);
288 sdb_store_service("l", "s1", 1);
289 sdb_store_service("l", "s2", 1);
291 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
292 int status;
294 status = sdb_store_service_attr(golden_data[i].host,
295 golden_data[i].svc, golden_data[i].attr,
296 &golden_data[i].value, golden_data[i].last_update);
297 fail_unless(status == golden_data[i].expected,
298 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
299 "expected: %d", golden_data[i].host, golden_data[i].svc,
300 golden_data[i].attr, golden_data[i].value.data.integer,
301 golden_data[i].last_update, status, golden_data[i].expected);
302 }
303 }
304 END_TEST
306 static void
307 verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags)
308 {
309 int pos;
310 size_t len1, len2;
311 size_t i;
313 len1 = strlen(sdb_strbuf_string(buf));
314 len2 = strlen(expected);
316 pos = -1;
317 if (len1 != len2)
318 pos = (int)(len1 <= len2 ? len1 : len2);
320 for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
321 if (sdb_strbuf_string(buf)[i] != expected[i]) {
322 pos = (int)i;
323 break;
324 }
325 }
327 fail_unless(pos == -1,
328 "sdb_store_tojson(%x) returned unexpected result\n"
329 " got: %s\n %*s\n expected: %s",
330 flags, sdb_strbuf_string(buf), pos + 1, "^", expected);
331 } /* verify_json_output */
333 START_TEST(test_store_tojson)
334 {
335 sdb_strbuf_t *buf;
336 size_t i;
338 struct {
339 struct {
340 sdb_store_matcher_t *(*m)(sdb_store_cond_t *);
341 int field;
342 sdb_data_t value;
343 } filter;
344 int flags;
345 const char *expected;
346 } golden_data[] = {
347 { { NULL, 0, SDB_DATA_INIT }, 0,
348 "{\"hosts\":["
349 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
350 "\"update_interval\": \"0s\", \"backends\": [], "
351 "\"attributes\": ["
352 "{\"name\": \"k1\", \"value\": \"v1\", "
353 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
354 "\"update_interval\": \"0s\", \"backends\": []},"
355 "{\"name\": \"k2\", \"value\": \"v2\", "
356 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
357 "\"update_interval\": \"0s\", \"backends\": []},"
358 "{\"name\": \"k3\", \"value\": \"v3\", "
359 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
360 "\"update_interval\": \"0s\", \"backends\": []}"
361 "], "
362 "\"metrics\": [], "
363 "\"services\": []},"
364 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
365 "\"update_interval\": \"0s\", \"backends\": [], "
366 "\"attributes\": [], "
367 "\"metrics\": [], "
368 "\"services\": ["
369 "{\"name\": \"s1\", "
370 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
371 "\"update_interval\": \"0s\", \"backends\": [], "
372 "\"attributes\": []},"
373 "{\"name\": \"s2\", "
374 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
375 "\"update_interval\": \"0s\", \"backends\": [], "
376 "\"attributes\": ["
377 "{\"name\": \"k1\", \"value\": 123, "
378 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
379 "\"update_interval\": \"0s\", \"backends\": []},"
380 "{\"name\": \"k2\", \"value\": 4711, "
381 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
382 "\"update_interval\": \"0s\", \"backends\": []}"
383 "]}"
384 "]}"
385 "]}" },
386 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_SERVICES,
387 "{\"hosts\":["
388 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
389 "\"update_interval\": \"0s\", \"backends\": [], "
390 "\"attributes\": ["
391 "{\"name\": \"k1\", \"value\": \"v1\", "
392 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
393 "\"update_interval\": \"0s\", \"backends\": []},"
394 "{\"name\": \"k2\", \"value\": \"v2\", "
395 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
396 "\"update_interval\": \"0s\", \"backends\": []},"
397 "{\"name\": \"k3\", \"value\": \"v3\", "
398 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
399 "\"update_interval\": \"0s\", \"backends\": []}"
400 "], "
401 "\"metrics\": []},"
402 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
403 "\"update_interval\": \"0s\", \"backends\": [], "
404 "\"attributes\": [], "
405 "\"metrics\": []}"
406 "]}" },
407 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_METRICS,
408 "{\"hosts\":["
409 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
410 "\"update_interval\": \"0s\", \"backends\": [], "
411 "\"attributes\": ["
412 "{\"name\": \"k1\", \"value\": \"v1\", "
413 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
414 "\"update_interval\": \"0s\", \"backends\": []},"
415 "{\"name\": \"k2\", \"value\": \"v2\", "
416 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
417 "\"update_interval\": \"0s\", \"backends\": []},"
418 "{\"name\": \"k3\", \"value\": \"v3\", "
419 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
420 "\"update_interval\": \"0s\", \"backends\": []}"
421 "], "
422 "\"services\": []},"
423 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
424 "\"update_interval\": \"0s\", \"backends\": [], "
425 "\"attributes\": [], "
426 "\"services\": ["
427 "{\"name\": \"s1\", "
428 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
429 "\"update_interval\": \"0s\", \"backends\": [], "
430 "\"attributes\": []},"
431 "{\"name\": \"s2\", "
432 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
433 "\"update_interval\": \"0s\", \"backends\": [], "
434 "\"attributes\": ["
435 "{\"name\": \"k1\", \"value\": 123, "
436 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
437 "\"update_interval\": \"0s\", \"backends\": []},"
438 "{\"name\": \"k2\", \"value\": 4711, "
439 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
440 "\"update_interval\": \"0s\", \"backends\": []}"
441 "]}"
442 "]}"
443 "]}" },
444 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ATTRIBUTES,
445 "{\"hosts\":["
446 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
447 "\"update_interval\": \"0s\", \"backends\": [], "
448 "\"metrics\": [], "
449 "\"services\": []},"
450 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
451 "\"update_interval\": \"0s\", \"backends\": [], "
452 "\"metrics\": [], "
453 "\"services\": ["
454 "{\"name\": \"s1\", "
455 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
456 "\"update_interval\": \"0s\", \"backends\": []},"
457 "{\"name\": \"s2\", "
458 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
459 "\"update_interval\": \"0s\", \"backends\": []}"
460 "]}"
461 "]}" },
462 { { NULL, 0, SDB_DATA_INIT }, SDB_SKIP_ALL,
463 "{\"hosts\":["
464 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
465 "\"update_interval\": \"0s\", \"backends\": []},"
466 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
467 "\"update_interval\": \"0s\", \"backends\": []}"
468 "]}" },
469 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
470 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
471 "{\"hosts\":["
472 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
473 "\"update_interval\": \"0s\", \"backends\": [], "
474 "\"attributes\": [], "
475 "\"metrics\": [], "
476 "\"services\": ["
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 "]}"
485 "]}"
486 "]}" },
487 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
488 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, 0,
489 "{\"hosts\":["
490 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
491 "\"update_interval\": \"0s\", \"backends\": [], "
492 "\"attributes\": ["
493 "{\"name\": \"k1\", \"value\": \"v1\", "
494 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
495 "\"update_interval\": \"0s\", \"backends\": []},"
496 "], "
497 "\"metrics\": [], "
498 "\"services\": []}"
499 "]}" },
500 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
501 { SDB_TYPE_DATETIME, { .datetime = 3 } } }, 0,
502 "{\"hosts\":["
503 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
504 "\"update_interval\": \"0s\", \"backends\": [], "
505 "\"attributes\": [], "
506 "\"metrics\": [], "
507 "\"services\": []}"
508 "]}" },
509 };
511 buf = sdb_strbuf_create(0);
512 fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
513 populate();
515 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
516 sdb_store_matcher_t *filter = NULL;
517 char filter_str[1024];
518 int status;
520 sdb_strbuf_clear(buf);
522 if (golden_data[i].filter.m) {
523 sdb_store_expr_t *expr;
524 sdb_store_cond_t *c = NULL;
526 expr = sdb_store_expr_constvalue(&golden_data[i].filter.value);
527 fail_unless(expr != NULL,
528 "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
529 c = sdb_store_obj_cond(golden_data[i].filter.field, expr);
530 sdb_object_deref(SDB_OBJ(expr));
531 fail_unless(c != NULL,
532 "INTERNAL ERROR: sdb_store_obj_cond() = NULL");
533 filter = golden_data[i].filter.m(c);
534 sdb_object_deref(SDB_OBJ(c));
535 fail_unless(filter != NULL,
536 "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
537 }
539 if (sdb_store_matcher_tostring(filter, filter_str, sizeof(filter_str)))
540 snprintf(filter_str, sizeof(filter_str), "ERR");
542 status = sdb_store_tojson(buf, filter, golden_data[i].flags);
543 fail_unless(status == 0,
544 "sdb_store_tojson(<buf>, %s, %x) = %d; expected: 0",
545 filter_str, golden_data[i].flags, status);
547 verify_json_output(buf, golden_data[i].expected, golden_data[i].flags);
548 sdb_object_deref(SDB_OBJ(filter));
549 }
550 sdb_strbuf_destroy(buf);
551 }
552 END_TEST
554 START_TEST(test_get_field)
555 {
556 sdb_store_obj_t *host;
557 sdb_data_t value = SDB_DATA_INIT;
558 int check;
560 sdb_store_host("host", 10);
561 sdb_store_host("host", 20);
563 host = sdb_store_get_host("host");
564 fail_unless(host != NULL,
565 "INTERNAL ERROR: store doesn't have host after adding it");
567 check = sdb_store_get_field(NULL, 0, NULL);
568 fail_unless(check < 0,
569 "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
570 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
571 fail_unless(check < 0,
572 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
573 "expected: <0");
574 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
575 fail_unless(check < 0,
576 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
577 "expected: <0");
578 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
579 fail_unless(check < 0,
580 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
581 "expected: <0");
583 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
584 fail_unless(check == 0,
585 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
586 "%d; expected: 0");
587 fail_unless((value.type == SDB_TYPE_DATETIME)
588 && (value.data.datetime == 20),
589 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
590 "returned value {%d, %lu}; expected {%d, 20}",
591 value.type, value.data.datetime, SDB_TYPE_DATETIME);
593 check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
594 fail_unless(check == 0,
595 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
596 "%d; expected: 0");
597 /* let's assume we're at least in year 1980 ;-) */
598 fail_unless((value.type == SDB_TYPE_DATETIME)
599 && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
600 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
601 "returned value {%d, %lu}; expected {%d, >%lu}",
602 value.type, value.data.datetime,
603 SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
605 check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
606 fail_unless(check == 0,
607 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
608 "%d; expected: 0");
609 fail_unless((value.type == SDB_TYPE_DATETIME)
610 && (value.data.datetime == 10),
611 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
612 "returned value {%d, %lu}; expected {%d, 10}",
613 value.type, value.data.datetime, SDB_TYPE_DATETIME);
614 }
615 END_TEST
617 START_TEST(test_interval)
618 {
619 sdb_store_obj_t *host;
621 /* 10 us interval */
622 sdb_store_host("host", 10);
623 sdb_store_host("host", 20);
624 sdb_store_host("host", 30);
625 sdb_store_host("host", 40);
627 host = sdb_store_get_host("host");
628 fail_unless(host != NULL,
629 "INTERNAL ERROR: store doesn't have host after adding it");
631 fail_unless(host->interval == 10,
632 "sdb_store_host() did not calculate interval correctly: "
633 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
635 /* multiple updates for the same timestamp don't modify the interval */
636 sdb_store_host("host", 40);
637 sdb_store_host("host", 40);
638 sdb_store_host("host", 40);
639 sdb_store_host("host", 40);
641 fail_unless(host->interval == 10,
642 "sdb_store_host() changed interval when doing multiple updates "
643 "using the same timestamp; got: %"PRIsdbTIME"; "
644 "expected: %"PRIsdbTIME, host->interval, 10);
646 /* multiple updates using an timestamp don't modify the interval */
647 sdb_store_host("host", 20);
648 sdb_store_host("host", 20);
649 sdb_store_host("host", 20);
650 sdb_store_host("host", 20);
652 fail_unless(host->interval == 10,
653 "sdb_store_host() changed interval when doing multiple updates "
654 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
655 host->interval, 10);
657 /* new interval: 20 us */
658 sdb_store_host("host", 60);
659 fail_unless(host->interval == 11,
660 "sdb_store_host() did not calculate interval correctly: "
661 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
663 /* new interval: 40 us */
664 sdb_store_host("host", 100);
665 fail_unless(host->interval == 13,
666 "sdb_store_host() did not calculate interval correctly: "
667 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
669 sdb_object_deref(SDB_OBJ(host));
670 }
671 END_TEST
673 static int
674 iter_incr(sdb_store_obj_t *obj, void *user_data)
675 {
676 intptr_t *i = user_data;
678 fail_unless(obj != NULL,
679 "sdb_store_iterate callback received NULL obj; expected: "
680 "<store base obj>");
681 fail_unless(i != NULL,
682 "sdb_store_iterate callback received NULL user_data; "
683 "expected: <pointer to data>");
685 ++(*i);
686 return 0;
687 } /* iter_incr */
689 static int
690 iter_error(sdb_store_obj_t *obj, void *user_data)
691 {
692 intptr_t *i = user_data;
694 fail_unless(obj != NULL,
695 "sdb_store_iterate callback received NULL obj; expected: "
696 "<store base obj>");
697 fail_unless(i != NULL,
698 "sdb_store_iterate callback received NULL user_data; "
699 "expected: <pointer to data>");
701 ++(*i);
702 return -1;
703 } /* iter_error */
705 START_TEST(test_iterate)
706 {
707 intptr_t i = 0;
708 int check;
710 /* empty store */
711 check = sdb_store_iterate(iter_incr, &i);
712 fail_unless(check == -1,
713 "sdb_store_iterate(), empty store = %d; expected: -1", check);
714 fail_unless(i == 0,
715 "sdb_store_iterate called callback %d times; expected: 0", (int)i);
717 populate();
719 check = sdb_store_iterate(iter_incr, &i);
720 fail_unless(check == 0,
721 "sdb_store_iterate() = %d; expected: 0", check);
722 fail_unless(i == 2,
723 "sdb_store_iterate called callback %d times; expected: 1", (int)i);
725 i = 0;
726 check = sdb_store_iterate(iter_error, &i);
727 fail_unless(check == -1,
728 "sdb_store_iterate(), error callback = %d; expected: -1", check);
729 fail_unless(i == 1,
730 "sdb_store_iterate called callback %d times "
731 "(callback returned error); expected: 1", (int)i);
732 }
733 END_TEST
735 Suite *
736 core_store_suite(void)
737 {
738 Suite *s = suite_create("core::store");
739 TCase *tc;
741 tc = tcase_create("core");
742 tcase_add_test(tc, test_store_tojson);
743 tcase_add_test(tc, test_store_host);
744 tcase_add_test(tc, test_store_get_host);
745 tcase_add_test(tc, test_store_attr);
746 tcase_add_test(tc, test_store_service);
747 tcase_add_test(tc, test_store_service_attr);
748 tcase_add_test(tc, test_get_field);
749 tcase_add_test(tc, test_interval);
750 tcase_add_test(tc, test_iterate);
751 tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
752 suite_add_tcase(s, tc);
754 return s;
755 } /* core_store_suite */
757 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */