913e6b78a0905bb803a5d7073e3cc27c4a457904
1 /*
2 * SysDB - t/unit/core/store_lookup_test.c
3 * Copyright (C) 2014 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 "parser/parser.h"
35 #include "testutils.h"
37 #include <check.h>
38 #include <string.h>
40 static void
41 populate(void)
42 {
43 const char *hosts[] = { "a", "b", "c" };
45 struct {
46 const char *host;
47 const char *metric;
48 } metrics[] = {
49 { "a", "m1" },
50 { "b", "m1" },
51 { "b", "m2" },
52 };
54 struct {
55 const char *host;
56 const char *service;
57 } services[] = {
58 { "a", "s1" },
59 { "a", "s2" },
60 { "b", "s1" },
61 { "b", "s3" },
62 };
64 struct {
65 const char *host;
66 const char *name;
67 sdb_data_t value;
68 } attrs[] = {
69 { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
70 { "a", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
71 { "b", "k1", { SDB_TYPE_STRING, { .string = "v2" } } },
72 };
74 size_t i;
76 sdb_store_init();
78 for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
79 int status = sdb_store_host(hosts[i], 1);
80 fail_unless(status == 0,
81 "sdb_store_host(%s, 1) = %d; expected: 0",
82 hosts[i], status);
83 }
85 for (i = 0; i < SDB_STATIC_ARRAY_LEN(metrics); ++i) {
86 int status = sdb_store_metric(metrics[i].host,
87 metrics[i].metric, /* store */ NULL, 1);
88 fail_unless(status == 0,
89 "sdb_store_metric(%s, %s, NULL, 1) = %d; expected: 0",
90 metrics[i].host, metrics[i].metric, status);
91 }
93 for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
94 int status = sdb_store_service(services[i].host,
95 services[i].service, 1);
96 fail_unless(status == 0,
97 "sdb_store_service(%s, %s, 1) = %d; expected: 0",
98 services[i].host, services[i].service, status);
99 }
101 for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
102 int status = sdb_store_attribute(attrs[i].host,
103 attrs[i].name, &attrs[i].value, 1);
104 fail_unless(status == 0,
105 "sdb_store_attribute(%s, %s, <val>, 1) = %d; expected: 0",
106 attrs[i].host, attrs[i].name, status);
107 }
108 } /* populate */
110 struct {
111 int type;
112 char *name;
113 _Bool re;
115 int expected;
116 } cmp_name_data[] = {
117 { SDB_HOST, "a", 0, 1 },
118 { SDB_HOST, "a", 1, 1 },
119 { SDB_HOST, "b", 0, 0 },
120 { SDB_HOST, "b", 1, 0 },
121 { SDB_HOST, "^a$", 1, 1 },
122 { SDB_HOST, "^b$", 1, 0 },
123 { SDB_HOST, "^a$", 0, 0 },
124 { SDB_HOST, "^b$", 0, 0 },
125 { SDB_METRIC, "m1", 0, 1 },
126 { SDB_METRIC, "m1", 1, 1 },
127 { SDB_METRIC, "^m1$", 1, 1 },
128 { SDB_METRIC, "m", 1, 1 },
129 { SDB_METRIC, "s", 1, 0 },
130 { SDB_METRIC, "m2", 0, 0 },
131 { SDB_METRIC, "x1", 0, 0 },
132 { SDB_METRIC, "x1", 1, 0 },
133 { SDB_SERVICE, "s1", 0, 1 },
134 { SDB_SERVICE, "s2", 0, 1 },
135 { SDB_SERVICE, "s3", 0, 0 },
136 { SDB_SERVICE, "s4", 0, 0 },
137 { SDB_SERVICE, "^s1$", 1, 1 },
138 { SDB_SERVICE, "^s1$", 0, 0 },
139 { SDB_SERVICE, "x1", 0, 0 },
140 { SDB_SERVICE, "x1", 1, 0 },
141 { SDB_SERVICE, "x", 1, 0 },
142 { SDB_ATTRIBUTE, "k1", 0, 1 },
143 { SDB_ATTRIBUTE, "k2", 0, 1 },
144 { SDB_ATTRIBUTE, "k3", 0, 0 },
145 { SDB_ATTRIBUTE, "k4", 0, 0 },
146 { SDB_ATTRIBUTE, "k", 1, 1 },
147 { SDB_ATTRIBUTE, "1", 1, 1 },
148 { SDB_ATTRIBUTE, "3", 1, 0 },
149 };
151 START_TEST(test_cmp_name)
152 {
153 sdb_store_obj_t *host;
154 sdb_data_t datum;
155 sdb_store_expr_t *obj = NULL, *value;
156 sdb_store_matcher_t *m, *n;
157 int status;
159 host = sdb_store_get_host("a");
160 fail_unless(host != NULL,
161 "sdb_store_get_host(a) = NULL; expected: <host>");
163 datum.type = SDB_TYPE_STRING;
164 datum.data.string = cmp_name_data[_i].name;
166 if (cmp_name_data[_i].type == SDB_HOST) {
167 obj = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
168 fail_unless(obj != NULL,
169 "sdb_store_expr_fieldvalue(SDB_STORE_NAME) = NULL; "
170 "expected: <expr>");
171 }
172 value = sdb_store_expr_constvalue(&datum);
173 fail_unless(value != NULL,
174 "sdb_store_expr_constvalue(%s) = NULL; "
175 "expected: <expr>", cmp_name_data[_i].name);
177 if (cmp_name_data[_i].re)
178 m = sdb_store_regex_matcher(obj, value);
179 else
180 m = sdb_store_eq_matcher(obj, value);
182 if (cmp_name_data[_i].type != SDB_HOST) {
183 sdb_store_expr_t *iter;
184 sdb_store_matcher_t *tmp;
185 obj = sdb_store_expr_fieldvalue(SDB_FIELD_NAME);
186 iter = sdb_store_expr_typed(cmp_name_data[_i].type, obj);
187 tmp = sdb_store_any_matcher(iter, m);
188 ck_assert(iter && m);
189 sdb_object_deref(SDB_OBJ(iter));
190 sdb_object_deref(SDB_OBJ(m));
191 m = tmp;
192 }
193 sdb_object_deref(SDB_OBJ(obj));
194 sdb_object_deref(SDB_OBJ(value));
195 fail_unless(m != NULL,
196 "sdb_store_%s_matcher(%s, %s) = NULL; "
197 "expected: <matcher>",
198 cmp_name_data[_i].re ? "regex" : "eq",
199 SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
200 cmp_name_data[_i].name);
202 status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
203 fail_unless(status == cmp_name_data[_i].expected,
204 "sdb_store_matcher_matches(%s->%s, <host a>, NULL) = %d; "
205 "expected: %d", SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
206 cmp_name_data[_i].name, status, cmp_name_data[_i].expected);
208 n = sdb_store_inv_matcher(m);
209 fail_unless(n != NULL,
210 "sdb_store_inv_matcher() = NULL; expected: <matcher>");
211 sdb_object_deref(SDB_OBJ(m));
213 /* now match the inverted set of objects */
214 status = sdb_store_matcher_matches(n, host, /* filter */ NULL);
215 fail_unless(status == !cmp_name_data[_i].expected,
216 "sdb_store_matcher_matches(%s->%s, <host a>, NULL) = %d; "
217 "expected: %d", SDB_STORE_TYPE_TO_NAME(cmp_name_data[_i].type),
218 cmp_name_data[_i].name, status, !cmp_name_data[_i].expected);
220 sdb_object_deref(SDB_OBJ(n));
221 sdb_object_deref(SDB_OBJ(host));
222 }
223 END_TEST
225 struct {
226 const char *attr;
227 const sdb_data_t value;
228 int expected_lt, expected_le, expected_eq, expected_ge, expected_gt;
229 } cmp_attr_data[] = {
230 { "k1", { SDB_TYPE_STRING, { .string = "v1" } }, 0, 1, 1, 1, 0 },
231 { "k1", { SDB_TYPE_STRING, { .string = "v2" } }, 1, 1, 0, 0, 0 },
232 { "k1", { SDB_TYPE_STRING, { .string = "v0" } }, 0, 0, 0, 1, 1 },
233 { "k1", { SDB_TYPE_STRING, { .string = "0" } }, 0, 0, 0, 1, 1 },
234 { "k2", { SDB_TYPE_INTEGER, { .integer = 123 } }, 0, 1, 1, 1, 0 },
235 { "k2", { SDB_TYPE_INTEGER, { .integer = 124 } }, 1, 1, 0, 0, 0 },
236 { "k2", { SDB_TYPE_INTEGER, { .integer = 122 } }, 0, 0, 0, 1, 1 },
237 /* key does not exist */
238 { "k3", { SDB_TYPE_STRING, { .string = "v1" } }, 0, 0, 0, 0, 0 },
239 { "k3", { SDB_TYPE_STRING, { .string = "123" } }, 0, 0, 0, 0, 0 },
240 { "k3", { SDB_TYPE_INTEGER, { .integer = 123 } }, 0, 0, 0, 0, 0 },
241 /* type mismatch */
242 { "k1", { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 1, 1 },
243 { "k2", { SDB_TYPE_STRING, { .string = "123" } }, 0, 1, 1, 1, 0 },
244 };
246 START_TEST(test_cmp_attr)
247 {
248 sdb_store_obj_t *host;
249 sdb_store_expr_t *attr;
250 sdb_store_expr_t *value;
251 char value_str[1024];
252 int status;
253 size_t j;
255 struct {
256 sdb_store_matcher_t *(*matcher)(sdb_store_expr_t *,
257 sdb_store_expr_t *);
258 int expected;
259 } tests[] = {
260 { sdb_store_lt_matcher, cmp_attr_data[_i].expected_lt },
261 { sdb_store_le_matcher, cmp_attr_data[_i].expected_le },
262 { sdb_store_eq_matcher, cmp_attr_data[_i].expected_eq },
263 { sdb_store_ge_matcher, cmp_attr_data[_i].expected_ge },
264 { sdb_store_gt_matcher, cmp_attr_data[_i].expected_gt },
265 };
267 const char *op_str[] = { "<", "<=", "=", ">=", ">" };
268 ck_assert(SDB_STATIC_ARRAY_LEN(tests) == SDB_STATIC_ARRAY_LEN(op_str));
270 host = sdb_store_get_host("a");
271 fail_unless(host != NULL,
272 "sdb_store_get_host(a) = NULL; expected: <host>");
274 sdb_data_format(&cmp_attr_data[_i].value,
275 value_str, sizeof(value_str), SDB_UNQUOTED);
277 attr = sdb_store_expr_attrvalue(cmp_attr_data[_i].attr);
278 fail_unless(attr != NULL,
279 "sdb_store_expr_attrvalue(%s) = NULL; expected: <expr>",
280 cmp_attr_data[_i].attr);
282 value = sdb_store_expr_constvalue(&cmp_attr_data[_i].value);
283 fail_unless(value != NULL,
284 "sdb_store_expr_constvalue(%s) = NULL; expected: <expr>",
285 value_str);
287 for (j = 0; j < SDB_STATIC_ARRAY_LEN(tests); ++j) {
288 sdb_store_matcher_t *m;
290 m = tests[j].matcher(attr, value);
291 fail_unless(m != NULL,
292 "sdb_store_<cond>_matcher() = NULL; expected: <matcher>");
294 status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
295 fail_unless(status == tests[j].expected,
296 "sdb_store_matcher_matches(<attr[%s] %s %s>, "
297 "<host>, NULL) = %d; expected: %d",
298 cmp_attr_data[_i].attr, op_str[j], value_str,
299 status, tests[j].expected);
301 sdb_object_deref(SDB_OBJ(m));
302 }
304 sdb_object_deref(SDB_OBJ(attr));
305 sdb_object_deref(SDB_OBJ(value));
306 sdb_object_deref(SDB_OBJ(host));
307 }
308 END_TEST
310 struct {
311 const char *host;
312 int field;
313 const sdb_data_t value;
314 int expected_lt, expected_le, expected_eq, expected_ge, expected_gt;
315 } cmp_obj_data[] = {
316 { "b", SDB_FIELD_NAME,
317 { SDB_TYPE_STRING, { .string = "a" } }, 0, 0, 0, 1, 1 },
318 { "b", SDB_FIELD_NAME,
319 { SDB_TYPE_STRING, { .string = "b" } }, 0, 1, 1, 1, 0 },
320 { "b", SDB_FIELD_NAME,
321 { SDB_TYPE_STRING, { .string = "c" } }, 1, 1, 0, 0, 0 },
322 /* last-update = 1 for all objects */
323 { "a", SDB_FIELD_LAST_UPDATE,
324 { SDB_TYPE_DATETIME, { .datetime = 1 } }, 0, 1, 1, 1, 0 },
325 { "a", SDB_FIELD_LAST_UPDATE,
326 { SDB_TYPE_DATETIME, { .datetime = 2 } }, 1, 1, 0, 0, 0 },
327 { "a", SDB_FIELD_LAST_UPDATE,
328 { SDB_TYPE_DATETIME, { .datetime = 0 } }, 0, 0, 0, 1, 1 },
329 /* age > 0 for all objects */
330 { "a", SDB_FIELD_AGE,
331 { SDB_TYPE_DATETIME, { .datetime = 0 } }, 0, 0, 0, 1, 1 },
332 /* interval = 0 for all objects */
333 { "a", SDB_FIELD_INTERVAL,
334 { SDB_TYPE_DATETIME, { .datetime = 0 } }, 0, 1, 1, 1, 0 },
335 { "a", SDB_FIELD_INTERVAL,
336 { SDB_TYPE_DATETIME, { .datetime = 1 } }, 1, 1, 0, 0, 0 },
337 /* type mismatch */
338 { "a", SDB_FIELD_LAST_UPDATE,
339 { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 0, 0 },
340 { "a", SDB_FIELD_AGE,
341 { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 0, 0 },
342 { "a", SDB_FIELD_INTERVAL,
343 { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 0, 0 },
344 { "a", SDB_FIELD_BACKEND,
345 { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 0, 0 },
346 { "a", SDB_FIELD_BACKEND,
347 { SDB_TYPE_INTEGER, { .integer = 0 } }, 0, 0, 0, 0, 0 },
348 /* (64bit) integer value without zero-bytes */
349 { "a", SDB_FIELD_BACKEND,
350 { SDB_TYPE_INTEGER, { .integer = 0xffffffffffffffffL } },
351 0, 0, 0, 0, 0 },
352 };
354 START_TEST(test_cmp_obj)
355 {
356 sdb_store_obj_t *host;
357 sdb_store_expr_t *field;
358 sdb_store_expr_t *value;
359 char value_str[1024];
360 int status;
361 size_t j;
363 struct {
364 sdb_store_matcher_t *(*matcher)(sdb_store_expr_t *,
365 sdb_store_expr_t *);
366 int expected;
367 } tests[] = {
368 { sdb_store_lt_matcher, cmp_obj_data[_i].expected_lt },
369 { sdb_store_le_matcher, cmp_obj_data[_i].expected_le },
370 { sdb_store_eq_matcher, cmp_obj_data[_i].expected_eq },
371 { sdb_store_ge_matcher, cmp_obj_data[_i].expected_ge },
372 { sdb_store_gt_matcher, cmp_obj_data[_i].expected_gt },
373 };
374 char *op_str[] = { "<", "<=", "=", ">=", ">" };
376 ck_assert(SDB_STATIC_ARRAY_LEN(tests) == SDB_STATIC_ARRAY_LEN(op_str));
378 host = sdb_store_get_host(cmp_obj_data[_i].host);
379 fail_unless(host != NULL,
380 "sdb_store_get_host(%s) = NULL; expected: <host>",
381 cmp_obj_data[_i].host);
383 sdb_data_format(&cmp_obj_data[_i].value,
384 value_str, sizeof(value_str), SDB_UNQUOTED);
386 field = sdb_store_expr_fieldvalue(cmp_obj_data[_i].field);
387 fail_unless(field != NULL,
388 "sdb_store_expr_fieldvalue(%d) = NULL; "
389 "expected: <expr>", cmp_obj_data[_i].field);
391 value = sdb_store_expr_constvalue(&cmp_obj_data[_i].value);
392 fail_unless(value != NULL,
393 "sdb_store_expr_constvalue(%s) = NULL; "
394 "expected: <expr>", value_str);
396 for (j = 0; j < SDB_STATIC_ARRAY_LEN(tests); ++j) {
397 char m_str[1024];
398 sdb_store_matcher_t *m;
400 snprintf(m_str, sizeof(m_str), "%s %s %s",
401 SDB_FIELD_TO_NAME(cmp_obj_data[_i].field),
402 op_str[j], value_str);
404 m = tests[j].matcher(field, value);
405 fail_unless(m != NULL,
406 "sdb_store_<cond>_matcher() = NULL; expected: <matcher>");
408 status = sdb_store_matcher_matches(m, host, /* filter */ NULL);
409 fail_unless(status == tests[j].expected,
410 "sdb_store_matcher_matches(<%s>, <host '%s'>, NULL) = %d; "
411 "expected: %d", m_str, cmp_obj_data[_i].host, status,
412 tests[j].expected);
414 sdb_object_deref(SDB_OBJ(m));
415 }
417 sdb_object_deref(SDB_OBJ(field));
418 sdb_object_deref(SDB_OBJ(value));
419 sdb_object_deref(SDB_OBJ(host));
420 }
421 END_TEST
423 START_TEST(test_store_match_op)
424 {
425 sdb_store_obj_t *obj;
427 sdb_data_t d = { SDB_TYPE_STRING, { .string = "a" } };
428 sdb_store_expr_t *e = sdb_store_expr_constvalue(&d);
430 sdb_store_matcher_t *never = sdb_store_isnull_matcher(e);
431 sdb_store_matcher_t *always = sdb_store_inv_matcher(never);
433 struct {
434 const char *op;
435 sdb_store_matcher_t *left;
436 sdb_store_matcher_t *right;
437 int expected;
438 } golden_data[] = {
439 { "OR", always, always, 1 },
440 { "OR", always, never, 1 },
441 { "OR", never, always, 1 },
442 { "OR", never, never, 0 },
443 { "AND", always, always, 1 },
444 { "AND", always, never, 0 },
445 { "AND", never, always, 0 },
446 { "AND", never, never, 0 },
447 };
449 int status;
450 size_t i;
452 obj = sdb_store_get_host("a");
454 status = sdb_store_matcher_matches(always, obj, /* filter */ NULL);
455 fail_unless(status == 1,
456 "INTERNAL ERROR: 'always' did not match host");
457 status = sdb_store_matcher_matches(never, obj, /* filter */ NULL);
458 fail_unless(status == 0,
459 "INTERNAL ERROR: 'never' matches host");
461 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
462 sdb_store_matcher_t *m;
464 if (! strcmp(golden_data[i].op, "OR"))
465 m = sdb_store_dis_matcher(golden_data[i].left,
466 golden_data[i].right);
467 else if (! strcmp(golden_data[i].op, "AND"))
468 m = sdb_store_con_matcher(golden_data[i].left,
469 golden_data[i].right);
470 else {
471 fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op);
472 continue;
473 }
475 #define TO_NAME(v) (((v) == always) ? "always" \
476 : ((v) == never) ? "never" : "<unknown>")
478 status = sdb_store_matcher_matches(m, obj, /* filter */ NULL);
479 fail_unless(status == golden_data[i].expected,
480 "%s(%s, %s, NULL) = %d; expected: %d", golden_data[i].op,
481 TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right),
482 status, golden_data[i].expected);
484 #undef TO_NAME
486 sdb_object_deref(SDB_OBJ(m));
487 }
489 sdb_object_deref(SDB_OBJ(always));
490 sdb_object_deref(SDB_OBJ(never));
491 sdb_object_deref(SDB_OBJ(e));
493 sdb_object_deref(SDB_OBJ(obj));
494 }
495 END_TEST
497 static int
498 scan_cb(sdb_store_obj_t *obj, sdb_store_matcher_t *filter, void *user_data)
499 {
500 int *i = user_data;
502 if (! sdb_store_matcher_matches(filter, obj, NULL))
503 return 0;
505 fail_unless(obj != NULL,
506 "sdb_store_scan callback received NULL obj; expected: "
507 "<store base obj>");
508 fail_unless(i != NULL,
509 "sdb_store_scan callback received NULL user_data; "
510 "expected: <pointer to data>");
512 ++(*i);
513 return 0;
514 } /* scan_cb */
516 struct {
517 const char *query;
518 const char *filter;
519 int expected;
520 } scan_data[] = {
521 /* TODO: check the name of the expected hosts */
522 { "name = 'a'", NULL, 1 },
523 { "name = 'a'", "name = 'x'", 0 }, /* filter never matches */
524 { "name = 'a'",
525 "NOT attribute['x'] = ''", 1 }, /* filter always matches */
526 { "name =~ 'a|b'", NULL, 2 },
527 { "name =~ 'host'", NULL, 0 },
528 { "name =~ '.'", NULL, 3 },
529 { "ANY backend = 'backend'", NULL, 0 },
530 { "ALL backend = ''", NULL, 3 }, /* backend is empty */
531 { "backend = ['backend']", NULL, 0 },
532 { "backend != ['backend']", NULL, 3 },
533 { "backend < ['backend']", NULL, 3 },
534 { "backend <= ['backend']", NULL, 3 },
535 { "backend >= ['backend']", NULL, 0 },
536 { "backend > ['backend']", NULL, 0 },
537 { "ANY metric.name = 'm1'", NULL, 2 },
538 { "ANY metric.name = 'm1'", "name = 'x'", 0 }, /* filter never matches */
539 { "ANY metric.name = 'm1'",
540 "NOT attribute['x'] = ''", 2 }, /* filter always matches */
541 { "ANY metric.name =~ 'm'", NULL, 2 },
542 { "ALL metric.name =~ 'm'", NULL, 3 },
543 { "ANY metric.name =~ 'm'", "name !~ '1'", 1 },
544 { "ANY metric.name =~ 'm'", "name !~ 'm'", 0 },
545 { "ALL metric.name =~ '1'", NULL, 2 },
546 { "ALL metric.name =~ '2'", NULL, 1 },
547 { "ANY metric.name !~ 'm'", NULL, 0 },
548 { "ALL metric.name !~ 'm'", NULL, 1 },
549 { "ANY metric.name =~ 'x'", NULL, 0 },
550 { "ANY service.name = 's1'", NULL, 2 },
551 { "ANY service.name = 's1'", "name = 'x'", 0 }, /* filter never matches */
552 { "ANY service.name = 's1'",
553 "NOT attribute['x'] = ''", 2 }, /* filter always matches */
554 { "ANY service.name =~ 's'", NULL, 2 },
555 { "ANY service.name =~ 's'", "name !~ 's'", 0 },
556 { "ANY service.name =~ 's'", "name !~ '1'", 2 },
557 { "ANY service.name !~ 's'", NULL, 0 },
558 { "ANY attribute.name = 'k1'", NULL, 2 },
559 { "ANY attribute.name = 'k1'", "name = 'x'", 0 }, /* filter never matches */
560 { "ANY attribute.name = 'k1'",
561 "NOT attribute['x'] = ''", 2 }, /* filter always matches */
562 { "ANY attribute.name =~ 'k'", NULL, 2 },
563 { "ANY attribute.name =~ 'k'",
564 "name !~ '1'", 1 },
565 { "ANY attribute.name =~ 'k'",
566 "name !~ 'k'", 0 },
567 { "ANY attribute.name =~ '1'", NULL, 2 },
568 { "ANY attribute.name =~ '2'", NULL, 1 },
569 { "ANY attribute.name = 'x'", NULL, 0 },
570 { "ANY attribute.name =~ 'x'", NULL, 0 },
571 { "ALL attribute.name = 'k1'", NULL, 2 },
572 { "ANY attribute.value = 'v1'", NULL, 1 },
573 { "ANY attribute.value =~ 'v'", NULL, 2 },
574 { "ANY attribute.value = 123", NULL, 1 },
575 { "host.name = 'a'", NULL, 1 },
576 { "host.attribute['k1'] =~ 'v1'",
577 NULL, 1 },
578 { "host.attribute['x1'] IS NULL",
579 NULL, 3 },
580 /* not a boolean so neither TRUE nor FALSE: */
581 { "attribute['k1'] IS TRUE", NULL, 0 },
582 { "attribute['k1'] IS FALSE", NULL, 0 },
583 { "attribute['k1'] = 'v1'", NULL, 1 },
584 { "attribute['k1'] = 'v1'",
585 "name != 'k1'", 0 },
586 { "attribute['k1'] =~ 'v1'", NULL, 1 },
587 { "attribute['k1'] =~ '^v1$'", NULL, 1 },
588 { "attribute['k1'] =~ 'v'", NULL, 2 },
589 { "attribute['k1'] =~ '1'", NULL, 1 },
590 { "attribute['k1'] !~ 'v'", NULL, 0 },
591 { "attribute['k1'] = 'v2'", NULL, 1 },
592 { "attribute['k1'] =~ 'v2'", NULL, 1 },
593 { "attribute['x1'] =~ 'v'", NULL, 0 },
594 { "attribute['x1'] =~ 'NULL'", NULL, 0 },
595 { "attribute['x1'] !~ 'v'", NULL, 0 },
596 { "attribute['k1'] IS NULL", NULL, 1 },
597 { "attribute['x1'] IS NULL", NULL, 3 },
598 { "attribute['k1'] IS TRUE", NULL, 0 },
599 { "attribute['x1'] IS TRUE", NULL, 0 },
600 { "attribute['k1'] IS FALSE", NULL, 0 },
601 { "attribute['x1'] IS FALSE", NULL, 0 },
602 { "attribute['k1'] IS NOT NULL", NULL, 2 },
603 { "attribute['x1'] IS NOT NULL", NULL, 0 },
604 { "attribute['x1'] IS NOT TRUE", NULL, 3 },
605 { "attribute['k2'] < 123", NULL, 0 },
606 { "attribute['k2'] <= 123", NULL, 1 },
607 { "attribute['k2'] >= 123", NULL, 1 },
608 { "attribute['k2'] > 123", NULL, 0 },
609 { "attribute['k2'] = 123", NULL, 1 },
610 { "attribute['k2'] != 123", NULL, 0 },
611 { "attribute['k1'] != 'v1'", NULL, 1 },
612 { "attribute['k1'] != 'v2'", NULL, 1 },
613 { "ANY attribute.name != 'x' "
614 "AND attribute['k1'] !~ 'x'", NULL, 2 },
615 };
617 START_TEST(test_scan)
618 {
619 sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
620 sdb_store_matcher_t *m, *filter = NULL;
621 sdb_ast_node_t *ast;
622 int check, n;
624 n = 0;
625 check = sdb_store_scan(SDB_HOST, /* matcher */ NULL, /* filter */ NULL,
626 scan_cb, &n);
627 fail_unless(check == 0,
628 "sdb_store_scan() = %d; expected: 0", check);
629 fail_unless(n == 3,
630 "sdb_store_scan called callback %d times; expected: 3", (int)n);
632 ast = sdb_parser_parse_conditional(scan_data[_i].query, -1, errbuf);
633 m = sdb_store_query_prepare_matcher(ast);
634 sdb_object_deref(SDB_OBJ(ast));
635 fail_unless(m != NULL,
636 "sdb_parser_parse_conditional(%s, -1) = NULL; expected: <ast> "
637 "(parser error: %s)", scan_data[_i].query,
638 sdb_strbuf_string(errbuf));
640 if (scan_data[_i].filter) {
641 ast = sdb_parser_parse_conditional(scan_data[_i].filter, -1, errbuf);
642 filter = sdb_store_query_prepare_matcher(ast);
643 sdb_object_deref(SDB_OBJ(ast));
644 fail_unless(filter != NULL,
645 "sdb_parser_parse_conditional(%s, -1) = NULL; "
646 "expected: <ast> (parser error: %s)",
647 scan_data[_i].filter, sdb_strbuf_string(errbuf));
648 }
650 n = 0;
651 sdb_store_scan(SDB_HOST, m, filter, scan_cb, &n);
652 fail_unless(n == scan_data[_i].expected,
653 "sdb_store_scan(HOST, matcher{%s}, filter{%s}) "
654 "found %d hosts; expected: %d", scan_data[_i].query,
655 scan_data[_i].filter, n, scan_data[_i].expected);
657 sdb_object_deref(SDB_OBJ(filter));
658 sdb_object_deref(SDB_OBJ(m));
659 sdb_strbuf_destroy(errbuf);
660 }
661 END_TEST
663 TEST_MAIN("core::store_lookup")
664 {
665 TCase *tc = tcase_create("core");
666 tcase_add_checked_fixture(tc, populate, sdb_store_clear);
667 TC_ADD_LOOP_TEST(tc, cmp_name);
668 TC_ADD_LOOP_TEST(tc, cmp_attr);
669 TC_ADD_LOOP_TEST(tc, cmp_obj);
670 TC_ADD_LOOP_TEST(tc, scan);
671 tcase_add_test(tc, test_store_match_op);
672 ADD_TCASE(tc);
673 }
674 TEST_MAIN_END
676 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */