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