1 /*
2 * SysDB - t/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 #include "core/store.h"
29 #include "libsysdb_test.h"
31 #include <check.h>
32 #include <string.h>
34 START_TEST(test_store_host)
35 {
36 struct {
37 const char *name;
38 sdb_time_t last_update;
39 int expected;
40 } golden_data[] = {
41 { "a", 2, 0 },
42 { "a", 3, 0 },
43 { "a", 1, 1 },
44 { "b", 2, 0 },
45 { "b", 1, 1 },
46 { "A", 1, 1 }, /* case-insensitive */
47 { "A", 4, 0 },
48 };
50 struct {
51 const char *name;
52 _Bool has;
53 } golden_hosts[] = {
54 { "a", 1 == 1 },
55 { "b", 1 == 1 },
56 { "c", 0 == 1 },
57 { "A", 1 == 1 },
58 };
60 size_t i;
62 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
63 int status;
65 status = sdb_store_host(golden_data[i].name,
66 golden_data[i].last_update);
67 fail_unless(status == golden_data[i].expected,
68 "sdb_store_host(%s, %d) = %d; expected: %d",
69 golden_data[i].name, (int)golden_data[i].last_update,
70 status, golden_data[i].expected);
71 }
73 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
74 _Bool has;
76 has = sdb_store_has_host(golden_hosts[i].name);
77 fail_unless(has == golden_hosts[i].has,
78 "sdb_store_has_host(%s) = %d; expected: %d",
79 golden_hosts[i].name, has, golden_hosts[i].has);
80 }
81 }
82 END_TEST
84 START_TEST(test_store_get_host)
85 {
86 char *golden_hosts[] = { "a", "b", "c" };
87 char *unknown_hosts[] = { "x", "y", "z" };
88 size_t i;
90 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
91 int status = sdb_store_host(golden_hosts[i], 1);
92 fail_unless(status >= 0,
93 "sdb_store_host(%s) = %d; expected: >=0",
94 golden_hosts[i], status);
95 }
97 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_hosts); ++i) {
98 sdb_store_base_t *sobj1, *sobj2;
99 int ref_cnt;
101 fail_unless(sdb_store_has_host(golden_hosts[i]),
102 "sdb_store_has_host(%s) = FALSE; expected: TRUE",
103 golden_hosts[i]);
105 sobj1 = sdb_store_get_host(golden_hosts[i]);
106 fail_unless(sobj1 != NULL,
107 "sdb_store_get_host(%s) = NULL; expected: <host>",
108 golden_hosts[i]);
109 ref_cnt = SDB_OBJ(sobj1)->ref_cnt;
111 fail_unless(ref_cnt > 1,
112 "sdb_store_get_host(%s) did not increment ref count: "
113 "got: %d; expected: >1", golden_hosts[i], ref_cnt);
115 sobj2 = sdb_store_get_host(golden_hosts[i]);
116 fail_unless(sobj2 != NULL,
117 "sdb_store_get_host(%s) = NULL; expected: <host>",
118 golden_hosts[i]);
120 fail_unless(sobj1 == sobj2,
121 "sdb_store_get_host(%s) returned different objects "
122 "in successive calls", golden_hosts[i]);
123 fail_unless(SDB_OBJ(sobj2)->ref_cnt == ref_cnt + 1,
124 "sdb_store_get_hosts(%s) did not increment ref count "
125 "(first call: %d; second call: %d)",
126 golden_hosts[i], ref_cnt, SDB_OBJ(sobj2)->ref_cnt);
128 sdb_object_deref(SDB_OBJ(sobj1));
129 sdb_object_deref(SDB_OBJ(sobj2));
130 }
131 for (i = 0; i < SDB_STATIC_ARRAY_LEN(unknown_hosts); ++i) {
132 sdb_store_base_t *sobj;
134 fail_unless(!sdb_store_has_host(unknown_hosts[i]),
135 "sdb_store_has_host(%s) = TRUE; expected: FALSE",
136 unknown_hosts[i]);
138 sobj = sdb_store_get_host(unknown_hosts[i]);
139 fail_unless(!sobj, "sdb_store_get_host(%s) = <host:%s>; expected: NULL",
140 unknown_hosts[i], sobj ? SDB_OBJ(sobj)->name : "NULL");
141 }
142 }
143 END_TEST
145 START_TEST(test_store_attr)
146 {
147 struct {
148 const char *host;
149 const char *key;
150 char *value;
151 sdb_time_t last_update;
152 int expected;
153 } golden_data[] = {
154 { "k", "k", "v", 1, -1 },
155 { "k", "k", "v", 1, -1 }, /* retry to ensure the host is not created */
156 { "l", "k1", "v1", 1, 0 },
157 { "l", "k1", "v2", 2, 0 },
158 { "l", "k1", "v3", 1, 1 },
159 { "l", "k2", "v1", 1, 0 },
160 { "m", "k", "v1", 2, 0 },
161 { "m", "k", "v2", 1, 1 },
162 };
164 size_t i;
166 sdb_store_host("l", 1);
167 sdb_store_host("m", 1);
168 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
169 sdb_data_t datum;
170 int status;
172 /* XXX: test other types as well */
173 datum.type = SDB_TYPE_STRING;
174 datum.data.string = golden_data[i].value;
176 status = sdb_store_attribute(golden_data[i].host,
177 golden_data[i].key, &datum,
178 golden_data[i].last_update);
179 fail_unless(status == golden_data[i].expected,
180 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
181 golden_data[i].host, golden_data[i].key, golden_data[i].value,
182 golden_data[i].last_update, status, golden_data[i].expected);
183 }
184 }
185 END_TEST
187 START_TEST(test_store_service)
188 {
189 struct {
190 const char *host;
191 const char *svc;
192 sdb_time_t last_update;
193 int expected;
194 } golden_data[] = {
195 { "k", "s", 1, -1 },
196 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
197 { "l", "s1", 1, 0 },
198 { "l", "s1", 2, 0 },
199 { "l", "s1", 1, 1 },
200 { "l", "s2", 1, 0 },
201 { "m", "s", 2, 0 },
202 { "m", "s", 1, 1 },
203 };
205 size_t i;
207 sdb_store_host("m", 1);
208 sdb_store_host("l", 1);
209 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
210 int status;
212 status = sdb_store_service(golden_data[i].host,
213 golden_data[i].svc, golden_data[i].last_update);
214 fail_unless(status == golden_data[i].expected,
215 "sdb_store_attribute(%s, %s, %d) = %d; expected: %d",
216 golden_data[i].host, golden_data[i].svc,
217 golden_data[i].last_update, status, golden_data[i].expected);
218 }
219 }
220 END_TEST
222 static void
223 verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags)
224 {
225 int pos;
226 size_t len1, len2;
227 size_t i;
229 len1 = strlen(sdb_strbuf_string(buf));
230 len2 = strlen(expected);
232 pos = -1;
233 if (len1 != len2)
234 pos = (int)(len1 <= len2 ? len1 : len2);
236 for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
237 if (sdb_strbuf_string(buf)[i] != expected[i]) {
238 pos = (int)i;
239 break;
240 }
241 }
243 fail_unless(pos == -1,
244 "sdb_store_tojson(%x) returned unexpected result\n"
245 " got: %s\n %*s\n expected: %s",
246 flags, sdb_strbuf_string(buf), pos + 1, "^", expected);
247 } /* verify_json_output */
249 START_TEST(test_store_tojson)
250 {
251 sdb_strbuf_t *buf;
252 sdb_data_t datum;
253 size_t i;
255 struct {
256 int flags;
257 const char *expected;
258 } golden_data[] = {
259 { 0, "{\"hosts\":["
260 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
261 "\"attributes\": ["
262 "{\"name\": \"k1\", \"value\": \"v1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
263 "{\"name\": \"k2\", \"value\": \"v2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
264 "{\"name\": \"k3\", \"value\": \"v3\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
265 "], "
266 "\"services\": []},"
267 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
268 "\"attributes\": [], "
269 "\"services\": ["
270 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
271 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
272 "]}"
273 "]}" },
274 { SDB_SKIP_SERVICES,
275 "{\"hosts\":["
276 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
277 "\"attributes\": ["
278 "{\"name\": \"k1\", \"value\": \"v1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
279 "{\"name\": \"k2\", \"value\": \"v2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
280 "{\"name\": \"k3\", \"value\": \"v3\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
281 "]},"
282 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
283 "\"attributes\": []}"
284 "]}" },
285 { SDB_SKIP_ATTRIBUTES,
286 "{\"hosts\":["
287 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
288 "\"services\": []},"
289 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
290 "\"services\": ["
291 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
292 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
293 "]}"
294 "]}" },
295 { SDB_SKIP_SERVICES | SDB_SKIP_ATTRIBUTES,
296 "{\"hosts\":["
297 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
298 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
299 "]}" },
300 };
302 sdb_store_host("h1", 1);
303 sdb_store_host("h2", 1);
305 datum.type = SDB_TYPE_STRING;
306 datum.data.string = "v1";
307 sdb_store_attribute("h1", "k1", &datum, 1);
308 datum.data.string = "v2";
309 sdb_store_attribute("h1", "k2", &datum, 1);
310 datum.data.string = "v3";
311 sdb_store_attribute("h1", "k3", &datum, 1);
313 sdb_store_service("h2", "s1", 1);
314 sdb_store_service("h2", "s2", 1);
316 buf = sdb_strbuf_create(0);
318 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
319 int status;
321 sdb_strbuf_clear(buf);
323 status = sdb_store_tojson(buf, golden_data[i].flags);
324 fail_unless(status == 0,
325 "sdb_store_tojson(%x) = %d; expected: 0",
326 golden_data[i].flags, status);
328 verify_json_output(buf, golden_data[i].expected, golden_data[i].flags);
329 }
330 sdb_strbuf_destroy(buf);
331 }
332 END_TEST
334 Suite *
335 core_store_suite(void)
336 {
337 Suite *s = suite_create("core::store");
338 TCase *tc;
340 tc = tcase_create("core");
341 /* test this first to ensure the store is empty
342 * even when using CK_NOFORK */
343 tcase_add_test(tc, test_store_tojson);
344 tcase_add_test(tc, test_store_host);
345 tcase_add_test(tc, test_store_get_host);
346 tcase_add_test(tc, test_store_attr);
347 tcase_add_test(tc, test_store_service);
348 suite_add_tcase(s, tc);
350 return s;
351 } /* core_store_suite */
353 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */