8308f3334f39d7c2c8cd71362f5903eab399c412
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 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "core/store.h"
33 #include "core/store-private.h"
34 #include "testutils.h"
36 #include <check.h>
37 #include <string.h>
38 #include <strings.h>
40 static void
41 init(void)
42 {
43 sdb_store_init();
44 }
46 static void
47 populate(void)
48 {
49 sdb_data_t datum;
51 sdb_store_init();
53 sdb_store_host("h1", 1);
54 sdb_store_host("h2", 3);
56 datum.type = SDB_TYPE_STRING;
57 datum.data.string = "v1";
58 sdb_store_attribute("h1", "k1", &datum, 1);
59 datum.data.string = "v2";
60 sdb_store_attribute("h1", "k2", &datum, 2);
61 datum.data.string = "v3";
62 sdb_store_attribute("h1", "k3", &datum, 2);
64 /* make sure that older updates don't overwrite existing values */
65 datum.data.string = "fail";
66 sdb_store_attribute("h1", "k2", &datum, 1);
67 sdb_store_attribute("h1", "k3", &datum, 2);
69 sdb_store_metric("h1", "m1", /* store */ NULL, 2);
70 sdb_store_metric("h1", "m2", /* store */ NULL, 1);
71 sdb_store_metric("h2", "m1", /* store */ NULL, 1);
73 sdb_store_service("h2", "s1", 1);
74 sdb_store_service("h2", "s2", 2);
76 datum.type = SDB_TYPE_INTEGER;
77 datum.data.integer = 42;
78 sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
80 datum.data.integer = 123;
81 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
82 datum.data.integer = 4711;
83 sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
85 /* don't overwrite k1 */
86 datum.data.integer = 666;
87 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
88 } /* populate */
90 START_TEST(test_store_host)
91 {
92 struct {
93 const char *name;
94 sdb_time_t last_update;
95 int expected;
96 } golden_data[] = {
97 { "a", 1, 0 },
98 { "a", 2, 0 },
99 { "a", 1, 1 },
100 { "b", 1, 0 },
101 { "b", 1, 1 },
102 { "A", 1, 1 }, /* case-insensitive */
103 { "A", 3, 0 },
104 };
106 struct {
107 const char *name;
108 _Bool has;
109 } golden_hosts[] = {
110 { "a", 1 == 1 },
111 { "b", 1 == 1 },
112 { "c", 0 == 1 },
113 { "A", 1 == 1 },
114 };
116 size_t i;
118 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
119 int status;
121 status = sdb_store_host(golden_data[i].name,
122 golden_data[i].last_update);
123 fail_unless(status == golden_data[i].expected,
124 "sdb_store_host(%s, %d) = %d; expected: %d",
125 golden_data[i].name, (int)golden_data[i].last_update,
126 status, golden_data[i].expected);
127 }
129 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
130 _Bool has;
132 has = sdb_store_has_host(golden_hosts[i].name);
133 fail_unless(has == golden_hosts[i].has,
134 "sdb_store_has_host(%s) = %d; expected: %d",
135 golden_hosts[i].name, has, golden_hosts[i].has);
136 }
137 }
138 END_TEST
140 START_TEST(test_store_get_host)
141 {
142 char *golden_hosts[] = { "a", "b", "c" };
143 char *unknown_hosts[] = { "x", "y", "z" };
144 size_t i;
146 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
147 int status = sdb_store_host(golden_hosts[i], 1);
148 fail_unless(status >= 0,
149 "sdb_store_host(%s) = %d; expected: >=0",
150 golden_hosts[i], status);
151 }
153 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
154 sdb_store_obj_t *sobj1, *sobj2;
155 int ref_cnt;
157 fail_unless(sdb_store_has_host(golden_hosts[i]),
158 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
159 golden_hosts[i]);
161 sobj1 = sdb_store_get_host(golden_hosts[i]);
162 fail_unless(sobj1 != NULL,
163 "sdb_store_get_host(%s) = NULL; expected: <host>",
164 golden_hosts[i]);
165 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
167 fail_unless(ref_cnt > 1,
168 "sdb_store_get_host(%s) did not increment ref count: "
169 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
171 sobj2 = sdb_store_get_host(golden_hosts[i]);
172 fail_unless(sobj2 != NULL,
173 "sdb_store_get_host(%s) = NULL; expected: <host>",
174 golden_hosts[i]);
176 fail_unless(sobj1 == sobj2,
177 "sdb_store_get_host(%s) returned different objects "
178 "in successive calls", golden_hosts[i]);
179 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
180 "sdb_store_get_hosts(%s) did not increment ref count "
181 "(first call: %d; second call: %d)",
182 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
184 sdb_object_deref(SDB_OBJ(sobj1));
185 sdb_object_deref(SDB_OBJ(sobj2));
186 }
187 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
188 sdb_store_obj_t *sobj;
190 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
191 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
192 unknown_hosts[i]);
194 sobj = sdb_store_get_host(unknown_hosts[i]);
195 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
196 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
197 }
198 }
199 END_TEST
201 START_TEST(test_store_attr)
202 {
203 struct {
204 const char *host;
205 const char *key;
206 char *value;
207 sdb_time_t last_update;
208 int expected;
209 } golden_data[] = {
210 { "k", "k", "v", 1, -1 },
211 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
212 { "l", "k1", "v1", 1, 0 },
213 { "l", "k1", "v2", 2, 0 },
214 { "l", "k1", "v3", 2, 1 },
215 { "l", "k2", "v1", 1, 0 },
216 { "m", "k", "v1", 1, 0 },
217 { "m", "k", "v2", 1, 1 },
218 };
220 size_t i;
222 sdb_store_host("l", 1);
223 sdb_store_host("m", 1);
224 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
225 sdb_data_t datum;
226 int status;
228 /* XXX: test other types as well */
229 datum.type = SDB_TYPE_STRING;
230 datum.data.string = golden_data[i].value;
232 status = sdb_store_attribute(golden_data[i].host,
233 golden_data[i].key, &datum,
234 golden_data[i].last_update);
235 fail_unless(status == golden_data[i].expected,
236 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
237 golden_data[i].host, golden_data[i].key, golden_data[i].value,
238 golden_data[i].last_update, status, golden_data[i].expected);
239 }
240 }
241 END_TEST
243 START_TEST(test_store_metric)
244 {
245 sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
246 sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
248 struct {
249 const char *host;
250 const char *metric;
251 sdb_metric_store_t *store;
252 sdb_time_t last_update;
253 int expected;
254 } golden_data[] = {
255 { "k", "m", NULL, 1, -1 },
256 { "k", "m", NULL, 1, -1 }, /* retry to ensure the host is not created */
257 { "k", "m", &store1, 1, -1 },
258 { "l", "m1", NULL, 1, 0 },
259 { "l", "m1", &store1, 2, 0 },
260 { "l", "m1", &store1, 3, 0 },
261 { "l", "m1", NULL, 3, 1 },
262 { "l", "m2", &store1, 1, 0 },
263 { "l", "m2", &store2, 2, 0 },
264 { "l", "m2", NULL, 3, 0 },
265 { "m", "m", &store1, 1, 0 },
266 { "m", "m", NULL, 2, 0 },
267 { "m", "m", NULL, 2, 1 },
268 { "m", "m", &store1, 3, 0 },
269 { "m", "m", &store2, 4, 0 },
270 { "m", "m", NULL, 5, 0 },
271 };
273 size_t i;
275 sdb_store_host("m", 1);
276 sdb_store_host("l", 1);
277 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
278 int status;
280 status = sdb_store_metric(golden_data[i].host,
281 golden_data[i].metric, golden_data[i].store,
282 golden_data[i].last_update);
283 fail_unless(status == golden_data[i].expected,
284 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
285 golden_data[i].host, golden_data[i].metric,
286 golden_data[i].store, golden_data[i].last_update,
287 status, golden_data[i].expected);
288 }
289 }
290 END_TEST
292 START_TEST(test_store_metric_attr)
293 {
294 struct {
295 const char *host;
296 const char *metric;
297 const char *attr;
298 const sdb_data_t value;
299 sdb_time_t last_update;
300 int expected;
301 } golden_data[] = {
302 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
303 /* retry, it should still fail */
304 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
305 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
306 /* retry, it should still fail */
307 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
308 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
309 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
310 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
311 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
312 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
313 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
314 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
315 };
317 size_t i;
319 sdb_store_host("m", 1);
320 sdb_store_host("l", 1);
321 sdb_store_metric("m", "m1", NULL, 1);
322 sdb_store_metric("l", "m1", NULL, 1);
323 sdb_store_metric("l", "m2", NULL, 1);
325 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
326 int status;
328 status = sdb_store_metric_attr(golden_data[i].host,
329 golden_data[i].metric, golden_data[i].attr,
330 &golden_data[i].value, golden_data[i].last_update);
331 fail_unless(status == golden_data[i].expected,
332 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
333 "expected: %d", golden_data[i].host, golden_data[i].metric,
334 golden_data[i].attr, golden_data[i].value.data.integer,
335 golden_data[i].last_update, status, golden_data[i].expected);
336 }
337 }
338 END_TEST
340 START_TEST(test_store_service)
341 {
342 struct {
343 const char *host;
344 const char *svc;
345 sdb_time_t last_update;
346 int expected;
347 } golden_data[] = {
348 { "k", "s", 1, -1 },
349 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
350 { "l", "s1", 1, 0 },
351 { "l", "s1", 2, 0 },
352 { "l", "s1", 2, 1 },
353 { "l", "s2", 1, 0 },
354 { "m", "s", 1, 0 },
355 { "m", "s", 1, 1 },
356 };
358 size_t i;
360 sdb_store_host("m", 1);
361 sdb_store_host("l", 1);
362 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
363 int status;
365 status = sdb_store_service(golden_data[i].host,
366 golden_data[i].svc, golden_data[i].last_update);
367 fail_unless(status == golden_data[i].expected,
368 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
369 golden_data[i].host, golden_data[i].svc,
370 golden_data[i].last_update, status, golden_data[i].expected);
371 }
372 }
373 END_TEST
375 START_TEST(test_store_service_attr)
376 {
377 struct {
378 const char *host;
379 const char *svc;
380 const char *attr;
381 const sdb_data_t value;
382 sdb_time_t last_update;
383 int expected;
384 } golden_data[] = {
385 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
386 /* retry, it should still fail */
387 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
388 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
389 /* retry, it should still fail */
390 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
391 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
392 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
393 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
394 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
395 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
396 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
397 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
398 };
400 size_t i;
402 sdb_store_host("m", 1);
403 sdb_store_host("l", 1);
404 sdb_store_service("m", "s1", 1);
405 sdb_store_service("l", "s1", 1);
406 sdb_store_service("l", "s2", 1);
408 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
409 int status;
411 status = sdb_store_service_attr(golden_data[i].host,
412 golden_data[i].svc, golden_data[i].attr,
413 &golden_data[i].value, golden_data[i].last_update);
414 fail_unless(status == golden_data[i].expected,
415 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
416 "expected: %d", golden_data[i].host, golden_data[i].svc,
417 golden_data[i].attr, golden_data[i].value.data.integer,
418 golden_data[i].last_update, status, golden_data[i].expected);
419 }
420 }
421 END_TEST
423 static struct {
424 const char *hostname;
425 const char *attr; /* optional */
426 int field;
427 int expected;
428 sdb_data_t value;
429 } get_field_data[] = {
430 { NULL, NULL, 0, -1, { SDB_TYPE_NULL, { 0 } } },
431 { NULL, NULL, SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
432 { NULL, NULL, SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
433 { NULL, NULL, SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
434 { NULL, NULL, SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
435 { NULL, NULL, SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
436 { NULL, NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
437 { "host", NULL, SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
438 { "host", NULL, SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
439 /* the test will handle AGE specially */
440 { "host", NULL, SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
441 { "host", NULL, SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "host" } } },
442 { "host", NULL, SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
443 { "host", NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
444 { "host", "attr", SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
445 { "host", "attr", SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
446 /* the test will handle AGE specially */
447 { "host", "attr", SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
448 { "host", "attr", SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "attr" } } },
449 { "host", "attr", SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
450 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_INTEGER, { .integer = 1 } } },
451 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } } },
452 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_STRING, { .string = "foo" } } },
453 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DATETIME, { .datetime = 1234567890L } } },
454 { "host", "a", SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
455 { "host", "a", SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
456 { "host", "a", SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
457 { "host", "a", SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
458 { "host", "a", SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
459 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
460 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
461 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
462 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
463 };
465 /* returns a tuple <type> <name> */
466 #define OBJ_NAME(obj) \
467 (obj) ? SDB_STORE_TYPE_TO_NAME(obj->type) : "NULL", \
468 (obj) ? SDB_OBJ(obj)->name : ""
469 START_TEST(test_get_field)
470 {
471 sdb_store_obj_t *obj = NULL;
472 sdb_data_t value = SDB_DATA_INIT;
473 char value_str[128], expected_value_str[128];
474 sdb_time_t now = sdb_gettime();
475 int check;
477 sdb_store_host("host", 10);
478 sdb_store_host("host", 20);
479 sdb_store_attribute("host", "attr", &get_field_data[_i].value, 10);
480 sdb_store_attribute("host", "attr", &get_field_data[_i].value, 20);
482 if (get_field_data[_i].hostname) {
483 obj = sdb_store_get_host(get_field_data[_i].hostname);
484 ck_assert(obj != NULL);
486 if (get_field_data[_i].attr) {
487 sdb_store_obj_t *tmp = sdb_store_get_child(obj,
488 SDB_ATTRIBUTE, get_field_data[_i].attr);
489 sdb_object_deref(SDB_OBJ(obj));
490 obj = tmp;
491 }
492 }
494 check = sdb_store_get_field(obj, get_field_data[_i].field, NULL);
495 fail_unless(check == get_field_data[_i].expected,
496 "sdb_store_get_field(%s %s, %s, NULL) = %d; expected: %d",
497 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
498 check, get_field_data[_i].expected);
499 check = sdb_store_get_field(obj, get_field_data[_i].field, &value);
500 fail_unless(check == get_field_data[_i].expected,
501 "sdb_store_get_field(%s %s, %s, <value>) = %d; expected: %d",
502 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
503 check, get_field_data[_i].expected);
505 if (get_field_data[_i].expected) {
506 sdb_object_deref(SDB_OBJ(obj));
507 return;
508 }
510 if (get_field_data[_i].field == SDB_FIELD_AGE) {
511 get_field_data[_i].value.type = SDB_TYPE_DATETIME;
512 get_field_data[_i].value.data.datetime = now;
513 }
515 sdb_data_format(&value, value_str, sizeof(value_str), 0);
516 sdb_data_format(&get_field_data[_i].value, expected_value_str,
517 sizeof(expected_value_str), 0);
519 if (get_field_data[_i].field == SDB_FIELD_AGE) {
520 fail_unless((value.type == SDB_TYPE_DATETIME)
521 && (value.data.datetime >= now),
522 "sdb_store_get_field(%s %s, %s, <value>) "
523 "returned value %s; expected >=%s", OBJ_NAME(obj),
524 SDB_FIELD_TO_NAME(get_field_data[_i].field),
525 value_str, expected_value_str);
526 }
527 else {
528 fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
529 "sdb_store_get_field(%s %s, %s, <value>) "
530 "returned value %s; expected %s", OBJ_NAME(obj),
531 SDB_FIELD_TO_NAME(get_field_data[_i].field),
532 value_str, expected_value_str);
533 }
534 sdb_data_free_datum(&value);
535 sdb_object_deref(SDB_OBJ(obj));
536 }
537 END_TEST
538 #undef OBJ_NAME
540 START_TEST(test_get_child)
541 {
542 struct {
543 const char *host;
544 const char *name;
545 int type;
546 int expected;
547 } golden_data[] = {
548 { "h1", NULL, SDB_HOST, 0 },
549 { "h1", NULL, SDB_SERVICE, -1 },
550 { "h1", NULL, SDB_METRIC, -1 },
551 { "h1", NULL, SDB_ATTRIBUTE, -1 },
552 { "h2", NULL, SDB_HOST, 0 },
553 { "h2", NULL, SDB_SERVICE, -1 },
554 { "h2", NULL, SDB_METRIC, -1 },
555 { "h2", NULL, SDB_ATTRIBUTE, -1 },
556 { "h3", NULL, SDB_HOST, -1 },
557 { "h1", "k1", SDB_ATTRIBUTE, 0 },
558 { "h1", "x1", SDB_ATTRIBUTE, -1 },
559 { "h2", "k1", SDB_ATTRIBUTE, -1 },
560 { "h1", "k1", SDB_SERVICE, -1 },
561 { "h1", "k1", SDB_METRIC, -1 },
562 { "h1", "s1", SDB_SERVICE, -1 },
563 { "h2", "s1", SDB_SERVICE, 0 },
564 { "h1", "m2", SDB_METRIC, 0 },
565 { "h2", "m2", SDB_METRIC, -1 },
566 };
568 size_t i;
570 populate();
572 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
573 sdb_store_obj_t *obj;
574 const char *expected_name = golden_data[i].host;
576 obj = sdb_store_get_host(golden_data[i].host);
577 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
578 fail_unless(obj == NULL,
579 "sdb_store_get_host(%s) = %p; expected: NULL",
580 golden_data[i].host, obj);
581 else
582 fail_unless(obj != NULL,
583 "sdb_store_get_host(%s) = NULL; expected: <host>",
584 golden_data[i].host);
586 if (golden_data[i].type != SDB_HOST) {
587 sdb_store_obj_t *tmp;
589 expected_name = golden_data[i].name;
591 tmp = sdb_store_get_child(obj,
592 golden_data[i].type, golden_data[i].name);
593 if (golden_data[i].expected)
594 fail_unless(tmp == NULL,
595 "sdb_store_get_child(<%s>, %s, %s) = %p; "
596 "expected: NULL", golden_data[i].host,
597 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
598 golden_data[i].name, tmp);
599 else
600 fail_unless(tmp != NULL,
601 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
602 "expected: <obj>", golden_data[i].host,
603 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
604 golden_data[i].name);
606 sdb_object_deref(SDB_OBJ(obj));
607 obj = tmp;
608 }
610 if (golden_data[i].expected)
611 continue;
613 fail_unless(obj->type == golden_data[i].type,
614 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
615 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
616 golden_data[i].host, golden_data[i].name, obj->type,
617 golden_data[i].type);
618 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
619 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
620 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
621 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
622 expected_name);
624 sdb_object_deref(SDB_OBJ(obj));
625 }
626 }
627 END_TEST
629 START_TEST(test_interval)
630 {
631 sdb_store_obj_t *host;
633 /* 10 us interval */
634 sdb_store_host("host", 10);
635 sdb_store_host("host", 20);
636 sdb_store_host("host", 30);
637 sdb_store_host("host", 40);
639 host = sdb_store_get_host("host");
640 fail_unless(host != NULL,
641 "INTERNAL ERROR: store doesn't have host after adding it");
643 fail_unless(host->interval == 10,
644 "sdb_store_host() did not calculate interval correctly: "
645 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
647 /* multiple updates for the same timestamp don't modify the interval */
648 sdb_store_host("host", 40);
649 sdb_store_host("host", 40);
650 sdb_store_host("host", 40);
651 sdb_store_host("host", 40);
653 fail_unless(host->interval == 10,
654 "sdb_store_host() changed interval when doing multiple updates "
655 "using the same timestamp; got: %"PRIsdbTIME"; "
656 "expected: %"PRIsdbTIME, host->interval, 10);
658 /* multiple updates using an timestamp don't modify the interval */
659 sdb_store_host("host", 20);
660 sdb_store_host("host", 20);
661 sdb_store_host("host", 20);
662 sdb_store_host("host", 20);
664 fail_unless(host->interval == 10,
665 "sdb_store_host() changed interval when doing multiple updates "
666 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
667 host->interval, 10);
669 /* new interval: 20 us */
670 sdb_store_host("host", 60);
671 fail_unless(host->interval == 11,
672 "sdb_store_host() did not calculate interval correctly: "
673 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
675 /* new interval: 40 us */
676 sdb_store_host("host", 100);
677 fail_unless(host->interval == 13,
678 "sdb_store_host() did not calculate interval correctly: "
679 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
681 sdb_object_deref(SDB_OBJ(host));
682 }
683 END_TEST
685 static int
686 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
687 {
688 intptr_t *i = user_data;
690 if (! sdb_store_matcher_matches(filter, obj, NULL))
691 return 0;
693 fail_unless(obj != NULL,
694 "sdb_store_scan callback received NULL obj; expected: "
695 "<store base obj>");
696 fail_unless(i != NULL,
697 "sdb_store_scan callback received NULL user_data; "
698 "expected: <pointer to data>");
700 ++(*i);
701 return 0;
702 } /* scan_count */
704 static int
705 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
706 {
707 intptr_t *i = user_data;
709 if (! sdb_store_matcher_matches(filter, obj, NULL))
710 return 0;
712 fail_unless(obj != NULL,
713 "sdb_store_scan callback received NULL obj; expected: "
714 "<store base obj>");
715 fail_unless(i != NULL,
716 "sdb_store_scan callback received NULL user_data; "
717 "expected: <pointer to data>");
719 ++(*i);
720 return -1;
721 } /* scan_error */
723 START_TEST(test_scan)
724 {
725 intptr_t i = 0;
726 int check;
728 /* empty store */
729 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
730 scan_count, &i);
731 fail_unless(check == 0,
732 "sdb_store_scan(HOST), empty store = %d; expected: 0", check);
733 fail_unless(i == 0,
734 "sdb_store_scan(HOST) called callback %d times; "
735 "expected: 0", (int)i);
737 populate();
739 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
740 scan_count, &i);
741 fail_unless(check == 0,
742 "sdb_store_scan(HOST) = %d; expected: 0", check);
743 fail_unless(i == 2,
744 "sdb_store_scan(HOST) called callback %d times; "
745 "expected: 1", (int)i);
747 i = 0;
748 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
749 scan_error, &i);
750 fail_unless(check == -1,
751 "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
752 fail_unless(i == 1,
753 "sdb_store_scan(HOST) called callback %d times "
754 "(callback returned error); expected: 1", (int)i);
756 i = 0;
757 check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
758 scan_count, &i);
759 fail_unless(check == 0,
760 "sdb_store_scan(SERVICE) = %d; expected: 0", check);
761 fail_unless(i == 2,
762 "sdb_store_scan(SERVICE) called callback %d times; "
763 "expected: 2", (int)i);
765 i = 0;
766 check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
767 scan_count, &i);
768 fail_unless(check == 0,
769 "sdb_store_scan(METRIC) = %d; expected: 0", check);
770 fail_unless(i == 3,
771 "sdb_store_scan(METRIC) called callback %d times; "
772 "expected: 3", (int)i);
773 }
774 END_TEST
776 TEST_MAIN("core::store")
777 {
778 TCase *tc = tcase_create("core");
779 tcase_add_test(tc, test_store_host);
780 tcase_add_test(tc, test_store_get_host);
781 tcase_add_test(tc, test_store_attr);
782 tcase_add_test(tc, test_store_metric);
783 tcase_add_test(tc, test_store_metric_attr);
784 tcase_add_test(tc, test_store_service);
785 tcase_add_test(tc, test_store_service_attr);
786 TC_ADD_LOOP_TEST(tc, get_field);
787 tcase_add_test(tc, test_get_child);
788 tcase_add_test(tc, test_interval);
789 tcase_add_test(tc, test_scan);
790 tcase_add_unchecked_fixture(tc, init, sdb_store_clear);
791 ADD_TCASE(tc);
792 }
793 TEST_MAIN_END
795 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */