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/memstore-private.h"
35 #include "testutils.h"
37 #include <check.h>
38 #include <string.h>
39 #include <strings.h>
41 static sdb_memstore_t *store;
43 static void
44 init(void)
45 {
46 store = sdb_memstore_create();
47 ck_assert(store != NULL);
48 }
50 static void
51 populate(void)
52 {
53 sdb_data_t datum;
55 sdb_memstore_host(store, "h1", 1);
56 sdb_memstore_host(store, "h2", 3);
58 datum.type = SDB_TYPE_STRING;
59 datum.data.string = "v1";
60 sdb_memstore_attribute(store, "h1", "k1", &datum, 1);
61 datum.data.string = "v2";
62 sdb_memstore_attribute(store, "h1", "k2", &datum, 2);
63 datum.data.string = "v3";
64 sdb_memstore_attribute(store, "h1", "k3", &datum, 2);
66 /* make sure that older updates don't overwrite existing values */
67 datum.data.string = "fail";
68 sdb_memstore_attribute(store, "h1", "k2", &datum, 1);
69 sdb_memstore_attribute(store, "h1", "k3", &datum, 2);
71 sdb_memstore_metric(store, "h1", "m1", /* store */ NULL, 2);
72 sdb_memstore_metric(store, "h1", "m2", /* store */ NULL, 1);
73 sdb_memstore_metric(store, "h2", "m1", /* store */ NULL, 1);
75 sdb_memstore_service(store, "h2", "s1", 1);
76 sdb_memstore_service(store, "h2", "s2", 2);
78 datum.type = SDB_TYPE_INTEGER;
79 datum.data.integer = 42;
80 sdb_memstore_metric_attr(store, "h1", "m1", "k3", &datum, 2);
82 datum.data.integer = 123;
83 sdb_memstore_service_attr(store, "h2", "s2", "k1", &datum, 2);
84 datum.data.integer = 4711;
85 sdb_memstore_service_attr(store, "h2", "s2", "k2", &datum, 1);
87 /* don't overwrite k1 */
88 datum.data.integer = 666;
89 sdb_memstore_service_attr(store, "h2", "s2", "k1", &datum, 2);
90 } /* populate */
92 static void
93 turndown(void)
94 {
95 sdb_object_deref(SDB_OBJ(store));
96 store = NULL;
97 } /* turndown */
99 START_TEST(test_store_host)
100 {
101 struct {
102 const char *name;
103 sdb_time_t last_update;
104 int expected;
105 } golden_data[] = {
106 { "a", 1, 0 },
107 { "a", 2, 0 },
108 { "a", 1, 1 },
109 { "b", 1, 0 },
110 { "b", 1, 1 },
111 { "A", 1, 1 }, /* case-insensitive */
112 { "A", 3, 0 },
113 };
115 struct {
116 const char *name;
117 bool have;
118 } golden_hosts[] = {
119 { "a", 1 == 1 },
120 { "b", 1 == 1 },
121 { "c", 0 == 1 },
122 { "A", 1 == 1 },
123 };
125 size_t i;
127 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
128 int status;
130 status = sdb_memstore_host(store, golden_data[i].name,
131 golden_data[i].last_update);
132 fail_unless(status == golden_data[i].expected,
133 "sdb_memstore_host(%s, %d) = %d; expected: %d",
134 golden_data[i].name, (int)golden_data[i].last_update,
135 status, golden_data[i].expected);
136 }
138 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
139 sdb_memstore_obj_t *have;
141 have = sdb_memstore_get_host(store, golden_hosts[i].name);
142 fail_unless((have != NULL) == golden_hosts[i].have,
143 "sdb_memstore_get_host(%s) = %p; expected: %s",
144 golden_hosts[i].name, have,
145 golden_hosts[i].have ? "<host>" : "NULL");
146 sdb_object_deref(SDB_OBJ(have));
147 }
148 }
149 END_TEST
151 START_TEST(test_store_get_host)
152 {
153 char *golden_hosts[] = { "a", "b", "c" };
154 char *unknown_hosts[] = { "x", "y", "z" };
155 size_t i;
157 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
158 int status = sdb_memstore_host(store, golden_hosts[i], 1);
159 fail_unless(status >= 0,
160 "sdb_memstore_host(%s) = %d; expected: >=0",
161 golden_hosts[i], status);
162 }
164 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
165 sdb_memstore_obj_t *sobj1, *sobj2;
166 int ref_cnt;
168 sobj1 = sdb_memstore_get_host(store, golden_hosts[i]);
169 fail_unless(sobj1 != NULL,
170 "sdb_memstore_get_host(%s) = NULL; expected: <host>",
171 golden_hosts[i]);
172 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
174 fail_unless(ref_cnt > 1,
175 "sdb_memstore_get_host(%s) did not increment ref count: "
176 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
178 sobj2 = sdb_memstore_get_host(store, golden_hosts[i]);
179 fail_unless(sobj2 != NULL,
180 "sdb_memstore_get_host(%s) = NULL; expected: <host>",
181 golden_hosts[i]);
183 fail_unless(sobj1 == sobj2,
184 "sdb_memstore_get_host(%s) returned different objects "
185 "in successive calls", golden_hosts[i]);
186 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
187 "sdb_memstore_get_hosts(%s) did not increment ref count "
188 "(first call: %d; second call: %d)",
189 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
191 sdb_object_deref(SDB_OBJ(sobj1));
192 sdb_object_deref(SDB_OBJ(sobj2));
193 }
194 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
195 sdb_memstore_obj_t *sobj;
197 sobj = sdb_memstore_get_host(store, unknown_hosts[i]);
198 fail_unless(!sobj, "sdb_memstore_get_host(%s) = <host:%s>; expected: NULL",
199 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
200 }
201 }
202 END_TEST
204 START_TEST(test_store_attr)
205 {
206 struct {
207 const char *host;
208 const char *key;
209 char *value;
210 sdb_time_t last_update;
211 int expected;
212 } golden_data[] = {
213 { "k", "k", "v", 1, -1 },
214 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
215 { "l", "k1", "v1", 1, 0 },
216 { "l", "k1", "v2", 2, 0 },
217 { "l", "k1", "v3", 2, 1 },
218 { "l", "k2", "v1", 1, 0 },
219 { "m", "k", "v1", 1, 0 },
220 { "m", "k", "v2", 1, 1 },
221 };
223 size_t i;
225 sdb_memstore_host(store, "l", 1);
226 sdb_memstore_host(store, "m", 1);
227 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
228 sdb_data_t datum;
229 int status;
231 /* XXX: test other types as well */
232 datum.type = SDB_TYPE_STRING;
233 datum.data.string = golden_data[i].value;
235 status = sdb_memstore_attribute(store, golden_data[i].host,
236 golden_data[i].key, &datum,
237 golden_data[i].last_update);
238 fail_unless(status == golden_data[i].expected,
239 "sdb_memstore_attribute(%s, %s, %s, %d) = %d; expected: %d",
240 golden_data[i].host, golden_data[i].key, golden_data[i].value,
241 golden_data[i].last_update, status, golden_data[i].expected);
242 }
243 }
244 END_TEST
246 START_TEST(test_store_metric)
247 {
248 sdb_metric_store_t store1 = { "dummy-type1", "dummy-id1" };
249 sdb_metric_store_t store2 = { "dummy-type2", "dummy-id2" };
251 struct {
252 const char *host;
253 const char *metric;
254 sdb_metric_store_t *store;
255 sdb_time_t last_update;
256 int expected;
257 } golden_data[] = {
258 { "k", "m", NULL, 1, -1 },
259 { "k", "m", NULL, 1, -1 }, /* retry to ensure the host is not created */
260 { "k", "m", &store1, 1, -1 },
261 { "l", "m1", NULL, 1, 0 },
262 { "l", "m1", &store1, 2, 0 },
263 { "l", "m1", &store1, 3, 0 },
264 { "l", "m1", NULL, 3, 1 },
265 { "l", "m2", &store1, 1, 0 },
266 { "l", "m2", &store2, 2, 0 },
267 { "l", "m2", NULL, 3, 0 },
268 { "m", "m", &store1, 1, 0 },
269 { "m", "m", NULL, 2, 0 },
270 { "m", "m", NULL, 2, 1 },
271 { "m", "m", &store1, 3, 0 },
272 { "m", "m", &store2, 4, 0 },
273 { "m", "m", NULL, 5, 0 },
274 };
276 size_t i;
278 sdb_memstore_host(store, "m", 1);
279 sdb_memstore_host(store, "l", 1);
280 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
281 int status;
283 status = sdb_memstore_metric(store, golden_data[i].host,
284 golden_data[i].metric, golden_data[i].store,
285 golden_data[i].last_update);
286 fail_unless(status == golden_data[i].expected,
287 "sdb_memstore_metric(%s, %s, %p, %d) = %d; expected: %d",
288 golden_data[i].host, golden_data[i].metric,
289 golden_data[i].store, golden_data[i].last_update,
290 status, golden_data[i].expected);
291 }
292 }
293 END_TEST
295 START_TEST(test_store_metric_attr)
296 {
297 struct {
298 const char *host;
299 const char *metric;
300 const char *attr;
301 const sdb_data_t value;
302 sdb_time_t last_update;
303 int expected;
304 } golden_data[] = {
305 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
306 /* retry, it should still fail */
307 { "k", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
308 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
309 /* retry, it should still fail */
310 { "l", "mX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
311 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
312 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
313 { "l", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
314 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
315 { "l", "m1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
316 { "l", "m2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
317 { "m", "m1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
318 };
320 size_t i;
322 sdb_memstore_host(store, "m", 1);
323 sdb_memstore_host(store, "l", 1);
324 sdb_memstore_metric(store, "m", "m1", NULL, 1);
325 sdb_memstore_metric(store, "l", "m1", NULL, 1);
326 sdb_memstore_metric(store, "l", "m2", NULL, 1);
328 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
329 int status;
331 status = sdb_memstore_metric_attr(store, golden_data[i].host,
332 golden_data[i].metric, golden_data[i].attr,
333 &golden_data[i].value, golden_data[i].last_update);
334 fail_unless(status == golden_data[i].expected,
335 "sdb_memstore_metric_attr(%s, %s, %s, %d, %d) = %d; "
336 "expected: %d", golden_data[i].host, golden_data[i].metric,
337 golden_data[i].attr, golden_data[i].value.data.integer,
338 golden_data[i].last_update, status, golden_data[i].expected);
339 }
340 }
341 END_TEST
343 START_TEST(test_store_service)
344 {
345 struct {
346 const char *host;
347 const char *svc;
348 sdb_time_t last_update;
349 int expected;
350 } golden_data[] = {
351 { "k", "s", 1, -1 },
352 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
353 { "l", "s1", 1, 0 },
354 { "l", "s1", 2, 0 },
355 { "l", "s1", 2, 1 },
356 { "l", "s2", 1, 0 },
357 { "m", "s", 1, 0 },
358 { "m", "s", 1, 1 },
359 };
361 size_t i;
363 sdb_memstore_host(store, "m", 1);
364 sdb_memstore_host(store, "l", 1);
365 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
366 int status;
368 status = sdb_memstore_service(store, golden_data[i].host,
369 golden_data[i].svc, golden_data[i].last_update);
370 fail_unless(status == golden_data[i].expected,
371 "sdb_memstore_service(%s, %s, %d) = %d; expected: %d",
372 golden_data[i].host, golden_data[i].svc,
373 golden_data[i].last_update, status, golden_data[i].expected);
374 }
375 }
376 END_TEST
378 START_TEST(test_store_service_attr)
379 {
380 struct {
381 const char *host;
382 const char *svc;
383 const char *attr;
384 const sdb_data_t value;
385 sdb_time_t last_update;
386 int expected;
387 } golden_data[] = {
388 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
389 /* retry, it should still fail */
390 { "k", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
391 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
392 /* retry, it should still fail */
393 { "l", "sX", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, -1 },
394 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
395 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
396 { "l", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 2, 0 },
397 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
398 { "l", "s1", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 1 },
399 { "l", "s2", "a2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
400 { "m", "s1", "a1", { SDB_TYPE_INTEGER, { .integer = 123 } }, 1, 0 },
401 };
403 size_t i;
405 sdb_memstore_host(store, "m", 1);
406 sdb_memstore_host(store, "l", 1);
407 sdb_memstore_service(store, "m", "s1", 1);
408 sdb_memstore_service(store, "l", "s1", 1);
409 sdb_memstore_service(store, "l", "s2", 1);
411 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
412 int status;
414 status = sdb_memstore_service_attr(store, golden_data[i].host,
415 golden_data[i].svc, golden_data[i].attr,
416 &golden_data[i].value, golden_data[i].last_update);
417 fail_unless(status == golden_data[i].expected,
418 "sdb_memstore_service_attr(%s, %s, %s, %d, %d) = %d; "
419 "expected: %d", golden_data[i].host, golden_data[i].svc,
420 golden_data[i].attr, golden_data[i].value.data.integer,
421 golden_data[i].last_update, status, golden_data[i].expected);
422 }
423 }
424 END_TEST
426 static struct {
427 const char *hostname;
428 const char *attr; /* optional */
429 int field;
430 int expected;
431 sdb_data_t value;
432 } get_field_data[] = {
433 { NULL, NULL, 0, -1, { SDB_TYPE_NULL, { 0 } } },
434 { NULL, NULL, SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
435 { NULL, NULL, SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
436 { NULL, NULL, SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
437 { NULL, NULL, SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
438 { NULL, NULL, SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
439 { NULL, NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
440 { "host", NULL, SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
441 { "host", NULL, SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
442 /* the test will handle AGE specially */
443 { "host", NULL, SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
444 { "host", NULL, SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "host" } } },
445 { "host", NULL, SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
446 { "host", NULL, SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
447 { "host", "attr", SDB_FIELD_LAST_UPDATE, 0, { SDB_TYPE_DATETIME, { .datetime = 20 } } },
448 { "host", "attr", SDB_FIELD_INTERVAL, 0, { SDB_TYPE_DATETIME, { .datetime = 10 } } },
449 /* the test will handle AGE specially */
450 { "host", "attr", SDB_FIELD_AGE, 0, { SDB_TYPE_NULL, { 0 } } },
451 { "host", "attr", SDB_FIELD_NAME, 0, { SDB_TYPE_STRING, { .string = "attr" } } },
452 { "host", "attr", SDB_FIELD_BACKEND, 0, { SDB_TYPE_ARRAY | SDB_TYPE_STRING, { .array = { 0, NULL } } } },
453 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_INTEGER, { .integer = 1 } } },
454 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } } },
455 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_STRING, { .string = "foo" } } },
456 { "host", "attr", SDB_FIELD_VALUE, 0, { SDB_TYPE_DATETIME, { .datetime = 1234567890L } } },
457 { "host", "a", SDB_FIELD_LAST_UPDATE, -1, { SDB_TYPE_NULL, { 0 } } },
458 { "host", "a", SDB_FIELD_INTERVAL, -1, { SDB_TYPE_NULL, { 0 } } },
459 { "host", "a", SDB_FIELD_AGE, -1, { SDB_TYPE_NULL, { 0 } } },
460 { "host", "a", SDB_FIELD_NAME, -1, { SDB_TYPE_NULL, { 0 } } },
461 { "host", "a", SDB_FIELD_BACKEND, -1, { SDB_TYPE_NULL, { 0 } } },
462 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
463 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
464 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
465 { "host", "a", SDB_FIELD_VALUE, -1, { SDB_TYPE_NULL, { 0 } } },
466 };
468 /* returns a tuple <type> <name> */
469 #define OBJ_NAME(obj) \
470 (obj) ? SDB_STORE_TYPE_TO_NAME(obj->type) : "NULL", \
471 (obj) ? SDB_OBJ(obj)->name : ""
472 START_TEST(test_get_field)
473 {
474 sdb_memstore_obj_t *obj = NULL;
475 sdb_data_t value = SDB_DATA_INIT;
476 char value_str[128], expected_value_str[128];
477 sdb_time_t now = sdb_gettime();
478 int check;
480 sdb_memstore_host(store, "host", 10);
481 sdb_memstore_host(store, "host", 20);
482 sdb_memstore_attribute(store, "host", "attr", &get_field_data[_i].value, 10);
483 sdb_memstore_attribute(store, "host", "attr", &get_field_data[_i].value, 20);
485 if (get_field_data[_i].hostname) {
486 obj = sdb_memstore_get_host(store, get_field_data[_i].hostname);
487 ck_assert(obj != NULL);
489 if (get_field_data[_i].attr) {
490 sdb_memstore_obj_t *tmp = sdb_memstore_get_child(obj,
491 SDB_ATTRIBUTE, get_field_data[_i].attr);
492 sdb_object_deref(SDB_OBJ(obj));
493 obj = tmp;
494 }
495 }
497 check = sdb_memstore_get_field(obj, get_field_data[_i].field, NULL);
498 fail_unless(check == get_field_data[_i].expected,
499 "sdb_memstore_get_field(%s %s, %s, NULL) = %d; expected: %d",
500 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
501 check, get_field_data[_i].expected);
502 check = sdb_memstore_get_field(obj, get_field_data[_i].field, &value);
503 fail_unless(check == get_field_data[_i].expected,
504 "sdb_memstore_get_field(%s %s, %s, <value>) = %d; expected: %d",
505 OBJ_NAME(obj), SDB_FIELD_TO_NAME(get_field_data[_i].field),
506 check, get_field_data[_i].expected);
508 if (get_field_data[_i].expected) {
509 sdb_object_deref(SDB_OBJ(obj));
510 return;
511 }
513 if (get_field_data[_i].field == SDB_FIELD_AGE) {
514 get_field_data[_i].value.type = SDB_TYPE_DATETIME;
515 get_field_data[_i].value.data.datetime = now;
516 }
518 sdb_data_format(&value, value_str, sizeof(value_str), 0);
519 sdb_data_format(&get_field_data[_i].value, expected_value_str,
520 sizeof(expected_value_str), 0);
522 if (get_field_data[_i].field == SDB_FIELD_AGE) {
523 fail_unless((value.type == SDB_TYPE_DATETIME)
524 && (value.data.datetime >= now),
525 "sdb_memstore_get_field(%s %s, %s, <value>) "
526 "returned value %s; expected >=%s", OBJ_NAME(obj),
527 SDB_FIELD_TO_NAME(get_field_data[_i].field),
528 value_str, expected_value_str);
529 }
530 else {
531 fail_unless(! sdb_data_cmp(&value, &get_field_data[_i].value),
532 "sdb_memstore_get_field(%s %s, %s, <value>) "
533 "returned value %s; expected %s", OBJ_NAME(obj),
534 SDB_FIELD_TO_NAME(get_field_data[_i].field),
535 value_str, expected_value_str);
536 }
537 sdb_data_free_datum(&value);
538 sdb_object_deref(SDB_OBJ(obj));
539 }
540 END_TEST
541 #undef OBJ_NAME
543 START_TEST(test_get_child)
544 {
545 struct {
546 const char *host;
547 int parent_type;
548 const char *parent;
549 const char *name;
550 int type;
551 int expected;
552 } golden_data[] = {
553 { "h1", -1, NULL, NULL, SDB_HOST, 0 },
554 { "h1", -1, NULL, NULL, SDB_SERVICE, -1 },
555 { "h1", -1, NULL, NULL, SDB_METRIC, -1 },
556 { "h1", -1, NULL, NULL, SDB_ATTRIBUTE, -1 },
557 { "h2", -1, NULL, NULL, SDB_HOST, 0 },
558 { "h2", -1, NULL, NULL, SDB_SERVICE, -1 },
559 { "h2", -1, NULL, NULL, SDB_METRIC, -1 },
560 { "h2", -1, NULL, NULL, SDB_ATTRIBUTE, -1 },
561 { "h3", -1, NULL, NULL, SDB_HOST, -1 },
562 { "h1", -1, NULL, "k1", SDB_ATTRIBUTE, 0 },
563 { "h1", -1, NULL, "x1", SDB_ATTRIBUTE, -1 },
564 { "h2", -1, NULL, "k1", SDB_ATTRIBUTE, -1 },
565 { "h1", -1, NULL, "k1", SDB_SERVICE, -1 },
566 { "h1", -1, NULL, "k1", SDB_METRIC, -1 },
567 { "h1", -1, NULL, "s1", SDB_SERVICE, -1 },
568 { "h2", -1, NULL, "s1", SDB_SERVICE, 0 },
569 { "h1", -1, NULL, "m2", SDB_METRIC, 0 },
570 { "h2", -1, NULL, "m2", SDB_METRIC, -1 },
571 { "h1", SDB_METRIC, "m1", "k3", SDB_ATTRIBUTE, 0 },
572 { "h1", SDB_METRIC, "m1", "x1", SDB_ATTRIBUTE, -1 },
573 { "h2", SDB_SERVICE, "s2", "k1", SDB_ATTRIBUTE, 0 },
574 { "h2", SDB_SERVICE, "s2", "x1", SDB_ATTRIBUTE, -1 },
575 };
577 size_t i;
579 populate();
581 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
582 sdb_memstore_obj_t *obj;
583 const char *expected_name = golden_data[i].host;
585 obj = sdb_memstore_get_host(store, golden_data[i].host);
586 if (golden_data[i].parent) {
587 sdb_memstore_obj_t *o;
588 o = sdb_memstore_get_child(obj,
589 golden_data[i].parent_type, golden_data[i].parent);
590 sdb_object_deref(SDB_OBJ(obj));
591 obj = o;
592 }
593 if (golden_data[i].expected && (golden_data[i].type == SDB_HOST))
594 fail_unless(obj == NULL,
595 "sdb_memstore_get_host(%s) = %p; expected: NULL",
596 golden_data[i].host, obj);
597 else
598 fail_unless(obj != NULL,
599 "sdb_memstore_get_host(%s) = NULL; expected: <host>",
600 golden_data[i].host);
602 if (golden_data[i].type != SDB_HOST) {
603 sdb_memstore_obj_t *tmp;
605 expected_name = golden_data[i].name;
607 tmp = sdb_memstore_get_child(obj,
608 golden_data[i].type, golden_data[i].name);
609 if (golden_data[i].expected)
610 fail_unless(tmp == NULL,
611 "sdb_memstore_get_child(<%s>, %s, %s) = %p; "
612 "expected: NULL", golden_data[i].host,
613 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
614 golden_data[i].name, tmp);
615 else
616 fail_unless(tmp != NULL,
617 "sdb_memstore_get_child(<%s>, %s, %s) = NULL; "
618 "expected: <obj>", golden_data[i].host,
619 SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
620 golden_data[i].name);
622 sdb_object_deref(SDB_OBJ(obj));
623 obj = tmp;
624 }
626 if (golden_data[i].expected)
627 continue;
629 fail_unless(obj->type == golden_data[i].type,
630 "sdb_memstore_get_<%s>(%s, %s) returned object of type %d; "
631 "expected: %d", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
632 golden_data[i].host, golden_data[i].name, obj->type,
633 golden_data[i].type);
634 fail_unless(! strcasecmp(SDB_OBJ(obj)->name, expected_name),
635 "sdb_memstore_get_<%s>(%s, %s) returned object named '%s'; "
636 "expected: '%s'", SDB_STORE_TYPE_TO_NAME(golden_data[i].type),
637 golden_data[i].host, golden_data[i].name, SDB_OBJ(obj)->name,
638 expected_name);
640 sdb_object_deref(SDB_OBJ(obj));
641 }
642 }
643 END_TEST
645 START_TEST(test_interval)
646 {
647 sdb_memstore_obj_t *host;
649 /* 10 us interval */
650 sdb_memstore_host(store, "host", 10);
651 sdb_memstore_host(store, "host", 20);
652 sdb_memstore_host(store, "host", 30);
653 sdb_memstore_host(store, "host", 40);
655 host = sdb_memstore_get_host(store, "host");
656 fail_unless(host != NULL,
657 "INTERNAL ERROR: store doesn't have host after adding it");
659 fail_unless(host->interval == 10,
660 "sdb_memstore_host() did not calculate interval correctly: "
661 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 10);
663 /* multiple updates for the same timestamp don't modify the interval */
664 sdb_memstore_host(store, "host", 40);
665 sdb_memstore_host(store, "host", 40);
666 sdb_memstore_host(store, "host", 40);
667 sdb_memstore_host(store, "host", 40);
669 fail_unless(host->interval == 10,
670 "sdb_memstore_host() changed interval when doing multiple updates "
671 "using the same timestamp; got: %"PRIsdbTIME"; "
672 "expected: %"PRIsdbTIME, host->interval, 10);
674 /* multiple updates using an timestamp don't modify the interval */
675 sdb_memstore_host(store, "host", 20);
676 sdb_memstore_host(store, "host", 20);
677 sdb_memstore_host(store, "host", 20);
678 sdb_memstore_host(store, "host", 20);
680 fail_unless(host->interval == 10,
681 "sdb_memstore_host() changed interval when doing multiple updates "
682 "using an old timestamp; got: %"PRIsdbTIME"; expected: %"PRIsdbTIME,
683 host->interval, 10);
685 /* new interval: 20 us */
686 sdb_memstore_host(store, "host", 60);
687 fail_unless(host->interval == 11,
688 "sdb_memstore_host() did not calculate interval correctly: "
689 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
691 /* new interval: 40 us */
692 sdb_memstore_host(store, "host", 100);
693 fail_unless(host->interval == 13,
694 "sdb_memstore_host() did not calculate interval correctly: "
695 "got: %"PRIsdbTIME"; expected: %"PRIsdbTIME, host->interval, 11);
697 sdb_object_deref(SDB_OBJ(host));
698 }
699 END_TEST
701 static int
702 scan_count(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, void *user_data)
703 {
704 intptr_t *i = user_data;
706 if (! sdb_memstore_matcher_matches(filter, obj, NULL))
707 return 0;
709 fail_unless(obj != NULL,
710 "sdb_memstore_scan callback received NULL obj; expected: "
711 "<store base obj>");
712 fail_unless(i != NULL,
713 "sdb_memstore_scan callback received NULL user_data; "
714 "expected: <pointer to data>");
716 ++(*i);
717 return 0;
718 } /* scan_count */
720 static int
721 scan_error(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter, void *user_data)
722 {
723 intptr_t *i = user_data;
725 if (! sdb_memstore_matcher_matches(filter, obj, NULL))
726 return 0;
728 fail_unless(obj != NULL,
729 "sdb_memstore_scan callback received NULL obj; expected: "
730 "<store base obj>");
731 fail_unless(i != NULL,
732 "sdb_memstore_scan callback received NULL user_data; "
733 "expected: <pointer to data>");
735 ++(*i);
736 return -1;
737 } /* scan_error */
739 START_TEST(test_scan)
740 {
741 intptr_t i = 0;
742 int check;
744 /* empty store */
745 check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
746 scan_count, &i);
747 fail_unless(check == 0,
748 "sdb_memstore_scan(HOST), empty store = %d; expected: 0", check);
749 fail_unless(i == 0,
750 "sdb_memstore_scan(HOST) called callback %d times; "
751 "expected: 0", (int)i);
753 populate();
755 check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
756 scan_count, &i);
757 fail_unless(check == 0,
758 "sdb_memstore_scan(HOST) = %d; expected: 0", check);
759 fail_unless(i == 2,
760 "sdb_memstore_scan(HOST) called callback %d times; "
761 "expected: 1", (int)i);
763 i = 0;
764 check = sdb_memstore_scan(store, SDB_HOST, /* m, filter = */ NULL, NULL,
765 scan_error, &i);
766 fail_unless(check == -1,
767 "sdb_memstore_scan(HOST), error callback = %d; expected: -1", check);
768 fail_unless(i == 1,
769 "sdb_memstore_scan(HOST) called callback %d times "
770 "(callback returned error); expected: 1", (int)i);
772 i = 0;
773 check = sdb_memstore_scan(store, SDB_SERVICE, /* m, filter = */ NULL, NULL,
774 scan_count, &i);
775 fail_unless(check == 0,
776 "sdb_memstore_scan(SERVICE) = %d; expected: 0", check);
777 fail_unless(i == 2,
778 "sdb_memstore_scan(SERVICE) called callback %d times; "
779 "expected: 2", (int)i);
781 i = 0;
782 check = sdb_memstore_scan(store, SDB_METRIC, /* m, filter = */ NULL, NULL,
783 scan_count, &i);
784 fail_unless(check == 0,
785 "sdb_memstore_scan(METRIC) = %d; expected: 0", check);
786 fail_unless(i == 3,
787 "sdb_memstore_scan(METRIC) called callback %d times; "
788 "expected: 3", (int)i);
789 }
790 END_TEST
792 TEST_MAIN("core::store")
793 {
794 TCase *tc = tcase_create("core");
795 tcase_add_unchecked_fixture(tc, init, turndown);
796 tcase_add_test(tc, test_store_host);
797 tcase_add_test(tc, test_store_get_host);
798 tcase_add_test(tc, test_store_attr);
799 tcase_add_test(tc, test_store_metric);
800 tcase_add_test(tc, test_store_metric_attr);
801 tcase_add_test(tc, test_store_service);
802 tcase_add_test(tc, test_store_service_attr);
803 TC_ADD_LOOP_TEST(tc, get_field);
804 tcase_add_test(tc, test_get_child);
805 tcase_add_test(tc, test_interval);
806 tcase_add_test(tc, test_scan);
807 ADD_TCASE(tc);
808 }
809 TEST_MAIN_END
811 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */