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