1 /*
2 * SysDB - t/unit/core/store_json_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 "libsysdb_test.h"
31 #include <assert.h>
33 #include <check.h>
34 #include <stdlib.h>
36 static void
37 populate(void)
38 {
39 sdb_data_t datum;
41 sdb_store_host("h1", 1);
42 sdb_store_host("h2", 3);
44 datum.type = SDB_TYPE_STRING;
45 datum.data.string = "v1";
46 sdb_store_attribute("h1", "k1", &datum, 1);
47 datum.data.string = "v2";
48 sdb_store_attribute("h1", "k2", &datum, 2);
49 datum.data.string = "v3";
50 sdb_store_attribute("h1", "k3", &datum, 2);
52 /* make sure that older updates don't overwrite existing values */
53 datum.data.string = "fail";
54 sdb_store_attribute("h1", "k2", &datum, 1);
55 sdb_store_attribute("h1", "k3", &datum, 2);
57 sdb_store_metric("h1", "m1", /* store */ NULL, 2);
58 sdb_store_metric("h1", "m2", /* store */ NULL, 1);
59 sdb_store_metric("h2", "m1", /* store */ NULL, 1);
61 sdb_store_service("h2", "s1", 1);
62 sdb_store_service("h2", "s2", 2);
64 datum.type = SDB_TYPE_INTEGER;
65 datum.data.integer = 42;
66 sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
68 datum.data.integer = 123;
69 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
70 datum.data.integer = 4711;
71 sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
73 /* don't overwrite k1 */
74 datum.data.integer = 666;
75 sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
76 } /* populate */
78 static int
79 scan_tojson(sdb_store_obj_t *obj,
80 sdb_store_matcher_t __attribute__((unused)) *filter,
81 void *user_data)
82 {
83 sdb_store_json_formatter_t *f = user_data;
84 return sdb_store_json_emit(f, obj);
85 } /* scan_tojson */
87 static int
88 scan_tojson_full(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
89 void *user_data)
90 {
91 sdb_store_json_formatter_t *f = user_data;
92 return sdb_store_json_emit_full(f, obj, filter);
93 } /* scan_tojson_full */
95 static void
96 verify_json_output(sdb_strbuf_t *buf, const char *expected)
97 {
98 const char *got = sdb_strbuf_string(buf);
99 size_t len1 = strlen(got);
100 size_t len2 = strlen(expected);
102 size_t i;
103 int pos = -1;
105 if (len1 != len2)
106 pos = (int)SDB_MIN(len1, len2);
108 for (i = 0; i < SDB_MIN(len1, len2); ++i) {
109 if (got[i] != expected[i]) {
110 pos = (int)i;
111 break;
112 }
113 }
115 fail_unless(pos == -1,
116 "Serializing hosts to JSON returned unexpected result\n"
117 " got: %s\n %*s\n expected: %s",
118 got, pos + 1, "^", expected);
119 } /* verify_json_output */
121 START_TEST(test_store_tojson)
122 {
123 sdb_strbuf_t *buf;
124 size_t i;
126 struct {
127 struct {
128 sdb_store_matcher_t *(*m)(sdb_store_expr_t *,
129 sdb_store_expr_t *);
130 int field;
131 sdb_data_t value;
132 } filter;
133 int type;
134 int (*f)(sdb_store_obj_t *, sdb_store_matcher_t *, void *);
135 const char *expected;
136 } golden_data[] = {
137 { { NULL, 0, SDB_DATA_INIT },
138 SDB_HOST, scan_tojson_full,
139 "["
140 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
141 "\"update_interval\": \"0s\", \"backends\": [], "
142 "\"attributes\": ["
143 "{\"name\": \"k1\", \"value\": \"v1\", "
144 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
145 "\"update_interval\": \"0s\", \"backends\": []},"
146 "{\"name\": \"k2\", \"value\": \"v2\", "
147 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
148 "\"update_interval\": \"0s\", \"backends\": []},"
149 "{\"name\": \"k3\", \"value\": \"v3\", "
150 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
151 "\"update_interval\": \"0s\", \"backends\": []}"
152 "], "
153 "\"metrics\": ["
154 "{\"name\": \"m1\", "
155 "\"timeseries\": false, "
156 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
157 "\"update_interval\": \"0s\", \"backends\": [], "
158 "\"attributes\": ["
159 "{\"name\": \"k3\", \"value\": 42, "
160 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
161 "\"update_interval\": \"0s\", \"backends\": []}"
162 "]},"
163 "{\"name\": \"m2\", "
164 "\"timeseries\": false, "
165 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
166 "\"update_interval\": \"0s\", \"backends\": []}"
167 "]},"
168 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
169 "\"update_interval\": \"0s\", \"backends\": [], "
170 "\"metrics\": ["
171 "{\"name\": \"m1\", "
172 "\"timeseries\": false, "
173 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
174 "\"update_interval\": \"0s\", \"backends\": []}"
175 "], "
176 "\"services\": ["
177 "{\"name\": \"s1\", "
178 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
179 "\"update_interval\": \"0s\", \"backends\": []},"
180 "{\"name\": \"s2\", "
181 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
182 "\"update_interval\": \"0s\", \"backends\": [], "
183 "\"attributes\": ["
184 "{\"name\": \"k1\", \"value\": 123, "
185 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
186 "\"update_interval\": \"0s\", \"backends\": []},"
187 "{\"name\": \"k2\", \"value\": 4711, "
188 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
189 "\"update_interval\": \"0s\", \"backends\": []}"
190 "]}"
191 "]}"
192 "]" },
193 { { NULL, 0, SDB_DATA_INIT },
194 SDB_HOST, scan_tojson,
195 "["
196 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
197 "\"update_interval\": \"0s\", \"backends\": []},"
198 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
199 "\"update_interval\": \"0s\", \"backends\": []}"
200 "]" },
201 { { sdb_store_eq_matcher, SDB_FIELD_NAME,
202 { SDB_TYPE_STRING, { .string = "h1" } } },
203 SDB_HOST, scan_tojson_full,
204 "["
205 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
206 "\"update_interval\": \"0s\", \"backends\": []}"
207 "]" },
208 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
209 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
210 SDB_HOST, scan_tojson_full,
211 "["
212 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
213 "\"update_interval\": \"0s\", \"backends\": [], "
214 "\"services\": ["
215 "{\"name\": \"s2\", "
216 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
217 "\"update_interval\": \"0s\", \"backends\": [], "
218 "\"attributes\": ["
219 "{\"name\": \"k1\", \"value\": 123, "
220 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
221 "\"update_interval\": \"0s\", \"backends\": []}"
222 "]}"
223 "]}"
224 "]" },
225 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
226 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
227 SDB_HOST, scan_tojson_full,
228 "["
229 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
230 "\"update_interval\": \"0s\", \"backends\": [], "
231 "\"attributes\": ["
232 "{\"name\": \"k1\", \"value\": \"v1\", "
233 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
234 "\"update_interval\": \"0s\", \"backends\": []}"
235 "], "
236 "\"metrics\": ["
237 "{\"name\": \"m2\", "
238 "\"timeseries\": false, "
239 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
240 "\"update_interval\": \"0s\", \"backends\": []}"
241 "]}"
242 "]" },
243 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
244 { SDB_TYPE_DATETIME, { .datetime = 3 } } },
245 SDB_HOST, scan_tojson_full,
246 "["
247 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
248 "\"update_interval\": \"0s\", \"backends\": []}"
249 "]" },
250 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
251 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
252 SDB_HOST, scan_tojson_full,
253 "[]" },
255 { { NULL, 0, SDB_DATA_INIT },
256 SDB_SERVICE, scan_tojson_full,
257 "["
258 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
259 "\"update_interval\": \"0s\", \"backends\": [], "
260 "\"services\": ["
261 "{\"name\": \"s1\", "
262 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
263 "\"update_interval\": \"0s\", \"backends\": []},"
264 "{\"name\": \"s2\", "
265 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
266 "\"update_interval\": \"0s\", \"backends\": [], "
267 "\"attributes\": ["
268 "{\"name\": \"k1\", \"value\": 123, "
269 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
270 "\"update_interval\": \"0s\", \"backends\": []},"
271 "{\"name\": \"k2\", \"value\": 4711, "
272 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
273 "\"update_interval\": \"0s\", \"backends\": []}"
274 "]}"
275 "]}"
276 "]" },
277 { { NULL, 0, SDB_DATA_INIT },
278 SDB_SERVICE, scan_tojson,
279 "["
280 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
281 "\"update_interval\": \"0s\", \"backends\": [], "
282 "\"services\": ["
283 "{\"name\": \"s1\", "
284 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
285 "\"update_interval\": \"0s\", \"backends\": []},"
286 "{\"name\": \"s2\", "
287 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
288 "\"update_interval\": \"0s\", \"backends\": []}"
289 "]}"
290 "]" },
291 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
292 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
293 SDB_SERVICE, scan_tojson_full,
294 "["
295 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
296 "\"update_interval\": \"0s\", \"backends\": [], "
297 "\"services\": ["
298 "{\"name\": \"s2\", "
299 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
300 "\"update_interval\": \"0s\", \"backends\": [], "
301 "\"attributes\": ["
302 "{\"name\": \"k1\", \"value\": 123, "
303 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
304 "\"update_interval\": \"0s\", \"backends\": []}"
305 "]}"
306 "]}"
307 "]" },
308 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
309 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
310 SDB_SERVICE, scan_tojson_full,
311 "[]" },
312 { { NULL, 0, SDB_DATA_INIT },
313 SDB_METRIC, scan_tojson_full,
314 "["
315 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
316 "\"update_interval\": \"0s\", \"backends\": [], "
317 "\"metrics\": ["
318 "{\"name\": \"m1\", "
319 "\"timeseries\": false, "
320 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
321 "\"update_interval\": \"0s\", \"backends\": [], "
322 "\"attributes\": ["
323 "{\"name\": \"k3\", \"value\": 42, "
324 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
325 "\"update_interval\": \"0s\", \"backends\": []}"
326 "]},"
327 "{\"name\": \"m2\", "
328 "\"timeseries\": false, "
329 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
330 "\"update_interval\": \"0s\", \"backends\": []}"
331 "]},"
332 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
333 "\"update_interval\": \"0s\", \"backends\": [], "
334 "\"metrics\": ["
335 "{\"name\": \"m1\", "
336 "\"timeseries\": false, "
337 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
338 "\"update_interval\": \"0s\", \"backends\": []}"
339 "]}"
340 "]" },
341 { { NULL, 0, SDB_DATA_INIT },
342 SDB_METRIC, scan_tojson,
343 "["
344 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
345 "\"update_interval\": \"0s\", \"backends\": [], "
346 "\"metrics\": ["
347 "{\"name\": \"m1\", "
348 "\"timeseries\": false, "
349 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
350 "\"update_interval\": \"0s\", \"backends\": []},"
351 "{\"name\": \"m2\", "
352 "\"timeseries\": false, "
353 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
354 "\"update_interval\": \"0s\", \"backends\": []}"
355 "]},"
356 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
357 "\"update_interval\": \"0s\", \"backends\": [], "
358 "\"metrics\": ["
359 "{\"name\": \"m1\", "
360 "\"timeseries\": false, "
361 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
362 "\"update_interval\": \"0s\", \"backends\": []}"
363 "]}"
364 "]" },
365 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
366 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
367 SDB_METRIC, scan_tojson_full,
368 "["
369 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
370 "\"update_interval\": \"0s\", \"backends\": [], "
371 "\"metrics\": ["
372 "{\"name\": \"m2\", "
373 "\"timeseries\": false, "
374 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
375 "\"update_interval\": \"0s\", \"backends\": []}"
376 "]}"
377 "]" },
378 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
379 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
380 SDB_METRIC, scan_tojson_full,
381 "[]" },
382 };
384 buf = sdb_strbuf_create(0);
385 fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
386 populate();
388 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
389 sdb_store_matcher_t *filter = NULL;
390 sdb_store_json_formatter_t *f;
391 int status;
393 sdb_strbuf_clear(buf);
395 if (golden_data[i].filter.m) {
396 sdb_store_expr_t *field;
397 sdb_store_expr_t *value;
399 field = sdb_store_expr_fieldvalue(golden_data[i].filter.field);
400 fail_unless(field != NULL,
401 "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
402 value = sdb_store_expr_constvalue(&golden_data[i].filter.value);
403 fail_unless(value != NULL,
404 "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
406 filter = golden_data[i].filter.m(field, value);
407 fail_unless(filter != NULL,
408 "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
410 sdb_object_deref(SDB_OBJ(field));
411 sdb_object_deref(SDB_OBJ(value));
412 }
414 sdb_strbuf_clear(buf);
415 f = sdb_store_json_formatter(buf,
416 golden_data[i].type, SDB_WANT_ARRAY);
417 assert(f);
419 status = sdb_store_scan(golden_data[i].type, /* m = */ NULL, filter,
420 golden_data[i].f, f);
421 fail_unless(status == 0,
422 "sdb_store_scan(HOST, ..., tojson) = %d; expected: 0",
423 status);
424 sdb_store_json_finish(f);
426 verify_json_output(buf, golden_data[i].expected);
427 free(f);
428 sdb_object_deref(SDB_OBJ(filter));
429 }
430 sdb_strbuf_destroy(buf);
431 }
432 END_TEST
434 Suite *
435 core_store_json_suite(void)
436 {
437 Suite *s = suite_create("core::store_json");
438 TCase *tc;
440 tc = tcase_create("core");
441 tcase_add_test(tc, test_store_tojson);
442 tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
443 suite_add_tcase(s, tc);
445 return s;
446 } /* core_store_json_suite */
448 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */