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