Code

t/: Added tests for json_formatter-based JSON generation.
[sysdb.git] / t / unit / core / store_json_test.c
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 #include "core/store.h"
29 #include "libsysdb_test.h"
31 #include <assert.h>
33 #include <check.h>
34 #include <stdlib.h>
36 static void
37 populate(void)
38 {
39         sdb_data_t datum;
41         sdb_store_host("h1", 1);
42         sdb_store_host("h2", 3);
44         datum.type = SDB_TYPE_STRING;
45         datum.data.string = "v1";
46         sdb_store_attribute("h1", "k1", &datum, 1);
47         datum.data.string = "v2";
48         sdb_store_attribute("h1", "k2", &datum, 2);
49         datum.data.string = "v3";
50         sdb_store_attribute("h1", "k3", &datum, 2);
52         /* make sure that older updates don't overwrite existing values */
53         datum.data.string = "fail";
54         sdb_store_attribute("h1", "k2", &datum, 1);
55         sdb_store_attribute("h1", "k3", &datum, 2);
57         sdb_store_metric("h1", "m1", /* store */ NULL, 2);
58         sdb_store_metric("h1", "m2", /* store */ NULL, 1);
59         sdb_store_metric("h2", "m1", /* store */ NULL, 1);
61         sdb_store_service("h2", "s1", 1);
62         sdb_store_service("h2", "s2", 2);
64         datum.type = SDB_TYPE_INTEGER;
65         datum.data.integer = 42;
66         sdb_store_metric_attr("h1", "m1", "k3", &datum, 2);
68         datum.data.integer = 123;
69         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
70         datum.data.integer = 4711;
71         sdb_store_service_attr("h2", "s2", "k2", &datum, 1);
73         /* don't overwrite k1 */
74         datum.data.integer = 666;
75         sdb_store_service_attr("h2", "s2", "k1", &datum, 2);
76 } /* populate */
78 static int
79 scan_tojson(sdb_store_obj_t *obj,
80                 sdb_store_matcher_t __attribute__((unused)) *filter,
81                 void *user_data)
82 {
83         sdb_store_json_formatter_t *f = user_data;
84         return sdb_store_json_emit(f, obj);
85 } /* scan_tojson */
87 static int
88 scan_tojson_full(sdb_store_obj_t *obj, sdb_store_matcher_t *filter,
89                 void *user_data)
90 {
91         sdb_store_json_formatter_t *f = user_data;
92         return sdb_store_json_emit_full(f, obj, filter);
93 } /* scan_tojson_full */
95 static void
96 verify_json_output(sdb_strbuf_t *buf, const char *expected)
97 {
98         const char *got = sdb_strbuf_string(buf);
99         size_t len1 = strlen(got);
100         size_t len2 = strlen(expected);
102         size_t i;
103         int pos = -1;
105         if (len1 != len2)
106                 pos = (int)SDB_MIN(len1, len2);
108         for (i = 0; i < SDB_MIN(len1, len2); ++i) {
109                 if (got[i] != expected[i]) {
110                         pos = (int)i;
111                         break;
112                 }
113         }
115         fail_unless(pos == -1,
116                         "Serializing hosts to JSON returned unexpected result\n"
117                         "         got: %s\n              %*s\n    expected: %s",
118                         got, pos + 1, "^", expected);
119 } /* verify_json_output */
121 START_TEST(test_store_tojson)
123         sdb_strbuf_t *buf;
124         size_t i;
126         struct {
127                 struct {
128                         sdb_store_matcher_t *(*m)(sdb_store_expr_t *,
129                                         sdb_store_expr_t *);
130                         int field;
131                         sdb_data_t value;
132                 } filter;
133                 int (*f)(sdb_store_obj_t *, sdb_store_matcher_t *, void *);
134                 const char *expected;
135         } golden_data[] = {
136                 { { NULL, 0, SDB_DATA_INIT }, scan_tojson_full,
137                         "["
138                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
139                                         "\"update_interval\": \"0s\", \"backends\": [], "
140                                         "\"attributes\": ["
141                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
142                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
143                                                         "\"update_interval\": \"0s\", \"backends\": []},"
144                                                 "{\"name\": \"k2\", \"value\": \"v2\", "
145                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
146                                                         "\"update_interval\": \"0s\", \"backends\": []},"
147                                                 "{\"name\": \"k3\", \"value\": \"v3\", "
148                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
149                                                         "\"update_interval\": \"0s\", \"backends\": []}"
150                                         "], "
151                                         "\"metrics\": ["
152                                                 "{\"name\": \"m1\", "
153                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
154                                                         "\"update_interval\": \"0s\", \"backends\": [], "
155                                                         "\"attributes\": ["
156                                                                 "{\"name\": \"k3\", \"value\": 42, "
157                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
158                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
159                                                         "]},"
160                                                 "{\"name\": \"m2\", "
161                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
162                                                         "\"update_interval\": \"0s\", \"backends\": []}"
163                                         "]},"
164                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
165                                         "\"update_interval\": \"0s\", \"backends\": [], "
166                                         "\"metrics\": ["
167                                                 "{\"name\": \"m1\", "
168                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
169                                                         "\"update_interval\": \"0s\", \"backends\": []}"
170                                         "], "
171                                         "\"services\": ["
172                                                 "{\"name\": \"s1\", "
173                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
174                                                         "\"update_interval\": \"0s\", \"backends\": []},"
175                                                 "{\"name\": \"s2\", "
176                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
177                                                         "\"update_interval\": \"0s\", \"backends\": [], "
178                                                         "\"attributes\": ["
179                                                                 "{\"name\": \"k1\", \"value\": 123, "
180                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
181                                                                         "\"update_interval\": \"0s\", \"backends\": []},"
182                                                                 "{\"name\": \"k2\", \"value\": 4711, "
183                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
184                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
185                                                         "]}"
186                                         "]}"
187                         "]" },
188                 { { NULL, 0, SDB_DATA_INIT }, scan_tojson,
189                         "["
190                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
191                                         "\"update_interval\": \"0s\", \"backends\": []},"
192                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
193                                         "\"update_interval\": \"0s\", \"backends\": []}"
194                         "]" },
195                 { { sdb_store_eq_matcher, SDB_FIELD_NAME,
196                                 { SDB_TYPE_STRING, { .string = "h1" } } }, scan_tojson_full,
197                         "["
198                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
199                                         "\"update_interval\": \"0s\", \"backends\": []}"
200                         "]" },
201                 { { sdb_store_gt_matcher, SDB_FIELD_LAST_UPDATE,
202                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, scan_tojson_full,
203                         "["
204                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
205                                         "\"update_interval\": \"0s\", \"backends\": [], "
206                                         "\"services\": ["
207                                                 "{\"name\": \"s2\", "
208                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
209                                                         "\"update_interval\": \"0s\", \"backends\": [], "
210                                                         "\"attributes\": ["
211                                                                 "{\"name\": \"k1\", \"value\": 123, "
212                                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
213                                                                         "\"update_interval\": \"0s\", \"backends\": []}"
214                                                         "]}"
215                                         "]}"
216                         "]" },
217                 { { sdb_store_le_matcher, SDB_FIELD_LAST_UPDATE,
218                                 { SDB_TYPE_DATETIME, { .datetime = 1 } } }, scan_tojson_full,
219                         "["
220                                 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
221                                         "\"update_interval\": \"0s\", \"backends\": [], "
222                                         "\"attributes\": ["
223                                                 "{\"name\": \"k1\", \"value\": \"v1\", "
224                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
225                                                         "\"update_interval\": \"0s\", \"backends\": []}"
226                                         "], "
227                                         "\"metrics\": ["
228                                                 "{\"name\": \"m2\", "
229                                                         "\"last_update\": \"1970-01-01 00:00:00 +0000\", "
230                                                         "\"update_interval\": \"0s\", \"backends\": []}"
231                                         "]}"
232                         "]" },
233                 { { sdb_store_ge_matcher, SDB_FIELD_LAST_UPDATE,
234                                 { SDB_TYPE_DATETIME, { .datetime = 3 } } }, scan_tojson_full,
235                         "["
236                                 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:00 +0000\", "
237                                         "\"update_interval\": \"0s\", \"backends\": []}"
238                         "]" },
239         };
241         buf = sdb_strbuf_create(0);
242         fail_unless(buf != NULL, "INTERNAL ERROR: failed to create string buffer");
243         populate();
245         for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
246                 sdb_store_matcher_t *filter = NULL;
247                 sdb_store_json_formatter_t *f;
248                 int status;
250                 sdb_strbuf_clear(buf);
252                 if (golden_data[i].filter.m) {
253                         sdb_store_expr_t *field;
254                         sdb_store_expr_t *value;
256                         field = sdb_store_expr_fieldvalue(golden_data[i].filter.field);
257                         fail_unless(field != NULL,
258                                         "INTERNAL ERROR: sdb_store_expr_fieldvalue() = NULL");
259                         value = sdb_store_expr_constvalue(&golden_data[i].filter.value);
260                         fail_unless(value != NULL,
261                                         "INTERNAL ERROR: sdb_store_expr_constvalue() = NULL");
263                         filter = golden_data[i].filter.m(field, value);
264                         fail_unless(filter != NULL,
265                                         "INTERNAL ERROR: sdb_store_*_matcher() = NULL");
267                         sdb_object_deref(SDB_OBJ(field));
268                         sdb_object_deref(SDB_OBJ(value));
269                 }
271                 sdb_strbuf_clear(buf);
272                 f = sdb_store_json_formatter(buf);
273                 assert(f);
275                 sdb_strbuf_append(buf, "[");
276                 status = sdb_store_scan(SDB_HOST, /* m = */ NULL, filter,
277                                 golden_data[i].f, f);
278                 fail_unless(status == 0,
279                                 "sdb_store_scan(HOST, ..., tojson) = %d; expected: 0",
280                                 status);
281                 sdb_store_json_finish(f);
282                 sdb_strbuf_append(buf, "]");
284                 verify_json_output(buf, golden_data[i].expected);
285                 free(f);
286                 sdb_object_deref(SDB_OBJ(filter));
287         }
288         sdb_strbuf_destroy(buf);
290 END_TEST
292 Suite *
293 core_store_json_suite(void)
295         Suite *s = suite_create("core::store_json");
296         TCase *tc;
298         tc = tcase_create("core");
299         tcase_add_test(tc, test_store_tojson);
300         tcase_add_unchecked_fixture(tc, NULL, sdb_store_clear);
301         suite_add_tcase(s, tc);
303         return s;
304 } /* core_store_json_suite */
306 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */