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;
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 sdb_object_deref(SDB_OBJ(h));
249 }
250 }
251 END_TEST
253 START_TEST(test_store_match_op)
254 {
255 sdb_store_base_t *obj;
257 sdb_store_matcher_t *always = sdb_store_host_matcher(NULL, NULL, NULL, NULL);
258 sdb_store_matcher_t *never = sdb_store_host_matcher("a", "b", NULL, NULL);
260 struct {
261 const char *op;
262 sdb_store_matcher_t *left;
263 sdb_store_matcher_t *right;
264 int expected;
265 } golden_data[] = {
266 { "OR", always, always, 1 },
267 { "OR", always, never, 1 },
268 { "OR", never, always, 1 },
269 { "OR", never, never, 0 },
270 { "AND", always, always, 1 },
271 { "AND", always, never, 0 },
272 { "AND", never, always, 0 },
273 { "AND", never, never, 0 },
274 };
276 int status;
277 size_t i;
279 obj = sdb_store_get_host("a");
281 status = sdb_store_matcher_matches(always, obj);
282 fail_unless(status == 1,
283 "INTERNAL ERROR: 'always' did not match host");
284 status = sdb_store_matcher_matches(never, obj);
285 fail_unless(status == 0,
286 "INTERNAL ERROR: 'never' matches host");
288 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
289 sdb_store_matcher_t *m;
291 if (! strcmp(golden_data[i].op, "OR"))
292 m = sdb_store_dis_matcher(golden_data[i].left,
293 golden_data[i].right);
294 else if (! strcmp(golden_data[i].op, "AND"))
295 m = sdb_store_con_matcher(golden_data[i].left,
296 golden_data[i].right);
297 else {
298 fail("INTERNAL ERROR: unexpected operator %s", golden_data[i].op);
299 continue;
300 }
302 #define TO_NAME(v) (((v) == always) ? "always" \
303 : ((v) == never) ? "never" : "<unknown>")
305 status = sdb_store_matcher_matches(m, obj);
306 fail_unless(status == golden_data[i].expected,
307 "%s(%s, %s) = %d; expected: %d", golden_data[i].op,
308 TO_NAME(golden_data[i].left), TO_NAME(golden_data[i].right),
309 status, golden_data[i].expected);
311 #undef TO_NAME
313 sdb_object_deref(SDB_OBJ(m));
314 }
316 sdb_object_deref(SDB_OBJ(always));
317 sdb_object_deref(SDB_OBJ(never));
318 }
319 END_TEST
321 START_TEST(test_parse_cmp)
322 {
323 sdb_store_matcher_t *check;
325 size_t i;
327 struct {
328 const char *obj_type;
329 const char *attr;
330 const char *op;
331 const char *value;
332 int expected;
333 } golden_data[] = {
334 { "host", "name", "=", "hostname", MATCHER_HOST },
335 { "host", "name", "=~", "hostname", MATCHER_HOST },
336 { "host", "attr", "=", "hostname", -1 },
337 { "host", "name", "&^", "hostname", -1 },
338 { "service", "name", "=", "srvname", MATCHER_SERVICE },
339 { "service", "name", "=", "srvname", MATCHER_SERVICE },
340 { "service", "attr", "=", "srvname", -1 },
341 { "service", "name", "&^", "srvname", -1 },
342 { "attribute", "name", "=", "attrname", MATCHER_ATTR },
343 { "attribute", "name", "=~", "attrname", MATCHER_ATTR },
344 { "attribute", "attr", "=", "attrname", MATCHER_ATTR },
345 { "attribute", "attr", "=~", "attrname", MATCHER_ATTR },
346 { "attribute", "attr", "&^", "attrname", -1 },
347 };
349 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
350 check = sdb_store_matcher_parse_cmp(golden_data[i].obj_type,
351 golden_data[i].attr, golden_data[i].op, golden_data[i].value);
353 if (golden_data[i].expected == -1) {
354 fail_unless(check == NULL,
355 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; "
356 "expected: NULL", golden_data[i].obj_type,
357 golden_data[i].attr, golden_data[i].op,
358 golden_data[i].value, check);
359 continue;
360 }
362 fail_unless(check != NULL,
363 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) = %p; "
364 "expected: NULL", golden_data[i].obj_type,
365 golden_data[i].attr, golden_data[i].op,
366 golden_data[i].value, check);
367 fail_unless(M(check)->type == golden_data[i].expected,
368 "sdb_store_matcher_parse_cmp(%s, %s, %s, %s) returned matcher "
369 "of type %d; expected: %d", golden_data[i].obj_type,
370 golden_data[i].attr, golden_data[i].op, golden_data[i].value,
371 M(check)->type, golden_data[i].expected);
373 sdb_object_deref(SDB_OBJ(check));
374 }
375 }
376 END_TEST
378 static int
379 lookup_cb(sdb_store_base_t *obj, void *user_data)
380 {
381 intptr_t *i = user_data;
383 fail_unless(obj != NULL,
384 "sdb_store_lookup callback received NULL obj; expected: "
385 "<store base obj>");
386 fail_unless(i != NULL,
387 "sdb_store_lookup callback received NULL user_data; "
388 "expected: <pointer to data>");
390 ++(*i);
391 return 0;
392 } /* lookup_cb */
394 START_TEST(test_lookup)
395 {
396 intptr_t i = 0;
397 int check;
399 check = sdb_store_lookup(NULL, lookup_cb, &i);
400 fail_unless(check == 0,
401 "sdb_store_lookup() = %d; expected: 0", check);
402 fail_unless(i == 3,
403 "sdb_store_lookup called callback %d times; expected: 3", (int)i);
404 }
405 END_TEST
407 Suite *
408 core_store_lookup_suite(void)
409 {
410 Suite *s = suite_create("core::store_lookup");
411 TCase *tc;
413 tc = tcase_create("core");
414 tcase_add_checked_fixture(tc, populate, sdb_store_clear);
415 tcase_add_test(tc, test_store_match);
416 tcase_add_test(tc, test_store_match_op);
417 tcase_add_test(tc, test_parse_cmp);
418 tcase_add_test(tc, test_lookup);
419 suite_add_tcase(s, tc);
421 return s;
422 } /* core_store_lookup_suite */
424 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */