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 *,
128 sdb_store_expr_t *);
129 int field;
130 sdb_data_t value;
131 } filter;
132 int type;
133 int (*f)(sdb_store_obj_t *, sdb_store_matcher_t *, void *);
134 const char *expected;
135 } store_tojson_data[] = {
136 { { NULL, 0, SDB_DATA_INIT },
137 SDB_HOST, scan_tojson_full,
138 "["
139 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
140 "\"update_interval\": \"0s\", \"backends\": [], "
141 "\"attributes\": ["
142 "{\"name\": \"k1\", \"value\": \"v1\", "
143 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
144 "\"update_interval\": \"0s\", \"backends\": []},"
145 "{\"name\": \"k2\", \"value\": \"v2\", "
146 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
147 "\"update_interval\": \"0s\", \"backends\": []},"
148 "{\"name\": \"k3\", \"value\": \"v3\", "
149 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
150 "\"update_interval\": \"0s\", \"backends\": []}"
151 "], "
152 "\"metrics\": ["
153 "{\"name\": \"m1\", "
154 "\"timeseries\": false, "
155 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
156 "\"update_interval\": \"0s\", \"backends\": [], "
157 "\"attributes\": ["
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 "]},"
167 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
168 "\"update_interval\": \"0s\", \"backends\": [], "
169 "\"metrics\": ["
170 "{\"name\": \"m1\", "
171 "\"timeseries\": false, "
172 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
173 "\"update_interval\": \"0s\", \"backends\": []}"
174 "], "
175 "\"services\": ["
176 "{\"name\": \"s1\", "
177 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
178 "\"update_interval\": \"0s\", \"backends\": []},"
179 "{\"name\": \"s2\", "
180 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
181 "\"update_interval\": \"0s\", \"backends\": [], "
182 "\"attributes\": ["
183 "{\"name\": \"k1\", \"value\": 123, "
184 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
185 "\"update_interval\": \"0s\", \"backends\": []},"
186 "{\"name\": \"k2\", \"value\": 4711, "
187 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
188 "\"update_interval\": \"0s\", \"backends\": []}"
189 "]}"
190 "]}"
191 "]" },
192 { { NULL, 0, SDB_DATA_INIT },
193 SDB_HOST, scan_tojson,
194 "["
195 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
196 "\"update_interval\": \"0s\", \"backends\": []},"
197 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
198 "\"update_interval\": \"0s\", \"backends\": []}"
199 "]" },
200 { { sdb_store_eq_matcher, SDB_FIELD_NAME,
201 { SDB_TYPE_STRING, { .string = "h1" } } },
202 SDB_HOST, scan_tojson_full,
203 "["
204 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
205 "\"update_interval\": \"0s\", \"backends\": []}"
206 "]" },
207 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
208 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
209 SDB_HOST, scan_tojson_full,
210 "["
211 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
212 "\"update_interval\": \"0s\", \"backends\": [], "
213 "\"services\": ["
214 "{\"name\": \"s2\", "
215 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
216 "\"update_interval\": \"0s\", \"backends\": [], "
217 "\"attributes\": ["
218 "{\"name\": \"k1\", \"value\": 123, "
219 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
220 "\"update_interval\": \"0s\", \"backends\": []}"
221 "]}"
222 "]}"
223 "]" },
224 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
225 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
226 SDB_HOST, scan_tojson_full,
227 "["
228 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
229 "\"update_interval\": \"0s\", \"backends\": [], "
230 "\"attributes\": ["
231 "{\"name\": \"k1\", \"value\": \"v1\", "
232 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
233 "\"update_interval\": \"0s\", \"backends\": []}"
234 "], "
235 "\"metrics\": ["
236 "{\"name\": \"m2\", "
237 "\"timeseries\": false, "
238 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
239 "\"update_interval\": \"0s\", \"backends\": []}"
240 "]}"
241 "]" },
242 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
243 { SDB_TYPE_DATETIME, { .datetime = 3 } } },
244 SDB_HOST, scan_tojson_full,
245 "["
246 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
247 "\"update_interval\": \"0s\", \"backends\": []}"
248 "]" },
249 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
250 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
251 SDB_HOST, scan_tojson_full,
252 "[]" },
254 { { NULL, 0, SDB_DATA_INIT },
255 SDB_SERVICE, scan_tojson_full,
256 "["
257 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
258 "\"update_interval\": \"0s\", \"backends\": [], "
259 "\"services\": ["
260 "{\"name\": \"s1\", "
261 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
262 "\"update_interval\": \"0s\", \"backends\": []},"
263 "{\"name\": \"s2\", "
264 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
265 "\"update_interval\": \"0s\", \"backends\": [], "
266 "\"attributes\": ["
267 "{\"name\": \"k1\", \"value\": 123, "
268 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
269 "\"update_interval\": \"0s\", \"backends\": []},"
270 "{\"name\": \"k2\", \"value\": 4711, "
271 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
272 "\"update_interval\": \"0s\", \"backends\": []}"
273 "]}"
274 "]}"
275 "]" },
276 { { NULL, 0, SDB_DATA_INIT },
277 SDB_SERVICE, scan_tojson,
278 "["
279 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
280 "\"update_interval\": \"0s\", \"backends\": [], "
281 "\"services\": ["
282 "{\"name\": \"s1\", "
283 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
284 "\"update_interval\": \"0s\", \"backends\": []},"
285 "{\"name\": \"s2\", "
286 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
287 "\"update_interval\": \"0s\", \"backends\": []}"
288 "]}"
289 "]" },
290 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
291 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
292 SDB_SERVICE, scan_tojson_full,
293 "["
294 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
295 "\"update_interval\": \"0s\", \"backends\": [], "
296 "\"services\": ["
297 "{\"name\": \"s2\", "
298 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
299 "\"update_interval\": \"0s\", \"backends\": [], "
300 "\"attributes\": ["
301 "{\"name\": \"k1\", \"value\": 123, "
302 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
303 "\"update_interval\": \"0s\", \"backends\": []}"
304 "]}"
305 "]}"
306 "]" },
307 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
308 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
309 SDB_SERVICE, scan_tojson_full,
310 "[]" },
311 { { NULL, 0, SDB_DATA_INIT },
312 SDB_METRIC, scan_tojson_full,
313 "["
314 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
315 "\"update_interval\": \"0s\", \"backends\": [], "
316 "\"metrics\": ["
317 "{\"name\": \"m1\", "
318 "\"timeseries\": false, "
319 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
320 "\"update_interval\": \"0s\", \"backends\": [], "
321 "\"attributes\": ["
322 "{\"name\": \"k3\", \"value\": 42, "
323 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
324 "\"update_interval\": \"0s\", \"backends\": []}"
325 "]},"
326 "{\"name\": \"m2\", "
327 "\"timeseries\": false, "
328 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
329 "\"update_interval\": \"0s\", \"backends\": []}"
330 "]},"
331 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
332 "\"update_interval\": \"0s\", \"backends\": [], "
333 "\"metrics\": ["
334 "{\"name\": \"m1\", "
335 "\"timeseries\": false, "
336 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
337 "\"update_interval\": \"0s\", \"backends\": []}"
338 "]}"
339 "]" },
340 { { NULL, 0, SDB_DATA_INIT },
341 SDB_METRIC, scan_tojson,
342 "["
343 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
344 "\"update_interval\": \"0s\", \"backends\": [], "
345 "\"metrics\": ["
346 "{\"name\": \"m1\", "
347 "\"timeseries\": false, "
348 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
349 "\"update_interval\": \"0s\", \"backends\": []},"
350 "{\"name\": \"m2\", "
351 "\"timeseries\": false, "
352 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
353 "\"update_interval\": \"0s\", \"backends\": []}"
354 "]},"
355 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
356 "\"update_interval\": \"0s\", \"backends\": [], "
357 "\"metrics\": ["
358 "{\"name\": \"m1\", "
359 "\"timeseries\": false, "
360 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
361 "\"update_interval\": \"0s\", \"backends\": []}"
362 "]}"
363 "]" },
364 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
365 { SDB_TYPE_DATETIME, { .datetime = 1 } } },
366 SDB_METRIC, scan_tojson_full,
367 "["
368 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
369 "\"update_interval\": \"0s\", \"backends\": [], "
370 "\"metrics\": ["
371 "{\"name\": \"m2\", "
372 "\"timeseries\": false, "
373 "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
374 "\"update_interval\": \"0s\", \"backends\": []}"
375 "]}"
376 "]" },
377 { { sdb_store_lt_matcher, SDB_FIELD_LAST_UPDATE,
378 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
379 SDB_METRIC, scan_tojson_full,
380 "[]" },
381 };
383 START_TEST(test_store_tojson)
384 {
385 sdb_strbuf_t *buf = sdb_strbuf_create(0);
386 sdb_store_matcher_t *filter = NULL;
387 sdb_store_json_formatter_t *f;
388 int status;
390 if (store_tojson_data[_i].filter.m) {
391 sdb_store_expr_t *field;
392 sdb_store_expr_t *value;
394 field = sdb_store_expr_fieldvalue(store_tojson_data[_i].filter.field);
395 fail_unless(field != NULL,
396 "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
397 value = sdb_store_expr_constvalue(&store_tojson_data[_i].filter.value);
398 fail_unless(value != NULL,
399 "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
401 filter = store_tojson_data[_i].filter.m(field, value);
402 fail_unless(filter != NULL,
403 "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
405 sdb_object_deref(SDB_OBJ(field));
406 sdb_object_deref(SDB_OBJ(value));
407 }
409 sdb_strbuf_clear(buf);
410 f = sdb_store_json_formatter(buf,
411 store_tojson_data[_i].type, SDB_WANT_ARRAY);
412 assert(f);
414 status = sdb_store_scan(store_tojson_data[_i].type,
415 /* m = */ NULL, filter, store_tojson_data[_i].f, f);
416 fail_unless(status == 0,
417 "sdb_store_scan(HOST, ..., tojson) = %d; expected: 0",
418 status);
419 sdb_store_json_finish(f);
421 verify_json_output(buf, store_tojson_data[_i].expected);
423 free(f);
424 sdb_object_deref(SDB_OBJ(filter));
425 sdb_strbuf_destroy(buf);
426 }
427 END_TEST
429 TEST_MAIN("core::store_json")
430 {
431 TCase *tc = tcase_create("core");
432 TC_ADD_LOOP_TEST(tc, store_tojson);
433 tcase_add_unchecked_fixture(tc, populate, sdb_store_clear);
434 ADD_TCASE(tc);
435 }
436 TEST_MAIN_END
438 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */