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 const 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 int status;
171 status = sdb_store_attribute(golden_data[i].host,
172 golden_data[i].key, golden_data[i].value,
173 golden_data[i].last_update);
174 fail_unless(status == golden_data[i].expected,
175 "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
176 golden_data[i].host, golden_data[i].key, golden_data[i].value,
177 golden_data[i].last_update, status, golden_data[i].expected);
178 }
179 }
180 END_TEST
182 START_TEST(test_store_service)
183 {
184 struct {
185 const char *host;
186 const char *svc;
187 sdb_time_t last_update;
188 int expected;
189 } golden_data[] = {
190 { "k", "s", 1, -1 },
191 { "k", "s", 1, -1 }, /* retry to ensure the host is not created */
192 { "l", "s1", 1, 0 },
193 { "l", "s1", 2, 0 },
194 { "l", "s1", 1, 1 },
195 { "l", "s2", 1, 0 },
196 { "m", "s", 2, 0 },
197 { "m", "s", 1, 1 },
198 };
200 size_t i;
202 sdb_store_host("m", 1);
203 sdb_store_host("l", 1);
204 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
205 int status;
207 status = sdb_store_service(golden_data[i].host,
208 golden_data[i].svc, golden_data[i].last_update);
209 fail_unless(status == golden_data[i].expected,
210 "sdb_store_attribute(%s, %s, %d) = %d; expected: %d",
211 golden_data[i].host, golden_data[i].svc,
212 golden_data[i].last_update, status, golden_data[i].expected);
213 }
214 }
215 END_TEST
217 static void
218 verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags)
219 {
220 int pos;
221 size_t len1, len2;
222 size_t i;
224 len1 = strlen(sdb_strbuf_string(buf));
225 len2 = strlen(expected);
227 pos = -1;
228 if (len1 != len2)
229 pos = (int)(len1 <= len2 ? len1 : len2);
231 for (i = 0; i < (len1 <= len2 ? len1 : len2); ++i) {
232 if (sdb_strbuf_string(buf)[i] != expected[i]) {
233 pos = (int)i;
234 break;
235 }
236 }
238 fail_unless(pos == -1,
239 "sdb_store_tojson(%x) returned unexpected result\n"
240 " got: %s\n %*s\n expected: %s",
241 flags, sdb_strbuf_string(buf), pos + 1, "^", expected);
242 } /* verify_json_output */
244 START_TEST(test_store_tojson)
245 {
246 sdb_strbuf_t *buf;
247 size_t i;
249 struct {
250 int flags;
251 const char *expected;
252 } golden_data[] = {
253 { 0, "{\"hosts\":["
254 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
255 "\"attributes\": ["
256 "{\"name\": \"k1\", \"value\": \"v1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
257 "{\"name\": \"k2\", \"value\": \"v2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
258 "{\"name\": \"k3\", \"value\": \"v3\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
259 "], "
260 "\"services\": []},"
261 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
262 "\"attributes\": [], "
263 "\"services\": ["
264 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
265 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
266 "]}"
267 "]}" },
268 { SDB_SKIP_SERVICES,
269 "{\"hosts\":["
270 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
271 "\"attributes\": ["
272 "{\"name\": \"k1\", \"value\": \"v1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
273 "{\"name\": \"k2\", \"value\": \"v2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
274 "{\"name\": \"k3\", \"value\": \"v3\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
275 "]},"
276 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
277 "\"attributes\": []}"
278 "]}" },
279 { SDB_SKIP_ATTRIBUTES,
280 "{\"hosts\":["
281 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
282 "\"services\": []},"
283 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
284 "\"services\": ["
285 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
286 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
287 "]}"
288 "]}" },
289 { SDB_SKIP_SERVICES | SDB_SKIP_ATTRIBUTES,
290 "{\"hosts\":["
291 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\"},"
292 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\"}"
293 "]}" },
294 };
296 sdb_store_host("h1", 1);
297 sdb_store_host("h2", 1);
299 sdb_store_attribute("h1", "k1", "v1", 1);
300 sdb_store_attribute("h1", "k2", "v2", 1);
301 sdb_store_attribute("h1", "k3", "v3", 1);
303 sdb_store_service("h2", "s1", 1);
304 sdb_store_service("h2", "s2", 1);
306 buf = sdb_strbuf_create(0);
308 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
309 int status;
311 sdb_strbuf_clear(buf);
313 status = sdb_store_tojson(buf, golden_data[i].flags);
314 fail_unless(status == 0,
315 "sdb_store_tojson(%x) = %d; expected: 0",
316 golden_data[i].flags, status);
318 verify_json_output(buf, golden_data[i].expected, golden_data[i].flags);
319 }
320 sdb_strbuf_destroy(buf);
321 }
322 END_TEST
324 Suite *
325 core_store_suite(void)
326 {
327 Suite *s = suite_create("core::store");
328 TCase *tc;
330 tc = tcase_create("core");
331 /* test this first to ensure the store is empty
332 * even when using CK_NOFORK */
333 tcase_add_test(tc, test_store_tojson);
334 tcase_add_test(tc, test_store_host);
335 tcase_add_test(tc, test_store_get_host);
336 tcase_add_test(tc, test_store_attr);
337 tcase_add_test(tc, test_store_service);
338 suite_add_tcase(s, tc);
340 return s;
341 } /* core_store_suite */
343 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */