1 /*
2 * SysDB - t/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 #include "core/store.h"
29 #include "core/store-private.h"
30 #include "libsysdb_test.h"
32 #include <check.h>
33 #include <string.h>
35 static void
36 populate(void)
37 {
38 const char *hosts[] = { "a", "b", "c" };
40 struct {
41 const char *host;
42 const char *service;
43 } services[] = {
44 { "a", "s1" },
45 { "a", "s2" },
46 { "b", "s1" },
47 { "b", "s3" },
48 };
50 struct {
51 const char *host;
52 const char *name;
53 sdb_data_t value;
54 } attrs[] = {
55 { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
56 };
58 size_t i;
60 for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
61 int status = sdb_store_host(hosts[i], 1);
62 fail_unless(status == 0,
63 "sdb_store_host(%s, 1) = %d; expected: 0",
64 hosts[i], status);
65 }
67 for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
68 int status = sdb_store_service(services[i].host,
69 services[i].service, 1);
70 fail_unless(status == 0,
71 "sdb_store_service(%s, %s, 1) = %d; expected: 0",
72 services[i].host, services[i].service, status);
73 }
75 for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
76 int status = sdb_store_attribute(attrs[i].host,
77 attrs[i].name, &attrs[i].value, 1);
78 fail_unless(status == 0,
79 "sdb_store_attribute(%s, %s, <val>, 1) = %d; expected: 0",
80 attrs[i].host, attrs[i].name, status);
81 }
82 } /* populate */
84 START_TEST(test_store_match)
85 {
86 sdb_store_base_t *obj;
88 struct {
89 const char *hostname;
90 const char *hostname_re;
92 const char *service_name;
93 const char *service_name_re;
95 const char *attr_name;
96 const char *attr_name_re;
97 const char *attr_value;
98 const char *attr_value_re;
100 int expected;
101 } golden_data[] = {
102 {
103 /* host */ NULL, NULL,
104 /* svc */ NULL, NULL,
105 /* attr */ NULL, NULL, NULL, NULL, 1
106 },
107 {
108 /* host */ "a", NULL,
109 /* svc */ NULL, NULL,
110 /* attr */ NULL, NULL, NULL, NULL, 1
111 },
112 {
113 /* host */ "b", NULL,
114 /* svc */ NULL, NULL,
115 /* attr */ NULL, NULL, NULL, NULL, 0
116 },
117 {
118 /* host */ NULL, "^a$",
119 /* svc */ NULL, NULL,
120 /* attr */ NULL, NULL, NULL, NULL, 1
121 },
122 {
123 /* host */ NULL, "^b$",
124 /* svc */ NULL, NULL,
125 /* attr */ NULL, NULL, NULL, NULL, 0
126 },
127 {
128 /* host */ "a", "^a$",
129 /* svc */ NULL, NULL,
130 /* attr */ NULL, NULL, NULL, NULL, 1
131 },
132 {
133 /* host */ "a", "^b$",
134 /* svc */ NULL, NULL,
135 /* attr */ NULL, NULL, NULL, NULL, 0
136 },
137 {
138 /* host */ "b", "^a$",
139 /* svc */ NULL, NULL,
140 /* attr */ NULL, NULL, NULL, NULL, 0
141 },
142 {
143 /* host */ "a", "^a$",
144 /* svc */ "s1", NULL,
145 /* attr */ NULL, NULL, NULL, NULL, 1
146 },
147 {
148 /* host */ "a", "^a$",
149 /* svc */ NULL, "^s1$",
150 /* attr */ NULL, NULL, NULL, NULL, 1
151 },
152 {
153 /* host */ "a", "^a$",
154 /* svc */ "s1", "^s1$",
155 /* attr */ NULL, NULL, NULL, NULL, 1
156 },
157 {
158 /* host */ "a", "^a$",
159 /* svc */ "x1", NULL,
160 /* attr */ NULL, NULL, NULL, NULL, 0
161 },
162 {
163 /* host */ "a", "^a$",
164 /* svc */ NULL, "x",
165 /* attr */ NULL, NULL, NULL, NULL, 0
166 },
167 {
168 /* host */ "a", "^a$",
169 /* svc */ "x1", "x",
170 /* attr */ NULL, NULL, NULL, NULL, 0
171 },
172 {
173 /* host */ "a", "^a$",
174 /* svc */ "s1", "x",
175 /* attr */ NULL, NULL, NULL, NULL, 0
176 },
177 {
178 /* host */ "a", "^a$",
179 /* svc */ "x1", "s",
180 /* attr */ NULL, NULL, NULL, NULL, 0
181 },
182 {
183 /* host */ "a", "^a$",
184 /* svc */ "s1", "^s1$",
185 /* attr */ "k1", NULL, NULL, NULL, 1
186 },
187 {
188 /* host */ "a", "^a$",
189 /* svc */ "s1", "^s1$",
190 /* attr */ NULL, "^k", NULL, NULL, 1
191 },
192 {
193 /* host */ "a", "^a$",
194 /* svc */ "s1", "^s1$",
195 /* attr */ NULL, NULL, "v1", NULL, 1
196 },
197 {
198 /* host */ "a", "^a$",
199 /* svc */ "s1", "^s1$",
200 /* attr */ NULL, NULL, NULL, "^v1$", 1
201 },
202 {
203 /* host */ "a", "^a$",
204 /* svc */ "s1", "^s1$",
205 /* attr */ "k1", "1", "v1", "1", 1
206 },
207 };
209 size_t i;
211 obj = sdb_store_get_host("a");
212 fail_unless(obj != NULL,
213 "sdb_store_get_host(a) = NULL; expected: <host>");
215 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
216 sdb_store_matcher_t *h, *s, *a, *n;
217 int status;
219 s = sdb_store_service_matcher(golden_data[i].service_name,
220 golden_data[i].service_name_re, NULL);
221 fail_unless(s != NULL,
222 "sdb_store_service_matcher() = NULL; expected: <matcher>");
224 a = sdb_store_attr_matcher(golden_data[i].attr_name,
225 golden_data[i].attr_name_re, golden_data[i].attr_value,
226 golden_data[i].attr_value_re);
227 fail_unless(a != NULL,
228 "sdb_store_attr_matcher() = NULL; expected: <matcher>");
230 h = sdb_store_host_matcher(golden_data[i].hostname,
231 golden_data[i].hostname_re, s, a);
232 fail_unless(h != NULL,
233 "sdb_store_host_matcher() = NULL: expected: <matcher>");
234 /* pass ownership to the host matcher */
235 sdb_object_deref(SDB_OBJ(s));
236 sdb_object_deref(SDB_OBJ(a));
238 status = sdb_store_matcher_matches(h, obj);
239 fail_unless(status == golden_data[i].expected,
240 "sdb_store_matcher_matches({{%s, %s},{%s, %s},"
241 "{%s, %s, %s, %s}}, <host a>) = %d; expected: %d",
242 golden_data[i].hostname, golden_data[i].hostname_re,
243 golden_data[i].service_name, golden_data[i].service_name_re,
244 golden_data[i].attr_name, golden_data[i].attr_name_re,
245 golden_data[i].attr_value, golden_data[i].attr_value_re,
246 status, golden_data[i].expected);
248 n = sdb_store_inv_matcher(h);
249 fail_unless(n != NULL,
250 "sdb_store_inv_matcher() = NULL; expected: <matcher>");
251 sdb_object_deref(SDB_OBJ(h));
253 /* now match the inverted set of objects */
254 status = sdb_store_matcher_matches(n, obj);
255 fail_unless(status == !golden_data[i].expected,
256 "sdb_store_matcher_matches(NOT{{%s, %s},{%s, %s},"
257 "{%s, %s, %s, %s}}, <host a>) = %d; expected: %d",
258 golden_data[i].hostname, golden_data[i].hostname_re,
259 golden_data[i].service_name, golden_data[i].service_name_re,
260 golden_data[i].attr_name, golden_data[i].attr_name_re,
261 golden_data[i].attr_value, golden_data[i].attr_value_re,
262 status, !golden_data[i].expected);
264 sdb_object_deref(SDB_OBJ(n));
265 }
266 }
267 END_TEST
269 START_TEST(test_store_match_op)
270 {
271 sdb_store_base_t *obj;
273 sdb_store_matcher_t *always = sdb_store_host_matcher(NULL, NULL, NULL, NULL);
274 sdb_store_matcher_t *never = sdb_store_host_matcher("a", "b", NULL, NULL);
276 struct {
277 const char *op;
278 sdb_store_matcher_t *left;
279 sdb_store_matcher_t *right;
280 int expected;
281 } golden_data[] = {
282 { "OR", always, always, 1 },
283 { "OR", always, never, 1 },
284 { "OR", never, always, 1 },
285 { "OR", never, never, 0 },
286 { "AND", always, always, 1 },
287 { "AND", always, never, 0 },
288 { "AND", never, always, 0 },
289 { "AND", never, never, 0 },
290 };
292 int status;
293 size_t i;
295 obj = sdb_store_get_host("a");
297 status = sdb_store_matcher_matches(always, obj);
298 fail_unless(status == 1,
299 "INTERNAL ERROR: 'always' did not match host");
300 status = sdb_store_matcher_matches(never, obj);
301 fail_unless(status == 0,
302 "INTERNAL ERROR: 'never' matches host");
304 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
305 sdb_store_matcher_t *m;
307 if (! strcmp(golden_data[i].op, "OR"))
308 m = sdb_store_dis_matcher(golden_data[i].left,
309 golden_data[i].right);
310 else if (! strcmp(golden_data[i].op, "AND"))
311 m = sdb_store_con_matcher(golden_data[i].left,
312 golden_data[i].right);
313 else {
314 fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op);
315 continue;
316 }
318 #define TO_NAME(v) (((v) == always) ? "always" \
319 : ((v) == never) ? "never" : "<unknown>")
321 status = sdb_store_matcher_matches(m, obj);
322 fail_unless(status == golden_data[i].expected,
323 "%s(%s, %s) = %d; expected: %d", golden_data[i].op,
324 TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right),
325 status, golden_data[i].expected);
327 #undef TO_NAME
329 sdb_object_deref(SDB_OBJ(m));
330 }
332 sdb_object_deref(SDB_OBJ(always));
333 sdb_object_deref(SDB_OBJ(never));
334 }
335 END_TEST
337 START_TEST(test_parse_cmp)
338 {
339 sdb_store_matcher_t *check;
341 size_t i;
343 struct {
344 const char *obj_type;
345 const char *attr;
346 const char *op;
347 const char *value;
348 int expected;
349 } golden_data[] = {
350 { "host", "name", "=", "hostname", MATCHER_HOST },
351 { "host", "name", "!=", "hostname", MATCHER_NOT },
352 { "host", "name", "=~", "hostname", MATCHER_HOST },
353 { "host", "name", "!~", "hostname", MATCHER_NOT },
354 { "host", "attr", "=", "hostname", -1 },
355 { "host", "attr", "!=", "hostname", -1 },
356 { "host", "name", "&^", "hostname", -1 },
357 { "service", "name", "=", "srvname", MATCHER_SERVICE },
358 { "service", "name", "!=", "srvname", MATCHER_NOT },
359 { "service", "name", "=~", "srvname", MATCHER_SERVICE },
360 { "service", "name", "!~", "srvname", MATCHER_NOT },
361 { "service", "attr", "=", "srvname", -1 },
362 { "service", "attr", "!=", "srvname", -1 },
363 { "service", "name", "&^", "srvname", -1 },
364 { "attribute", "name", "=", "attrname", MATCHER_ATTR },
365 { "attribute", "name", "!=", "attrname", MATCHER_NOT },
366 { "attribute", "name", "=~", "attrname", MATCHER_ATTR },
367 { "attribute", "name", "!~", "attrname", MATCHER_NOT },
368 { "attribute", "attr", "=", "attrname", MATCHER_ATTR },
369 { "attribute", "attr", "!=", "attrname", MATCHER_NOT },
370 { "attribute", "attr", "=~", "attrname", MATCHER_ATTR },
371 { "attribute", "attr", "!~", "attrname", MATCHER_NOT },
372 { "attribute", "attr", "&^", "attrname", -1 },
373 };
375 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
376 check = sdb_store_matcher_parse_cmp(golden_data[i].obj_type,
377 golden_data[i].attr, golden_data[i].op, golden_data[i].value);
379 if (golden_data[i].expected == -1) {
380 fail_unless(check == NULL,
381 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; "
382 "expected: NULL", golden_data[i].obj_type,
383 golden_data[i].attr, golden_data[i].op,
384 golden_data[i].value, check);
385 continue;
386 }
388 fail_unless(check != NULL,
389 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; "
390 "expected: NULL", golden_data[i].obj_type,
391 golden_data[i].attr, golden_data[i].op,
392 golden_data[i].value, check);
393 fail_unless(M(check)->type == golden_data[i].expected,
394 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) returned matcher "
395 "of type %d; expected: %d", golden_data[i].obj_type,
396 golden_data[i].attr, golden_data[i].op, golden_data[i].value,
397 M(check)->type, golden_data[i].expected);
399 sdb_object_deref(SDB_OBJ(check));
400 }
401 }
402 END_TEST
404 static int
405 lookup_cb(sdb_store_base_t *obj, void *user_data)
406 {
407 intptr_t *i = user_data;
409 fail_unless(obj != NULL,
410 "sdb_store_lookup callback received NULL obj; expected: "
411 "<store base obj>");
412 fail_unless(i != NULL,
413 "sdb_store_lookup callback received NULL user_data; "
414 "expected: <pointer to data>");
416 ++(*i);
417 return 0;
418 } /* lookup_cb */
420 START_TEST(test_lookup)
421 {
422 intptr_t i = 0;
423 int check;
425 check = sdb_store_lookup(NULL, lookup_cb, &i);
426 fail_unless(check == 0,
427 "sdb_store_lookup() = %d; expected: 0", check);
428 fail_unless(i == 3,
429 "sdb_store_lookup called callback %d times; expected: 3", (int)i);
430 }
431 END_TEST
433 Suite *
434 core_store_lookup_suite(void)
435 {
436 Suite *s = suite_create("core::store_lookup");
437 TCase *tc;
439 tc = tcase_create("core");
440 tcase_add_checked_fixture(tc, populate, sdb_store_clear);
441 tcase_add_test(tc, test_store_match);
442 tcase_add_test(tc, test_store_match_op);
443 tcase_add_test(tc, test_parse_cmp);
444 tcase_add_test(tc, test_lookup);
445 suite_add_tcase(s, tc);
447 return s;
448 } /* core_store_lookup_suite */
450 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */