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