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_memstore_t *store;
44 static void
45 populate(void)
46 {
47 sdb_data_t datum;
49 store = sdb_memstore_create();
50 ck_assert(store != NULL);
52 sdb_memstore_host(store, "h1", 1 * SDB_INTERVAL_SECOND);
53 sdb_memstore_host(store, "h2", 3 * SDB_INTERVAL_SECOND);
55 datum.type = SDB_TYPE_STRING;
56 datum.data.string = "v1";
57 sdb_memstore_attribute(store, "h1", "k1", &datum, 1 * SDB_INTERVAL_SECOND);
58 datum.data.string = "v2";
59 sdb_memstore_attribute(store, "h1", "k2", &datum, 2 * SDB_INTERVAL_SECOND);
60 datum.data.string = "v3";
61 sdb_memstore_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_memstore_attribute(store, "h1", "k2", &datum, 1 * SDB_INTERVAL_SECOND);
66 sdb_memstore_attribute(store, "h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND);
68 sdb_memstore_metric(store, "h1", "m1", /* store */ NULL, 2 * SDB_INTERVAL_SECOND);
69 sdb_memstore_metric(store, "h1", "m2", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
70 sdb_memstore_metric(store, "h2", "m1", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
72 sdb_memstore_service(store, "h2", "s1", 1 * SDB_INTERVAL_SECOND);
73 sdb_memstore_service(store, "h2", "s2", 2 * SDB_INTERVAL_SECOND);
75 datum.type = SDB_TYPE_INTEGER;
76 datum.data.integer = 42;
77 sdb_memstore_metric_attr(store, "h1", "m1", "k3",
78 &datum, 2 * SDB_INTERVAL_SECOND);
80 datum.data.integer = 123;
81 sdb_memstore_service_attr(store, "h2", "s2", "k1",
82 &datum, 2 * SDB_INTERVAL_SECOND);
83 datum.data.integer = 4711;
84 sdb_memstore_service_attr(store, "h2", "s2", "k2",
85 &datum, 1 * SDB_INTERVAL_SECOND);
87 /* don't overwrite k1 */
88 datum.data.integer = 666;
89 sdb_memstore_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_memstore_obj_t *obj,
102 sdb_memstore_matcher_t __attribute__((unused)) *filter,
103 void *user_data)
104 {
105 return sdb_memstore_emit(obj, &sdb_store_json_writer, user_data);
106 } /* scan_tojson */
108 static int
109 scan_tojson_full(sdb_memstore_obj_t *obj, sdb_memstore_matcher_t *filter,
110 void *user_data)
111 {
112 return sdb_memstore_emit_full(obj, filter, &sdb_store_json_writer, user_data);
113 } /* scan_tojson_full */
115 static void
116 verify_json_output(sdb_strbuf_t *buf, const char *expected)
117 {
118 const char *got = sdb_strbuf_string(buf);
119 size_t len1 = strlen(got);
120 size_t len2 = strlen(expected);
122 size_t i;
123 int pos = -1;
125 if (len1 != len2)
126 pos = (int)SDB_MIN(len1, len2);
128 for (i = 0; i < SDB_MIN(len1, len2); ++i) {
129 if (got[i] != expected[i]) {
130 pos = (int)i;
131 break;
132 }
133 }
135 fail_unless(pos == -1,
136 "Serializing hosts to JSON returned unexpected result\n"
137 " got: %s\n %*s\n expected: %s",
138 got, pos + 1, "^", expected);
139 } /* verify_json_output */
141 struct {
142 struct {
143 sdb_memstore_matcher_t *(*m)(sdb_memstore_expr_t *, sdb_memstore_expr_t *);
144 int field;
145 sdb_data_t value;
146 } filter;
147 int type;
148 int (*f)(sdb_memstore_obj_t *, sdb_memstore_matcher_t *, void *);
149 const char *expected;
150 } store_tojson_data[] = {
151 { { NULL, 0, SDB_DATA_INIT },
152 SDB_HOST, scan_tojson_full,
153 "["
154 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", "
155 "\"update_interval\": \"0s\", \"backends\": [], "
156 "\"attributes\": ["
157 "{\"name\": \"k1\", \"value\": \"v1\", "
158 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
159 "\"update_interval\": \"0s\", \"backends\": []},"
160 "{\"name\": \"k2\", \"value\": \"v2\", "
161 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
162 "\"update_interval\": \"0s\", \"backends\": []},"
163 "{\"name\": \"k3\", \"value\": \"v3\", "
164 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
165 "\"update_interval\": \"0s\", \"backends\": []}"
166 "], "
167 "\"metrics\": ["
168 "{\"name\": \"m1\", "
169 "\"timeseries\": false, "
170 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
171 "\"update_interval\": \"0s\", \"backends\": [], "
172 "\"attributes\": ["
173 "{\"name\": \"k3\", \"value\": 42, "
174 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
175 "\"update_interval\": \"0s\", \"backends\": []}"
176 "]},"
177 "{\"name\": \"m2\", "
178 "\"timeseries\": false, "
179 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
180 "\"update_interval\": \"0s\", \"backends\": []}"
181 "]},"
182 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
183 "\"update_interval\": \"0s\", \"backends\": [], "
184 "\"metrics\": ["
185 "{\"name\": \"m1\", "
186 "\"timeseries\": false, "
187 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
188 "\"update_interval\": \"0s\", \"backends\": []}"
189 "], "
190 "\"services\": ["
191 "{\"name\": \"s1\", "
192 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
193 "\"update_interval\": \"0s\", \"backends\": []},"
194 "{\"name\": \"s2\", "
195 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
196 "\"update_interval\": \"0s\", \"backends\": [], "
197 "\"attributes\": ["
198 "{\"name\": \"k1\", \"value\": 123, "
199 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
200 "\"update_interval\": \"0s\", \"backends\": []},"
201 "{\"name\": \"k2\", \"value\": 4711, "
202 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
203 "\"update_interval\": \"0s\", \"backends\": []}"
204 "]}"
205 "]}"
206 "]" },
207 { { NULL, 0, SDB_DATA_INIT },
208 SDB_HOST, scan_tojson,
209 "["
210 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", "
211 "\"update_interval\": \"0s\", \"backends\": []},"
212 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
213 "\"update_interval\": \"0s\", \"backends\": []}"
214 "]" },
215 { { sdb_memstore_eq_matcher, SDB_FIELD_NAME,
216 { SDB_TYPE_STRING, { .string = "h1" } } },
217 SDB_HOST, scan_tojson_full,
218 "["
219 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", "
220 "\"update_interval\": \"0s\", \"backends\": []}"
221 "]" },
222 { { sdb_memstore_gt_matcher, SDB_FIELD_LAST_UPDATE,
223 { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
224 SDB_HOST, scan_tojson_full,
225 "["
226 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
227 "\"update_interval\": \"0s\", \"backends\": [], "
228 "\"services\": ["
229 "{\"name\": \"s2\", "
230 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
231 "\"update_interval\": \"0s\", \"backends\": [], "
232 "\"attributes\": ["
233 "{\"name\": \"k1\", \"value\": 123, "
234 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
235 "\"update_interval\": \"0s\", \"backends\": []}"
236 "]}"
237 "]}"
238 "]" },
239 { { sdb_memstore_le_matcher, SDB_FIELD_LAST_UPDATE,
240 { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
241 SDB_HOST, scan_tojson_full,
242 "["
243 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", "
244 "\"update_interval\": \"0s\", \"backends\": [], "
245 "\"attributes\": ["
246 "{\"name\": \"k1\", \"value\": \"v1\", "
247 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
248 "\"update_interval\": \"0s\", \"backends\": []}"
249 "], "
250 "\"metrics\": ["
251 "{\"name\": \"m2\", "
252 "\"timeseries\": false, "
253 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
254 "\"update_interval\": \"0s\", \"backends\": []}"
255 "]}"
256 "]" },
257 { { sdb_memstore_ge_matcher, SDB_FIELD_LAST_UPDATE,
258 { SDB_TYPE_DATETIME, { .datetime = 3 * SDB_INTERVAL_SECOND } } },
259 SDB_HOST, scan_tojson_full,
260 "["
261 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", "
262 "\"update_interval\": \"0s\", \"backends\": []}"
263 "]" },
264 { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
265 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
266 SDB_HOST, scan_tojson_full,
267 "[]" },
269 { { NULL, 0, SDB_DATA_INIT },
270 SDB_SERVICE, scan_tojson_full,
271 "["
272 "{\"name\": \"s1\", "
273 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
274 "\"update_interval\": \"0s\", \"backends\": []},"
275 "{\"name\": \"s2\", "
276 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
277 "\"update_interval\": \"0s\", \"backends\": [], "
278 "\"attributes\": ["
279 "{\"name\": \"k1\", \"value\": 123, "
280 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
281 "\"update_interval\": \"0s\", \"backends\": []},"
282 "{\"name\": \"k2\", \"value\": 4711, "
283 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
284 "\"update_interval\": \"0s\", \"backends\": []}"
285 "]}"
286 "]" },
287 { { NULL, 0, SDB_DATA_INIT },
288 SDB_SERVICE, scan_tojson,
289 "["
290 "{\"name\": \"s1\", "
291 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
292 "\"update_interval\": \"0s\", \"backends\": []},"
293 "{\"name\": \"s2\", "
294 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
295 "\"update_interval\": \"0s\", \"backends\": []}"
296 "]" },
297 { { sdb_memstore_gt_matcher, SDB_FIELD_LAST_UPDATE,
298 { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
299 SDB_SERVICE, scan_tojson_full,
300 "["
301 "{\"name\": \"s2\", "
302 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
303 "\"update_interval\": \"0s\", \"backends\": [], "
304 "\"attributes\": ["
305 "{\"name\": \"k1\", \"value\": 123, "
306 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
307 "\"update_interval\": \"0s\", \"backends\": []}"
308 "]}"
309 "]" },
310 { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
311 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
312 SDB_SERVICE, scan_tojson_full,
313 "[]" },
314 { { NULL, 0, SDB_DATA_INIT },
315 SDB_METRIC, scan_tojson_full,
316 "["
317 "{\"name\": \"m1\", "
318 "\"timeseries\": false, "
319 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
320 "\"update_interval\": \"0s\", \"backends\": [], "
321 "\"attributes\": ["
322 "{\"name\": \"k3\", \"value\": 42, "
323 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
324 "\"update_interval\": \"0s\", \"backends\": []}"
325 "]},"
326 "{\"name\": \"m2\", "
327 "\"timeseries\": false, "
328 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
329 "\"update_interval\": \"0s\", \"backends\": []},"
330 "{\"name\": \"m1\", "
331 "\"timeseries\": false, "
332 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
333 "\"update_interval\": \"0s\", \"backends\": []}"
334 "]" },
335 { { NULL, 0, SDB_DATA_INIT },
336 SDB_METRIC, scan_tojson,
337 "["
338 "{\"name\": \"m1\", "
339 "\"timeseries\": false, "
340 "\"last_update\": \"1970-01-01 00:00:02 +0000\", "
341 "\"update_interval\": \"0s\", \"backends\": []},"
342 "{\"name\": \"m2\", "
343 "\"timeseries\": false, "
344 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
345 "\"update_interval\": \"0s\", \"backends\": []},"
346 "{\"name\": \"m1\", "
347 "\"timeseries\": false, "
348 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
349 "\"update_interval\": \"0s\", \"backends\": []}"
350 "]" },
351 { { sdb_memstore_le_matcher, SDB_FIELD_LAST_UPDATE,
352 { SDB_TYPE_DATETIME, { .datetime = 1 * SDB_INTERVAL_SECOND } } },
353 SDB_METRIC, scan_tojson_full,
354 "["
355 "{\"name\": \"m2\", "
356 "\"timeseries\": false, "
357 "\"last_update\": \"1970-01-01 00:00:01 +0000\", "
358 "\"update_interval\": \"0s\", \"backends\": []}"
359 "]" },
360 { { sdb_memstore_lt_matcher, SDB_FIELD_LAST_UPDATE,
361 { SDB_TYPE_DATETIME, { .datetime = 0 } } },
362 SDB_METRIC, scan_tojson_full,
363 "[]" },
364 };
366 START_TEST(test_store_tojson)
367 {
368 sdb_strbuf_t *buf = sdb_strbuf_create(0);
369 sdb_memstore_matcher_t *filter = NULL;
370 sdb_store_json_formatter_t *f;
371 int status;
373 if (store_tojson_data[_i].filter.m) {
374 sdb_memstore_expr_t *field;
375 sdb_memstore_expr_t *value;
377 field = sdb_memstore_expr_fieldvalue(store_tojson_data[_i].filter.field);
378 fail_unless(field != NULL,
379 "INTERNAL ERROR: sdb_memstore_expr_fieldvalue() = NULL");
380 value = sdb_memstore_expr_constvalue(&store_tojson_data[_i].filter.value);
381 fail_unless(value != NULL,
382 "INTERNAL ERROR: sdb_memstore_expr_constvalue() = NULL");
384 filter = store_tojson_data[_i].filter.m(field, value);
385 fail_unless(filter != NULL,
386 "INTERNAL ERROR: sdb_memstore_*_matcher() = NULL");
388 sdb_object_deref(SDB_OBJ(field));
389 sdb_object_deref(SDB_OBJ(value));
390 }
392 sdb_strbuf_clear(buf);
393 f = sdb_store_json_formatter(buf, store_tojson_data[_i].type, SDB_WANT_ARRAY);
394 ck_assert(f != NULL);
396 status = sdb_memstore_scan(store, store_tojson_data[_i].type,
397 /* m = */ NULL, filter, store_tojson_data[_i].f, f);
398 fail_unless(status == 0,
399 "sdb_memstore_scan(HOST, ..., tojson) = %d; expected: 0",
400 status);
401 sdb_store_json_finish(f);
403 verify_json_output(buf, store_tojson_data[_i].expected);
405 sdb_object_deref(SDB_OBJ(filter));
406 sdb_object_deref(SDB_OBJ(f));
407 sdb_strbuf_destroy(buf);
408 }
409 END_TEST
411 TEST_MAIN("core::store_json")
412 {
413 TCase *tc = tcase_create("core");
414 tcase_add_unchecked_fixture(tc, populate, turndown);
415 TC_ADD_LOOP_TEST(tc, store_tojson);
416 ADD_TCASE(tc);
417 }
418 TEST_MAIN_END
420 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */