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