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/plugin.h"
33 #include "core/store.h"
34 #include "core/store-private.h"
35 #include "testutils.h"
37 #include <check.h>
38 #include <string.h>
39 #include <strings.h>
41 static void
42 init(void)
43 {
44 sdb_store_init();
45 }
47 static void
48 populate(void)
49 {
50 sdb_data_t datum;
52 sdb_plugin_store_host("h1", 1);
53 sdb_plugin_store_host("h2", 3);
55 datum.type = SDB_TYPE_STRING;
56 datum.data.string = "v1";
57 sdb_plugin_store_attribute("h1", "k1", &datum, 1);
58 datum.data.string = "v2";
59 sdb_plugin_store_attribute("h1", "k2", &datum, 2);
60 datum.data.string = "v3";
61 sdb_plugin_store_attribute("h1", "k3", &datum, 2);
63 /* make sure that older updates don't overwrite existing values */
64 datum.data.string = "fail";
65 sdb_plugin_store_attribute("h1", "k2", &datum, 1);
66 sdb_plugin_store_attribute("h1", "k3", &datum, 2);
68 sdb_plugin_store_metric("h1", "m1", /* store */ NULL, 2);
69 sdb_plugin_store_metric("h1", "m2", /* store */ NULL, 1);
70 sdb_plugin_store_metric("h2", "m1", /* store */ NULL, 1);
72 sdb_plugin_store_service("h2", "s1", 1);
73 sdb_plugin_store_service("h2", "s2", 2);
75 datum.type = SDB_TYPE_INTEGER;
76 datum.data.integer = 42;
77 sdb_plugin_store_metric_attribute("h1", "m1", "k3", &datum, 2);
79 datum.data.integer = 123;
80 sdb_plugin_store_service_attribute("h2", "s2", "k1", &datum, 2);
81 datum.data.integer = 4711;
82 sdb_plugin_store_service_attribute("h2", "s2", "k2", &datum, 1);
84 /* don't overwrite k1 */
85 datum.data.integer = 666;
86 sdb_plugin_store_service_attribute("h2", "s2", "k1", &datum, 2);
87 } /* populate */
89 START_TEST(test_store_host)
90 {
91 struct {
92 const char *name;
93 sdb_time_t last_update;
94 int expected;
95 } golden_data[] = {
96 { "a", 1, 0 },
97 { "a", 2, 0 },
98 { "a", 1, 1 },
99 { "b", 1, 0 },
100 { "b", 1, 1 },
101 { "A", 1, 1 }, /* case-insensitive */
102 { "A", 3, 0 },
103 };
105 struct {
106 const char *name;
107 _Bool has;
108 } golden_hosts[] = {
109 { "a", 1 == 1 },
110 { "b", 1 == 1 },
111 { "c", 0 == 1 },
112 { "A", 1 == 1 },
113 };
115 size_t i;
117 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
118 int status;
120 status = sdb_plugin_store_host(golden_data[i].name,
121 golden_data[i].last_update);
122 fail_unless(status == golden_data[i].expected,
123 "sdb_plugin_store_host(%s, %d) = %d; expected: %d",
124 golden_data[i].name, (int)golden_data[i].last_update,
125 status, golden_data[i].expected);
126 }
128 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
129 _Bool has;
131 has = sdb_store_has_host(golden_hosts[i].name);
132 fail_unless(has == golden_hosts[i].has,
133 "sdb_store_has_host(%s) = %d; expected: %d",
134 golden_hosts[i].name, has, golden_hosts[i].has);
135 }
136 }
137 END_TEST
139 START_TEST(test_store_get_host)
140 {
141 char *golden_hosts[] = { "a", "b", "c" };
142 char *unknown_hosts[] = { "x", "y", "z" };
143 size_t i;
145 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
146 int status = sdb_plugin_store_host(golden_hosts[i], 1);
147 fail_unless(status >= 0,
148 "sdb_plugin_store_host(%s) = %d; expected: >=0",
149 golden_hosts[i], status);
150 }
152 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
153 sdb_store_obj_t *sobj1, *sobj2;
154 int ref_cnt;
156 fail_unless(sdb_store_has_host(golden_hosts[i]),
157 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
158 golden_hosts[i]);
160 sobj1 = sdb_store_get_host(golden_hosts[i]);
161 fail_unless(sobj1 != NULL,
162 "sdb_store_get_host(%s) = NULL; expected: <host>",
163 golden_hosts[i]);
164 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
166 fail_unless(ref_cnt > 1,
167 "sdb_store_get_host(%s) did not increment ref count: "
168 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
170 sobj2 = sdb_store_get_host(golden_hosts[i]);
171 fail_unless(sobj2 != NULL,
172 "sdb_store_get_host(%s) = NULL; expected: <host>",
173 golden_hosts[i]);
175 fail_unless(sobj1 == sobj2,
176 "sdb_store_get_host(%s) returned different objects "
177 "in successive calls", golden_hosts[i]);
178 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
179 "sdb_store_get_hosts(%s) did not increment ref count "
180 "(first call: %d; second call: %d)",
181 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
183 sdb_object_deref(SDB_OBJ(sobj1));
184 sdb_object_deref(SDB_OBJ(sobj2));
185 }
186 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
187 sdb_store_obj_t *sobj;
189 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
190 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
191 unknown_hosts[i]);
193 sobj = sdb_store_get_host(unknown_hosts[i]);
194 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
195 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
196 }
197 }
198 END_TEST
200 START_TEST(test_store_attr)
201 {
202 struct {
203 const char *host;
204 const char *key;
205 char *value;
206 sdb_time_t last_update;
207 int expected;
208 } golden_data[] = {
209 { "k", "k", "v", 1, -1 },
210 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
211 { "l", "k1", "v1", 1, 0 },
212 { "l", "k1", "v2", 2, 0 },
213 { "l", "k1", "v3", 2, 1 },
214 { "l", "k2", "v1", 1, 0 },
215 { "m", "k", "v1", 1, 0 },
216 { "m", "k", "v2", 1, 1 },
217 };
219 size_t i;
221 sdb_plugin_store_host("l", 1);
222 sdb_plugin_store_host("m", 1);
223 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
224 sdb_data_t datum;
225 int status;
227 /* XXX: test other types as well */
228 datum.type = SDB_TYPE_STRING;
229 datum.data.string = golden_data[i].value;
231 status = sdb_plugin_store_attribute(golden_data[i].host,
232 golden_data[i].key, &datum,
233 golden_data[i].last_update);
234 fail_unless(status == golden_data[i].expected,
235 "sdb_plugin_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
236 golden_data[i].host, golden_data[i].key, golden_data[i].value,
237 golden_data[i].last_update, status, golden_data[i].expected);
238 }
239 }
240 END_TEST
242 START_TEST(test_store_metric)
243 {
244 sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
245 sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
247 struct {
248 const char *host;
249 const char *metric;
250 sdb_metric_store_t *store;
251 sdb_time_t last_update;
252 int expected;
253 } golden_data[] = {
254 { "k", "m", NULL, 1, -1 },
255 { "k", "m", NULL, 1, -1 }, /* retry to ensure the host is not created */
256 { "k", "m", &store1, 1, -1 },
257 { "l", "m1", NULL, 1, 0 },
258 { "l", "m1", &store1, 2, 0 },
259 { "l", "m1", &store1, 3, 0 },
260 { "l", "m1", NULL, 3, 1 },
261 { "l", "m2", &store1, 1, 0 },
262 { "l", "m2", &store2, 2, 0 },
263 { "l", "m2", NULL, 3, 0 },
264 { "m", "m", &store1, 1, 0 },
265 { "m", "m", NULL, 2, 0 },
266 { "m", "m", NULL, 2, 1 },
267 { "m", "m", &store1, 3, 0 },
268 { "m", "m", &store2, 4, 0 },
269 { "m", "m", NULL, 5, 0 },
270 };
272 size_t i;
274 sdb_plugin_store_host("m", 1);
275 sdb_plugin_store_host("l", 1);
276 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
277 int status;
279 status = sdb_plugin_store_metric(golden_data[i].host,
280 golden_data[i].metric, golden_data[i].store,
281 golden_data[i].last_update);
282 fail_unless(status == golden_data[i].expected,
283 "sdb_plugin_store_metric(%s, %s, %p, %d) = %d; expected: %d",
284 golden_data[i].host, golden_data[i].metric,
285 golden_data[i].store, golden_data[i].last_update,
286 status, golden_data[i].expected);
287 }
288 }
289 END_TEST
291 START_TEST(test_store_metric_attr)
292 {
293 struct {
294 const char *host;
295 const char *metric;
296 const char *attr;
297 const sdb_data_t value;
298 sdb_time_t last_update;
299 int expected;
300 } golden_data[] = {
301 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
302 /* retry, it should still fail */
303 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
304 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
305 /* retry, it should still fail */
306 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
307 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
308 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
309 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
310 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
311 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
312 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
313 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
314 };
316 size_t i;
318 sdb_plugin_store_host("m", 1);
319 sdb_plugin_store_host("l", 1);
320 sdb_plugin_store_metric("m", "m1", NULL, 1);
321 sdb_plugin_store_metric("l", "m1", NULL, 1);
322 sdb_plugin_store_metric("l", "m2", NULL, 1);
324 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
325 int status;
327 status = sdb_plugin_store_metric_attribute(golden_data[i].host,
328 golden_data[i].metric, golden_data[i].attr,
329 &golden_data[i].value, golden_data[i].last_update);
330 fail_unless(status == golden_data[i].expected,
331 "sdb_plugin_store_metric_attribute(%s, %s, %s, %d, %d) = %d; "
332 "expected: %d", golden_data[i].host, golden_data[i].metric,
333 golden_data[i].attr, golden_data[i].value.data.integer,
334 golden_data[i].last_update, status, golden_data[i].expected);
335 }
336 }
337 END_TEST
339 START_TEST(test_store_service)
340 {
341 struct {
342 const char *host;
343 const char *svc;
344 sdb_time_t last_update;
345 int expected;
346 } golden_data[] = {
347 { "k", "s", 1, -1 },
348 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
349 { "l", "s1", 1, 0 },
350 { "l", "s1", 2, 0 },
351 { "l", "s1", 2, 1 },
352 { "l", "s2", 1, 0 },
353 { "m", "s", 1, 0 },
354 { "m", "s", 1, 1 },
355 };
357 size_t i;
359 sdb_plugin_store_host("m", 1);
360 sdb_plugin_store_host("l", 1);
361 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
362 int status;
364 status = sdb_plugin_store_service(golden_data[i].host,
365 golden_data[i].svc, golden_data[i].last_update);
366 fail_unless(status == golden_data[i].expected,
367 "sdb_plugin_store_service(%s, %s, %d) = %d; expected: %d",
368 golden_data[i].host, golden_data[i].svc,
369 golden_data[i].last_update, status, golden_data[i].expected);
370 }
371 }
372 END_TEST
374 START_TEST(test_store_service_attr)
375 {
376 struct {
377 const char *host;
378 const char *svc;
379 const char *attr;
380 const sdb_data_t value;
381 sdb_time_t last_update;
382 int expected;
383 } golden_data[] = {
384 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
385 /* retry, it should still fail */
386 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
387 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
388 /* retry, it should still fail */
389 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
390 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
391 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
392 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
393 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
394 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
395 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
396 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
397 };
399 size_t i;
401 sdb_plugin_store_host("m", 1);
402 sdb_plugin_store_host("l", 1);
403 sdb_plugin_store_service("m", "s1", 1);
404 sdb_plugin_store_service("l", "s1", 1);
405 sdb_plugin_store_service("l", "s2", 1);
407 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
408 int status;
410 status = sdb_plugin_store_service_attribute(golden_data[i].host,
411 golden_data[i].svc, golden_data[i].attr,
412 &golden_data[i].value, golden_data[i].last_update);
413 fail_unless(status == golden_data[i].expected,
414 "sdb_plugin_store_service_attribute(%s, %s, %s, %d, %d) = %d; "
415 "expected: %d", golden_data[i].host, golden_data[i].svc,
416 golden_data[i].attr, golden_data[i].value.data.integer,
417 golden_data[i].last_update, status, golden_data[i].expected);
418 }
419 }
420 END_TEST
422 static struct {
423 const char *hostname;
424 const char *attr; /* optional */
425 int field;
426 int expected;
427 sdb_data_t value;
428 } get_field_data[] = {
429 { NULL, NULL, 0, -1, { SDB_TYPE_NULL, { 0 } } },
430 { NULL, NULL, SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
431 { NULL, NULL, SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
432 { NULL, NULL, SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
433 { NULL, NULL, SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
434 { NULL, NULL, SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
435 { NULL, NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
436 { "host", NULL, SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
437 { "host", NULL, SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
438 /* the test will handle AGE specially */
439 { "host", NULL, SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
440 { "host", NULL, SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "host" } } },
441 { "host", NULL, SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
442 { "host", NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
443 { "host", "attr", SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
444 { "host", "attr", SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
445 /* the test will handle AGE specially */
446 { "host", "attr", SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
447 { "host", "attr", SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "attr" } } },
448 { "host", "attr", SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
449 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_INTEGER, { .integer = 1 } } },
450 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } } },
451 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_STRING, { .string = "foo" } } },
452 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DATETIME, { .datetime = 1234567890L } } },
453 { "host", "a", SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
454 { "host", "a", SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
455 { "host", "a", SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
456 { "host", "a", SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
457 { "host", "a", SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
458 { "host", "a", SDB_FIELD_VALUE, -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 };
464 /* returns a tuple <type> <name> */
465 #define OBJ_NAME(obj) \
466 (obj) ? SDB_STORE_TYPE_TO_NAME(obj->type) : "NULL", \
467 (obj) ? SDB_OBJ(obj)->name : ""
468 START_TEST(test_get_field)
469 {
470 sdb_store_obj_t *obj = NULL;
471 sdb_data_t value = SDB_DATA_INIT;
472 char value_str[128], expected_value_str[128];
473 sdb_time_t now = sdb_gettime();
474 int check;
476 sdb_plugin_store_host("host", 10);
477 sdb_plugin_store_host("host", 20);
478 sdb_plugin_store_attribute("host", "attr", &get_field_data[_i].value, 10);
479 sdb_plugin_store_attribute("host", "attr", &get_field_data[_i].value, 20);
481 if (get_field_data[_i].hostname) {
482 obj = sdb_store_get_host(get_field_data[_i].hostname);
483 ck_assert(obj != NULL);
485 if (get_field_data[_i].attr) {
486 sdb_store_obj_t *tmp = sdb_store_get_child(obj,
487 SDB_ATTRIBUTE, get_field_data[_i].attr);
488 sdb_object_deref(SDB_OBJ(obj));
489 obj = tmp;
490 }
491 }
493 check = sdb_store_get_field(obj, get_field_data[_i].field, NULL);
494 fail_unless(check == get_field_data[_i].expected,
495 "sdb_store_get_field(%s %s, %s, NULL) = %d; expected: %d",
496 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
497 check, get_field_data[_i].expected);
498 check = sdb_store_get_field(obj, get_field_data[_i].field, &value);
499 fail_unless(check == get_field_data[_i].expected,
500 "sdb_store_get_field(%s %s, %s, <value>) = %d; expected: %d",
501 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
502 check, get_field_data[_i].expected);
504 if (get_field_data[_i].expected) {
505 sdb_object_deref(SDB_OBJ(obj));
506 return;
507 }
509 if (get_field_data[_i].field == SDB_FIELD_AGE) {
510 get_field_data[_i].value.type = SDB_TYPE_DATETIME;
511 get_field_data[_i].value.data.datetime = now;
512 }
514 sdb_data_format(&value, value_str, sizeof(value_str), 0);
515 sdb_data_format(&get_field_data[_i].value, expected_value_str,
516 sizeof(expected_value_str), 0);
518 if (get_field_data[_i].field == SDB_FIELD_AGE) {
519 fail_unless((value.type == SDB_TYPE_DATETIME)
520 && (value.data.datetime >= now),
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 else {
527 fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
528 "sdb_store_get_field(%s %s, %s, <value>) "
529 "returned value %s; expected %s", OBJ_NAME(obj),
530 SDB_FIELD_TO_NAME(get_field_data[_i].field),
531 value_str, expected_value_str);
532 }
533 sdb_data_free_datum(&value);
534 sdb_object_deref(SDB_OBJ(obj));
535 }
536 END_TEST
537 #undef OBJ_NAME
539 START_TEST(test_get_child)
540 {
541 struct {
542 const char *host;
543 const char *name;
544 int type;
545 int expected;
546 } golden_data[] = {
547 { "h1", NULL, SDB_HOST, 0 },
548 { "h1", NULL, SDB_SERVICE, -1 },
549 { "h1", NULL, SDB_METRIC, -1 },
550 { "h1", NULL, SDB_ATTRIBUTE, -1 },
551 { "h2", NULL, SDB_HOST, 0 },
552 { "h2", NULL, SDB_SERVICE, -1 },
553 { "h2", NULL, SDB_METRIC, -1 },
554 { "h2", NULL, SDB_ATTRIBUTE, -1 },
555 { "h3", NULL, SDB_HOST, -1 },
556 { "h1", "k1", SDB_ATTRIBUTE, 0 },
557 { "h1", "x1", SDB_ATTRIBUTE, -1 },
558 { "h2", "k1", SDB_ATTRIBUTE, -1 },
559 { "h1", "k1", SDB_SERVICE, -1 },
560 { "h1", "k1", SDB_METRIC, -1 },
561 { "h1", "s1", SDB_SERVICE, -1 },
562 { "h2", "s1", SDB_SERVICE, 0 },
563 { "h1", "m2", SDB_METRIC, 0 },
564 { "h2", "m2", SDB_METRIC, -1 },
565 };
567 size_t i;
569 populate();
571 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
572 sdb_store_obj_t *obj;
573 const char *expected_name = golden_data[i].host;
575 obj = sdb_store_get_host(golden_data[i].host);
576 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
577 fail_unless(obj == NULL,
578 "sdb_store_get_host(%s) = %p; expected: NULL",
579 golden_data[i].host, obj);
580 else
581 fail_unless(obj != NULL,
582 "sdb_store_get_host(%s) = NULL; expected: <host>",
583 golden_data[i].host);
585 if (golden_data[i].type != SDB_HOST) {
586 sdb_store_obj_t *tmp;
588 expected_name = golden_data[i].name;
590 tmp = sdb_store_get_child(obj,
591 golden_data[i].type, golden_data[i].name);
592 if (golden_data[i].expected)
593 fail_unless(tmp == NULL,
594 "sdb_store_get_child(<%s>, %s, %s) = %p; "
595 "expected: NULL", golden_data[i].host,
596 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
597 golden_data[i].name, tmp);
598 else
599 fail_unless(tmp != NULL,
600 "sdb_store_get_child(<%s>, %s, %s) = NULL; "
601 "expected: <obj>", golden_data[i].host,
602 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
603 golden_data[i].name);
605 sdb_object_deref(SDB_OBJ(obj));
606 obj = tmp;
607 }
609 if (golden_data[i].expected)
610 continue;
612 fail_unless(obj->type == golden_data[i].type,
613 "sdb_store_get_<%s>(%s, %s) returned object of type %d; "
614 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
615 golden_data[i].host, golden_data[i].name, obj->type,
616 golden_data[i].type);
617 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
618 "sdb_store_get_<%s>(%s, %s) returned object named '%s'; "
619 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
620 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
621 expected_name);
623 sdb_object_deref(SDB_OBJ(obj));
624 }
625 }
626 END_TEST
628 START_TEST(test_interval)
629 {
630 sdb_store_obj_t *host;
632 /* 10 us interval */
633 sdb_plugin_store_host("host", 10);
634 sdb_plugin_store_host("host", 20);
635 sdb_plugin_store_host("host", 30);
636 sdb_plugin_store_host("host", 40);
638 host = sdb_store_get_host("host");
639 fail_unless(host != NULL,
640 "INTERNAL ERROR: store doesn't have host after adding it");
642 fail_unless(host->interval == 10,
643 "sdb_plugin_store_host() did not calculate interval correctly: "
644 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
646 /* multiple updates for the same timestamp don't modify the interval */
647 sdb_plugin_store_host("host", 40);
648 sdb_plugin_store_host("host", 40);
649 sdb_plugin_store_host("host", 40);
650 sdb_plugin_store_host("host", 40);
652 fail_unless(host->interval == 10,
653 "sdb_plugin_store_host() changed interval when doing multiple updates "
654 "using the same timestamp; got: %"PRIsdbTIME"; "
655 "expected: %"PRIsdbTIME, host->interval, 10);
657 /* multiple updates using an timestamp don't modify the interval */
658 sdb_plugin_store_host("host", 20);
659 sdb_plugin_store_host("host", 20);
660 sdb_plugin_store_host("host", 20);
661 sdb_plugin_store_host("host", 20);
663 fail_unless(host->interval == 10,
664 "sdb_plugin_store_host() changed interval when doing multiple updates "
665 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
666 host->interval, 10);
668 /* new interval: 20 us */
669 sdb_plugin_store_host("host", 60);
670 fail_unless(host->interval == 11,
671 "sdb_plugin_store_host() did not calculate interval correctly: "
672 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
674 /* new interval: 40 us */
675 sdb_plugin_store_host("host", 100);
676 fail_unless(host->interval == 13,
677 "sdb_plugin_store_host() did not calculate interval correctly: "
678 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
680 sdb_object_deref(SDB_OBJ(host));
681 }
682 END_TEST
684 static int
685 scan_count(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
686 {
687 intptr_t *i = user_data;
689 if (! sdb_store_matcher_matches(filter, obj, NULL))
690 return 0;
692 fail_unless(obj != NULL,
693 "sdb_store_scan callback received NULL obj; expected: "
694 "<store base obj>");
695 fail_unless(i != NULL,
696 "sdb_store_scan callback received NULL user_data; "
697 "expected: <pointer to data>");
699 ++(*i);
700 return 0;
701 } /* scan_count */
703 static int
704 scan_error(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
705 {
706 intptr_t *i = user_data;
708 if (! sdb_store_matcher_matches(filter, obj, NULL))
709 return 0;
711 fail_unless(obj != NULL,
712 "sdb_store_scan callback received NULL obj; expected: "
713 "<store base obj>");
714 fail_unless(i != NULL,
715 "sdb_store_scan callback received NULL user_data; "
716 "expected: <pointer to data>");
718 ++(*i);
719 return -1;
720 } /* scan_error */
722 START_TEST(test_scan)
723 {
724 intptr_t i = 0;
725 int check;
727 /* empty store */
728 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
729 scan_count, &i);
730 fail_unless(check == 0,
731 "sdb_store_scan(HOST), empty store = %d; expected: 0", check);
732 fail_unless(i == 0,
733 "sdb_store_scan(HOST) called callback %d times; "
734 "expected: 0", (int)i);
736 populate();
738 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
739 scan_count, &i);
740 fail_unless(check == 0,
741 "sdb_store_scan(HOST) = %d; expected: 0", check);
742 fail_unless(i == 2,
743 "sdb_store_scan(HOST) called callback %d times; "
744 "expected: 1", (int)i);
746 i = 0;
747 check = sdb_store_scan(SDB_HOST, /* m, filter = */ NULL, NULL,
748 scan_error, &i);
749 fail_unless(check == -1,
750 "sdb_store_scan(HOST), error callback = %d; expected: -1", check);
751 fail_unless(i == 1,
752 "sdb_store_scan(HOST) called callback %d times "
753 "(callback returned error); expected: 1", (int)i);
755 i = 0;
756 check = sdb_store_scan(SDB_SERVICE, /* m, filter = */ NULL, NULL,
757 scan_count, &i);
758 fail_unless(check == 0,
759 "sdb_store_scan(SERVICE) = %d; expected: 0", check);
760 fail_unless(i == 2,
761 "sdb_store_scan(SERVICE) called callback %d times; "
762 "expected: 2", (int)i);
764 i = 0;
765 check = sdb_store_scan(SDB_METRIC, /* m, filter = */ NULL, NULL,
766 scan_count, &i);
767 fail_unless(check == 0,
768 "sdb_store_scan(METRIC) = %d; expected: 0", check);
769 fail_unless(i == 3,
770 "sdb_store_scan(METRIC) called callback %d times; "
771 "expected: 3", (int)i);
772 }
773 END_TEST
775 TEST_MAIN("core::store")
776 {
777 TCase *tc = tcase_create("core");
778 tcase_add_test(tc, test_store_host);
779 tcase_add_test(tc, test_store_get_host);
780 tcase_add_test(tc, test_store_attr);
781 tcase_add_test(tc, test_store_metric);
782 tcase_add_test(tc, test_store_metric_attr);
783 tcase_add_test(tc, test_store_service);
784 tcase_add_test(tc, test_store_service_attr);
785 TC_ADD_LOOP_TEST(tc, get_field);
786 tcase_add_test(tc, test_get_child);
787 tcase_add_test(tc, test_interval);
788 tcase_add_test(tc, test_scan);
789 tcase_add_unchecked_fixture(tc, init, sdb_store_clear);
790 ADD_TCASE(tc);
791 }
792 TEST_MAIN_END
794 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */