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