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>
34 #include <strings.h>
36 static void
37 populate(void)
38 {
39 sdb_data_t datum;
41 sdb_store_host("h1", 1);
42 sdb_store_host("h2", 3);
44 datum.type = SDB_TYPE_STRING;
45 datum.data.string = "v1";
46 sdb_store_attribute("h1", "k1", &datum, 1);
47 datum.data.string = "v2";
48 sdb_store_attribute("h1", "k2", &datum, 2);
49 datum.data.string = "v3";
50 sdb_store_attribute("h1", "k3", &datum, 2);
52 /* make sure that older updates don't overwrite existing values */
53 datum.data.string = "fail";
54 sdb_store_attribute("h1", "k2", &datum, 1);
55 sdb_store_attribute("h1", "k3", &datum, 2);
57 sdb_store_metric("h1", "m1", /* store */ NULL, 2);
58 sdb_store_metric("h1", "m2", /* store */ NULL, 1);
59 sdb_store_metric("h2", "m1", /* store */ NULL, 1);
61 sdb_store_service("h2", "s1", 1);
62 sdb_store_service("h2", "s2", 2);
64 datum.type = SDB_TYPE_INTEGER;
65 datum.data.integer = 42;
66 sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
68 datum.data.integer = 123;
69 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
70 datum.data.integer = 4711;
71 sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
73 /* don't overwrite k1 */
74 datum.data.integer = 666;
75 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
76 } /* populate */
78 START_TEST(test_store_host)
79 {
80 struct {
81 const char *name;
82 sdb_time_t last_update;
83 int expected;
84 } golden_data[] = {
85 { "a", 1, 0 },
86 { "a", 2, 0 },
87 { "a", 1, 1 },
88 { "b", 1, 0 },
89 { "b", 1, 1 },
90 { "A", 1, 1 }, /* case-insensitive */
91 { "A", 3, 0 },
92 };
94 struct {
95 const char *name;
96 _Bool has;
97 } golden_hosts[] = {
98 { "a", 1 == 1 },
99 { "b", 1 == 1 },
100 { "c", 0 == 1 },
101 { "A", 1 == 1 },
102 };
104 size_t i;
106 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
107 int status;
109 status = sdb_store_host(golden_data[i].name,
110 golden_data[i].last_update);
111 fail_unless(status == golden_data[i].expected,
112 "sdb_store_host(%s, %d) = %d; expected: %d",
113 golden_data[i].name, (int)golden_data[i].last_update,
114 status, golden_data[i].expected);
115 }
117 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
118 _Bool has;
120 has = sdb_store_has_host(golden_hosts[i].name);
121 fail_unless(has == golden_hosts[i].has,
122 "sdb_store_has_host(%s) = %d; expected: %d",
123 golden_hosts[i].name, has, golden_hosts[i].has);
124 }
125 }
126 END_TEST
128 START_TEST(test_store_get_host)
129 {
130 char *golden_hosts[] = { "a", "b", "c" };
131 char *unknown_hosts[] = { "x", "y", "z" };
132 size_t i;
134 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
135 int status = sdb_store_host(golden_hosts[i], 1);
136 fail_unless(status >= 0,
137 "sdb_store_host(%s) = %d; expected: >=0",
138 golden_hosts[i], status);
139 }
141 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
142 sdb_store_obj_t *sobj1, *sobj2;
143 int ref_cnt;
145 fail_unless(sdb_store_has_host(golden_hosts[i]),
146 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
147 golden_hosts[i]);
149 sobj1 = sdb_store_get_host(golden_hosts[i]);
150 fail_unless(sobj1 != NULL,
151 "sdb_store_get_host(%s) = NULL; expected: <host>",
152 golden_hosts[i]);
153 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
155 fail_unless(ref_cnt > 1,
156 "sdb_store_get_host(%s) did not increment ref count: "
157 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
159 sobj2 = sdb_store_get_host(golden_hosts[i]);
160 fail_unless(sobj2 != NULL,
161 "sdb_store_get_host(%s) = NULL; expected: <host>",
162 golden_hosts[i]);
164 fail_unless(sobj1 == sobj2,
165 "sdb_store_get_host(%s) returned different objects "
166 "in successive calls", golden_hosts[i]);
167 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
168 "sdb_store_get_hosts(%s) did not increment ref count "
169 "(first call: %d; second call: %d)",
170 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
172 sdb_object_deref(SDB_OBJ(sobj1));
173 sdb_object_deref(SDB_OBJ(sobj2));
174 }
175 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
176 sdb_store_obj_t *sobj;
178 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
179 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
180 unknown_hosts[i]);
182 sobj = sdb_store_get_host(unknown_hosts[i]);
183 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
184 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
185 }
186 }
187 END_TEST
189 START_TEST(test_store_attr)
190 {
191 struct {
192 const char *host;
193 const char *key;
194 char *value;
195 sdb_time_t last_update;
196 int expected;
197 } golden_data[] = {
198 { "k", "k", "v", 1, -1 },
199 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
200 { "l", "k1", "v1", 1, 0 },
201 { "l", "k1", "v2", 2, 0 },
202 { "l", "k1", "v3", 2, 1 },
203 { "l", "k2", "v1", 1, 0 },
204 { "m", "k", "v1", 1, 0 },
205 { "m", "k", "v2", 1, 1 },
206 };
208 size_t i;
210 sdb_store_host("l", 1);
211 sdb_store_host("m", 1);
212 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
213 sdb_data_t datum;
214 int status;
216 /* XXX: test other types as well */
217 datum.type = SDB_TYPE_STRING;
218 datum.data.string = golden_data[i].value;
220 status = sdb_store_attribute(golden_data[i].host,
221 golden_data[i].key, &datum,
222 golden_data[i].last_update);
223 fail_unless(status == golden_data[i].expected,
224 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
225 golden_data[i].host, golden_data[i].key, golden_data[i].value,
226 golden_data[i].last_update, status, golden_data[i].expected);
227 }
228 }
229 END_TEST
231 START_TEST(test_store_metric)
232 {
233 sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
234 sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
236 struct {
237 const char *host;
238 const char *metric;
239 sdb_metric_store_t *store;
240 sdb_time_t last_update;
241 int expected;
242 } golden_data[] = {
243 { "k", "m", NULL, 1, -1 },
244 { "k", "m", NULL, 1, -1 }, /* retry to ensure the host is not created */
245 { "k", "m", &store1, 1, -1 },
246 { "l", "m1", NULL, 1, 0 },
247 { "l", "m1", &store1, 2, 0 },
248 { "l", "m1", &store1, 3, 0 },
249 { "l", "m1", NULL, 3, 1 },
250 { "l", "m2", &store1, 1, 0 },
251 { "l", "m2", &store2, 2, 0 },
252 { "l", "m2", NULL, 3, 0 },
253 { "m", "m", &store1, 1, 0 },
254 { "m", "m", NULL, 2, 0 },
255 { "m", "m", NULL, 2, 1 },
256 { "m", "m", &store1, 3, 0 },
257 { "m", "m", &store2, 4, 0 },
258 { "m", "m", NULL, 5, 0 },
259 };
261 size_t i;
263 sdb_store_host("m", 1);
264 sdb_store_host("l", 1);
265 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
266 int status;
268 status = sdb_store_metric(golden_data[i].host,
269 golden_data[i].metric, golden_data[i].store,
270 golden_data[i].last_update);
271 fail_unless(status == golden_data[i].expected,
272 "sdb_store_metric(%s, %s, %p, %d) = %d; expected: %d",
273 golden_data[i].host, golden_data[i].metric,
274 golden_data[i].store, golden_data[i].last_update,
275 status, golden_data[i].expected);
276 }
277 }
278 END_TEST
280 START_TEST(test_store_metric_attr)
281 {
282 struct {
283 const char *host;
284 const char *metric;
285 const char *attr;
286 const sdb_data_t value;
287 sdb_time_t last_update;
288 int expected;
289 } golden_data[] = {
290 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
291 /* retry, it should still fail */
292 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
293 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
294 /* retry, it should still fail */
295 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
296 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
297 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
298 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
299 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
300 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
301 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
302 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
303 };
305 size_t i;
307 sdb_store_host("m", 1);
308 sdb_store_host("l", 1);
309 sdb_store_metric("m", "m1", NULL, 1);
310 sdb_store_metric("l", "m1", NULL, 1);
311 sdb_store_metric("l", "m2", NULL, 1);
313 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
314 int status;
316 status = sdb_store_metric_attr(golden_data[i].host,
317 golden_data[i].metric, golden_data[i].attr,
318 &golden_data[i].value, golden_data[i].last_update);
319 fail_unless(status == golden_data[i].expected,
320 "sdb_store_metric_attr(%s, %s, %s, %d, %d) = %d; "
321 "expected: %d", golden_data[i].host, golden_data[i].metric,
322 golden_data[i].attr, golden_data[i].value.data.integer,
323 golden_data[i].last_update, status, golden_data[i].expected);
324 }
325 }
326 END_TEST
328 START_TEST(test_store_service)
329 {
330 struct {
331 const char *host;
332 const char *svc;
333 sdb_time_t last_update;
334 int expected;
335 } golden_data[] = {
336 { "k", "s", 1, -1 },
337 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
338 { "l", "s1", 1, 0 },
339 { "l", "s1", 2, 0 },
340 { "l", "s1", 2, 1 },
341 { "l", "s2", 1, 0 },
342 { "m", "s", 1, 0 },
343 { "m", "s", 1, 1 },
344 };
346 size_t i;
348 sdb_store_host("m", 1);
349 sdb_store_host("l", 1);
350 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
351 int status;
353 status = sdb_store_service(golden_data[i].host,
354 golden_data[i].svc, golden_data[i].last_update);
355 fail_unless(status == golden_data[i].expected,
356 "sdb_store_service(%s, %s, %d) = %d; expected: %d",
357 golden_data[i].host, golden_data[i].svc,
358 golden_data[i].last_update, status, golden_data[i].expected);
359 }
360 }
361 END_TEST
363 START_TEST(test_store_service_attr)
364 {
365 struct {
366 const char *host;
367 const char *svc;
368 const char *attr;
369 const sdb_data_t value;
370 sdb_time_t last_update;
371 int expected;
372 } golden_data[] = {
373 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
374 /* retry, it should still fail */
375 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
376 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
377 /* retry, it should still fail */
378 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
379 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
380 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
381 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
382 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
383 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
384 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
385 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
386 };
388 size_t i;
390 sdb_store_host("m", 1);
391 sdb_store_host("l", 1);
392 sdb_store_service("m", "s1", 1);
393 sdb_store_service("l", "s1", 1);
394 sdb_store_service("l", "s2", 1);
396 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
397 int status;
399 status = sdb_store_service_attr(golden_data[i].host,
400 golden_data[i].svc, golden_data[i].attr,
401 &golden_data[i].value, golden_data[i].last_update);
402 fail_unless(status == golden_data[i].expected,
403 "sdb_store_service_attr(%s, %s, %s, %d, %d) = %d; "
404 "expected: %d", golden_data[i].host, golden_data[i].svc,
405 golden_data[i].attr, golden_data[i].value.data.integer,
406 golden_data[i].last_update, status, golden_data[i].expected);
407 }
408 }
409 END_TEST
411 START_TEST(test_get_field)
412 {
413 sdb_store_obj_t *host;
414 sdb_data_t value = SDB_DATA_INIT;
415 int check;
417 sdb_store_host("host", 10);
418 sdb_store_host("host", 20);
420 host = sdb_store_get_host("host");
421 fail_unless(host != NULL,
422 "INTERNAL ERROR: store doesn't have host after adding it");
424 check = sdb_store_get_field(NULL, 0, NULL);
425 fail_unless(check < 0,
426 "sdb_store_get_field(NULL, 0, NULL) = %d; expected: <0");
427 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL);
428 fail_unless(check < 0,
429 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
430 "expected: <0");
431 check = sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, &value);
432 fail_unless(check < 0,
433 "sdb_store_get_field(NULL, SDB_FIELD_LAST_UPDATE, <value>) = %d; "
434 "expected: <0");
436 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, NULL);
437 fail_unless(check == 0,
438 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
439 "expected: 0");
440 /* 'name' is dynamically allocated; make sure it's not leaked even
441 * if there is no result parameter */
442 check = sdb_store_get_field(host, SDB_FIELD_NAME, NULL);
443 fail_unless(check == 0,
444 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, NULL) = %d; "
445 "expected: 0");
447 check = sdb_store_get_field(host, SDB_FIELD_NAME, &value);
448 fail_unless(check == 0,
449 "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) = "
450 "%d; expected: 0");
451 fail_unless((value.type == SDB_TYPE_STRING)
452 && (! strcmp(value.data.string, "host")),
453 "sdb_store_get_field(<host>, SDB_FIELD_NAME, <value>) "
454 "returned value {%d, %s}; expected {%d, host}",
455 value.type, value.data.string, SDB_TYPE_STRING);
456 sdb_data_free_datum(&value);
458 check = sdb_store_get_field(host, SDB_FIELD_LAST_UPDATE, &value);
459 fail_unless(check == 0,
460 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) = "
461 "%d; expected: 0");
462 fail_unless((value.type == SDB_TYPE_DATETIME)
463 && (value.data.datetime == 20),
464 "sdb_store_get_field(<host>, SDB_FIELD_LAST_UPDATE, <value>) "
465 "returned value {%d, %lu}; expected {%d, 20}",
466 value.type, value.data.datetime, SDB_TYPE_DATETIME);
468 check = sdb_store_get_field(host, SDB_FIELD_AGE, &value);
469 fail_unless(check == 0,
470 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) = "
471 "%d; expected: 0");
472 /* let's assume we're at least in year 1980 ;-) */
473 fail_unless((value.type == SDB_TYPE_DATETIME)
474 && (value.data.datetime > 10L * SDB_INTERVAL_YEAR),
475 "sdb_store_get_field(<host>, SDB_FIELD_AGE, <value>) "
476 "returned value {%d, %lu}; expected {%d, >%lu}",
477 value.type, value.data.datetime,
478 SDB_TYPE_DATETIME, 10L * SDB_INTERVAL_YEAR);
480 check = sdb_store_get_field(host, SDB_FIELD_INTERVAL, &value);
481 fail_unless(check == 0,
482 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) = "
483 "%d; expected: 0");
484 fail_unless((value.type == SDB_TYPE_DATETIME)
485 && (value.data.datetime == 10),
486 "sdb_store_get_field(<host>, SDB_FIELD_INTERVAL, <value>) "
487 "returned value {%d, %lu}; expected {%d, 10}",
488 value.type, value.data.datetime, SDB_TYPE_DATETIME);
490 check = sdb_store_get_field(host, SDB_FIELD_BACKEND, &value);
491 fail_unless(check == 0,
492 "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) = "
493 "%d; expected: 0");
494 /* there are no backends in this test */
495 fail_unless((value.type == (SDB_TYPE_ARRAY | SDB_TYPE_STRING))
496 && (value.data.array.length == 0)
497 && (value.data.array.values == NULL),
498 "sdb_store_get_field(<host>, SDB_FIELD_BACKEND, <value>) "
499 "returned value {%d, %lu, %p}; expected {%d, 0, NULL}",
500 value.type, value.data.array.length, value.data.array.values,
501 SDB_TYPE_ARRAY | SDB_TYPE_STRING);
502 }
503 END_TEST
505 START_TEST(test_get_child)
506 {
507 struct {
508 const char *host;
509 const char *name;
510 int type;
511 int expected;
512 } golden_data[] = {
513 { "h1", NULL, SDB_HOST, 0 },
514 { "h1", NULL, SDB_SERVICE, -1 },
515 { "h1", NULL, SDB_METRIC, -1 },
516 { "h1", NULL, SDB_ATTRIBUTE, -1 },
517 { "h2", NULL, SDB_HOST, 0 },
518 { "h2", NULL, SDB_SERVICE, -1 },
519 { "h2", NULL, SDB_METRIC, -1 },
520 { "h2", NULL, SDB_ATTRIBUTE, -1 },
521 { "h3", NULL, SDB_HOST, -1 },
522 { "h1", "k1", SDB_ATTRIBUTE, 0 },
523 { "h1", "x1", SDB_ATTRIBUTE, -1 },
524 { "h2", "k1", SDB_ATTRIBUTE, -1 },
525 { "h1", "k1", SDB_SERVICE, -1 },
526 { "h1", "k1", SDB_METRIC, -1 },
527 { "h1", "s1", SDB_SERVICE, -1 },
528 { "h2", "s1", SDB_SERVICE, 0 },
529 { "h1", "m2", SDB_METRIC, 0 },
530 { "h2", "m2", SDB_METRIC, -1 },
531 };
533 size_t i;
535 populate();
537 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
538 sdb_store_obj_t *obj;
539 const char *expected_name = golden_data[i].host;
541 obj = sdb_store_get_host(golden_data[i].host);
542 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
543 fail_unless(obj == NULL,
544 "sdb_store_get_host(%s) = %p; expected: NULL",
545 golden_data[i].host, obj);
546 else
547 fail_unless(obj != NULL,
548 "sdb_store_get_host(%s) = NULL; expected: <host>",
549 golden_data[i].host);
551 if (golden_data[i].type != SDB_HOST) {
552 sdb_store_obj_t *tmp;
554 expected_name = golden_data[i].name;
556 tmp = sdb_store_get_child(obj,
557 golden_data[i].type, golden_data[i].name);
558 if (golden_data[i].expected)
559 fail_unless(tmp == NULL,
560 "sdb_store_get_child(<%s>, %s, %s) = %p; "
561 "expected: NULL", golden_data[i].host,
562 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
563 golden_data[i].name, tmp);
564 else
565 fail_unless(tmp != NULL,
566 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
567 "expected: <obj>", golden_data[i].host,
568 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
569 golden_data[i].name);
571 sdb_object_deref(SDB_OBJ(obj));
572 obj = tmp;
573 }
575 if (golden_data[i].expected)
576 continue;
578 fail_unless(obj->type == golden_data[i].type,
579 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
580 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
581 golden_data[i].host, golden_data[i].name, obj->type,
582 golden_data[i].type);
583 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
584 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
585 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
586 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
587 expected_name);
589 sdb_object_deref(SDB_OBJ(obj));
590 }
591 }
592 END_TEST
594 START_TEST(test_interval)
595 {
596 sdb_store_obj_t *host;
598 /* 10 us interval */
599 sdb_store_host("host", 10);
600 sdb_store_host("host", 20);
601 sdb_store_host("host", 30);
602 sdb_store_host("host", 40);
604 host = sdb_store_get_host("host");
605 fail_unless(host != NULL,
606 "INTERNAL ERROR: store doesn't have host after adding it");
608 fail_unless(host->interval == 10,
609 "sdb_store_host() did not calculate interval correctly: "
610 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
612 /* multiple updates for the same timestamp don't modify the interval */
613 sdb_store_host("host", 40);
614 sdb_store_host("host", 40);
615 sdb_store_host("host", 40);
616 sdb_store_host("host", 40);
618 fail_unless(host->interval == 10,
619 "sdb_store_host() changed interval when doing multiple updates "
620 "using the same timestamp; got: %"PRIsdbTIME"; "
621 "expected: %"PRIsdbTIME, host->interval, 10);
623 /* multiple updates using an timestamp don't modify the interval */
624 sdb_store_host("host", 20);
625 sdb_store_host("host", 20);
626 sdb_store_host("host", 20);
627 sdb_store_host("host", 20);
629 fail_unless(host->interval == 10,
630 "sdb_store_host() changed interval when doing multiple updates "
631 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
632 host->interval, 10);
634 /* new interval: 20 us */
635 sdb_store_host("host", 60);
636 fail_unless(host->interval == 11,
637 "sdb_store_host() did not calculate interval correctly: "
638 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
640 /* new interval: 40 us */
641 sdb_store_host("host", 100);
642 fail_unless(host->interval == 13,
643 "sdb_store_host() did not calculate interval correctly: "
644 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
646 sdb_object_deref(SDB_OBJ(host));
647 }
648 END_TEST
650 static int
651 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
652 {
653 intptr_t *i = user_data;
655 if (! sdb_store_matcher_matches(filter, obj, NULL))
656 return 0;
658 fail_unless(obj != NULL,
659 "sdb_store_scan callback received NULL obj; expected: "
660 "<store base obj>");
661 fail_unless(i != NULL,
662 "sdb_store_scan callback received NULL user_data; "
663 "expected: <pointer to data>");
665 ++(*i);
666 return 0;
667 } /* scan_count */
669 static int
670 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
671 {
672 intptr_t *i = user_data;
674 if (! sdb_store_matcher_matches(filter, obj, NULL))
675 return 0;
677 fail_unless(obj != NULL,
678 "sdb_store_scan callback received NULL obj; expected: "
679 "<store base obj>");
680 fail_unless(i != NULL,
681 "sdb_store_scan callback received NULL user_data; "
682 "expected: <pointer to data>");
684 ++(*i);
685 return -1;
686 } /* scan_error */
688 START_TEST(test_scan)
689 {
690 intptr_t i = 0;
691 int check;
693 /* empty store */
694 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
695 scan_count, &i);
696 fail_unless(check == -1,
697 "sdb_store_scan(HOST), empty store = %d; expected: -1", check);
698 fail_unless(i == 0,
699 "sdb_store_scan(HOST) called callback %d times; "
700 "expected: 0", (int)i);
702 populate();
704 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
705 scan_count, &i);
706 fail_unless(check == 0,
707 "sdb_store_scan(HOST) = %d; expected: 0", check);
708 fail_unless(i == 2,
709 "sdb_store_scan(HOST) called callback %d times; "
710 "expected: 1", (int)i);
712 i = 0;
713 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
714 scan_error, &i);
715 fail_unless(check == -1,
716 "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
717 fail_unless(i == 1,
718 "sdb_store_scan(HOST) called callback %d times "
719 "(callback returned error); expected: 1", (int)i);
721 i = 0;
722 check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
723 scan_count, &i);
724 fail_unless(check == 0,
725 "sdb_store_scan(SERVICE) = %d; expected: 0", check);
726 fail_unless(i == 2,
727 "sdb_store_scan(SERVICE) called callback %d times; "
728 "expected: 2", (int)i);
730 i = 0;
731 check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
732 scan_count, &i);
733 fail_unless(check == 0,
734 "sdb_store_scan(METRIC) = %d; expected: 0", check);
735 fail_unless(i == 3,
736 "sdb_store_scan(METRIC) called callback %d times; "
737 "expected: 3", (int)i);
738 }
739 END_TEST
741 Suite *
742 core_store_suite(void)
743 {
744 Suite *s = suite_create("core::store");
745 TCase *tc;
747 tc = tcase_create("core");
748 tcase_add_test(tc, test_store_host);
749 tcase_add_test(tc, test_store_get_host);
750 tcase_add_test(tc, test_store_attr);
751 tcase_add_test(tc, test_store_metric);
752 tcase_add_test(tc, test_store_metric_attr);
753 tcase_add_test(tc, test_store_service);
754 tcase_add_test(tc, test_store_service_attr);
755 tcase_add_test(tc, test_get_field);
756 tcase_add_test(tc, test_get_child);
757 tcase_add_test(tc, test_interval);
758 tcase_add_test(tc, test_scan);
759 tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
760 suite_add_tcase(s, tc);
762 return s;
763 } /* core_store_suite */
765 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */