de8ab806843a34be4942f78939864dc275d06f1c
1 /*
2 * SysDB - t/unit/frontend/query_test.c
3 * Copyright (C) 2015 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/plugin.h"
33 #include "frontend/connection.h"
34 #include "frontend/connection-private.h"
35 #include "testutils.h"
37 #include <check.h>
39 /*
40 * private helpers
41 */
43 static void
44 populate(void)
45 {
46 sdb_store_t *store;
47 sdb_data_t datum;
49 /* the frontend accesses the store via the plugin API */
50 store = sdb_store_create();
51 ck_assert(store != NULL);
52 ck_assert(sdb_plugin_register_writer("test-writer",
53 &sdb_store_writer, SDB_OBJ(store)) == 0);
54 ck_assert(sdb_plugin_register_reader("test-reader",
55 &sdb_store_reader, SDB_OBJ(store)) == 0);
56 sdb_object_deref(SDB_OBJ(store));
58 /* populate the store */
59 sdb_plugin_store_host("h1", 1 * SDB_INTERVAL_SECOND);
60 sdb_plugin_store_host("h2", 3 * SDB_INTERVAL_SECOND);
62 datum.type = SDB_TYPE_STRING;
63 datum.data.string = "v1";
64 sdb_plugin_store_attribute("h1", "k1", &datum, 1 * SDB_INTERVAL_SECOND);
65 datum.data.string = "v2";
66 sdb_plugin_store_attribute("h1", "k2", &datum, 2 * SDB_INTERVAL_SECOND);
67 datum.data.string = "v3";
68 sdb_plugin_store_attribute("h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND);
70 sdb_plugin_store_metric("h1", "m1", /* store */ NULL, 2 * SDB_INTERVAL_SECOND);
71 sdb_plugin_store_metric("h1", "m2", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
72 sdb_plugin_store_metric("h2", "m1", /* store */ NULL, 5 * SDB_INTERVAL_SECOND);
73 sdb_plugin_store_metric("h2", "m1", /* store */ NULL, 10 * SDB_INTERVAL_SECOND);
75 datum.type = SDB_TYPE_INTEGER;
76 datum.data.integer = 42;
77 sdb_plugin_store_metric_attribute("h1", "m1", "k3",
78 &datum, 2 * SDB_INTERVAL_SECOND);
80 sdb_plugin_store_service("h2", "s1", 1 * SDB_INTERVAL_SECOND);
81 sdb_plugin_store_service("h2", "s2", 2 * SDB_INTERVAL_SECOND);
83 datum.data.integer = 123;
84 sdb_plugin_store_service_attribute("h2", "s2", "k1",
85 &datum, 2 * SDB_INTERVAL_SECOND);
86 datum.data.integer = 4711;
87 sdb_plugin_store_service_attribute("h2", "s2", "k2",
88 &datum, 1 * SDB_INTERVAL_SECOND);
89 } /* populate */
91 static void
92 turndown(void)
93 {
94 sdb_plugin_unregister_all();
95 } /* turndown */
97 #define HOST_H1 \
98 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
99 "\"update_interval\": \"0s\", \"backends\": [], " \
100 "\"attributes\": [" \
101 "{\"name\": \"k1\", \"value\": \"v1\", " \
102 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
103 "\"update_interval\": \"0s\", \"backends\": []}," \
104 "{\"name\": \"k2\", \"value\": \"v2\", " \
105 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
106 "\"update_interval\": \"0s\", \"backends\": []}," \
107 "{\"name\": \"k3\", \"value\": \"v3\", " \
108 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
109 "\"update_interval\": \"0s\", \"backends\": []}], " \
110 "\"metrics\": [" \
111 "{\"name\": \"m1\", \"timeseries\": false, " \
112 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
113 "\"update_interval\": \"0s\", \"backends\": [], " \
114 "\"attributes\": [" \
115 "{\"name\": \"hostname\", \"value\": \"h1\", " \
116 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
117 "\"update_interval\": \"0s\", \"backends\": []}," \
118 "{\"name\": \"k3\", \"value\": 42, " \
119 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
120 "\"update_interval\": \"0s\", \"backends\": []}]}," \
121 "{\"name\": \"m2\", \"timeseries\": false, " \
122 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
123 "\"update_interval\": \"0s\", \"backends\": [], " \
124 "\"attributes\": [" \
125 "{\"name\": \"hostname\", \"value\": \"h1\", " \
126 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
127 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
128 #define HOST_H2 \
129 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
130 "\"update_interval\": \"0s\", \"backends\": [], " \
131 "\"metrics\": [" \
132 "{\"name\": \"m1\", \"timeseries\": false, " \
133 "\"last_update\": \"1970-01-01 00:00:10 +0000\", " \
134 "\"update_interval\": \"5s\", \"backends\": [], " \
135 "\"attributes\": [" \
136 "{\"name\": \"hostname\", \"value\": \"h2\", " \
137 "\"last_update\": \"1970-01-01 00:00:10 +0000\", " \
138 "\"update_interval\": \"5s\", \"backends\": []}]}], " \
139 "\"services\": [" \
140 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
141 "\"update_interval\": \"0s\", \"backends\": [], " \
142 "\"attributes\": [" \
143 "{\"name\": \"hostname\", \"value\": \"h2\", " \
144 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
145 "\"update_interval\": \"0s\", \"backends\": []}]}," \
146 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:02 +0000\", " \
147 "\"update_interval\": \"0s\", \"backends\": [], " \
148 "\"attributes\": [" \
149 "{\"name\": \"hostname\", \"value\": \"h2\", " \
150 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
151 "\"update_interval\": \"0s\", \"backends\": []}," \
152 "{\"name\": \"k1\", \"value\": 123, " \
153 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
154 "\"update_interval\": \"0s\", \"backends\": []}," \
155 "{\"name\": \"k2\", \"value\": 4711, " \
156 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
157 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
158 #define HOST_H1_ARRAY "["HOST_H1"]"
159 #define HOST_H12_ARRAY "["HOST_H1","HOST_H2"]"
160 #define HOST_H1_LISTING \
161 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
162 "\"update_interval\": \"0s\", \"backends\": []}"
163 #define HOST_H2_LISTING \
164 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
165 "\"update_interval\": \"0s\", \"backends\": []}"
167 #define SERVICE_H2_S1 \
168 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
169 "\"update_interval\": \"0s\", \"backends\": [], " \
170 "\"services\": [" \
171 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
172 "\"update_interval\": \"0s\", \"backends\": [], " \
173 "\"attributes\": [" \
174 "{\"name\": \"hostname\", \"value\": \"h2\", " \
175 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
176 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
177 #define SERVICE_H2_S12 \
178 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
179 "\"update_interval\": \"0s\", \"backends\": [], " \
180 "\"services\": [" \
181 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
182 "\"update_interval\": \"0s\", \"backends\": [], " \
183 "\"attributes\": [" \
184 "{\"name\": \"hostname\", \"value\": \"h2\", " \
185 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
186 "\"update_interval\": \"0s\", \"backends\": []}]}," \
187 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:02 +0000\", " \
188 "\"update_interval\": \"0s\", \"backends\": [], " \
189 "\"attributes\": [" \
190 "{\"name\": \"hostname\", \"value\": \"h2\", " \
191 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
192 "\"update_interval\": \"0s\", \"backends\": []}," \
193 "{\"name\": \"k1\", \"value\": 123, " \
194 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
195 "\"update_interval\": \"0s\", \"backends\": []}," \
196 "{\"name\": \"k2\", \"value\": 4711, " \
197 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
198 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
199 #define SERVICE_H2_S1_ARRAY "["SERVICE_H2_S1"]"
200 #define SERVICE_H2_S12_LISTING \
201 "[{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
202 "\"update_interval\": \"0s\", \"backends\": [], " \
203 "\"services\": [" \
204 "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
205 "\"update_interval\": \"0s\", \"backends\": []}," \
206 "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:02 +0000\", " \
207 "\"update_interval\": \"0s\", \"backends\": []}]}]"
209 #define METRIC_H1_M1 \
210 "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
211 "\"update_interval\": \"0s\", \"backends\": [], " \
212 "\"metrics\": [" \
213 "{\"name\": \"m1\", \"timeseries\": false, " \
214 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
215 "\"update_interval\": \"0s\", \"backends\": [], " \
216 "\"attributes\": [" \
217 "{\"name\": \"hostname\", \"value\": \"h1\", " \
218 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
219 "\"update_interval\": \"0s\", \"backends\": []}," \
220 "{\"name\": \"k3\", \"value\": 42, " \
221 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
222 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
223 #define METRIC_H2_M1 \
224 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
225 "\"update_interval\": \"0s\", \"backends\": [], " \
226 "\"metrics\": [" \
227 "{\"name\": \"m1\", \"timeseries\": false, " \
228 "\"last_update\": \"1970-01-01 00:00:10 +0000\", " \
229 "\"update_interval\": \"5s\", \"backends\": [], " \
230 "\"attributes\": [" \
231 "{\"name\": \"hostname\", \"value\": \"h2\", " \
232 "\"last_update\": \"1970-01-01 00:00:10 +0000\", " \
233 "\"update_interval\": \"5s\", \"backends\": []}]}]}"
234 #define METRIC_H12_M1_ARRAY \
235 "["METRIC_H1_M1","METRIC_H2_M1"]"
236 #define METRIC_H12_M12_LISTING \
237 "[{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
238 "\"update_interval\": \"0s\", \"backends\": [], " \
239 "\"metrics\": [" \
240 "{\"name\": \"m1\", \"timeseries\": false, " \
241 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
242 "\"update_interval\": \"0s\", \"backends\": []}," \
243 "{\"name\": \"m2\", \"timeseries\": false, " \
244 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
245 "\"update_interval\": \"0s\", \"backends\": []}]}," \
246 "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
247 "\"update_interval\": \"0s\", \"backends\": [], " \
248 "\"metrics\": [" \
249 "{\"name\": \"m1\", \"timeseries\": false, " \
250 "\"last_update\": \"1970-01-01 00:00:10 +0000\", " \
251 "\"update_interval\": \"5s\", \"backends\": []}]}]"
253 typedef struct {
254 sdb_conn_t conn;
255 sdb_strbuf_t *write_buf;
256 } mock_conn_t;
257 #define MOCK_CONN(obj) ((mock_conn_t *)(obj))
258 #define CONN(obj) ((sdb_conn_t *)(obj))
260 static void
261 mock_conn_destroy(sdb_conn_t *conn)
262 {
263 sdb_strbuf_destroy(conn->buf);
264 sdb_strbuf_destroy(conn->errbuf);
265 sdb_strbuf_destroy(MOCK_CONN(conn)->write_buf);
266 free(conn);
267 } /* mock_conn_destroy */
269 static ssize_t
270 mock_conn_read(sdb_conn_t *conn, size_t len)
271 {
272 if (! conn)
273 return -1;
274 /* unused so far */
275 return len;
276 } /* conn_read */
278 static ssize_t
279 mock_conn_write(sdb_conn_t *conn, const void *buf, size_t len)
280 {
281 if (! conn)
282 return -1;
283 return sdb_strbuf_memappend(MOCK_CONN(conn)->write_buf, buf, len);
284 } /* conn_write */
286 static sdb_conn_t *
287 mock_conn_create(void)
288 {
289 mock_conn_t *conn;
291 conn = calloc(1, sizeof(*conn));
292 if (! conn) {
293 fail("INTERNAL ERROR: failed to allocate connection object");
294 return NULL;
295 }
297 SDB_OBJ(conn)->name = "mock_connection";
298 SDB_OBJ(conn)->ref_cnt = 1;
300 conn->conn.buf = sdb_strbuf_create(0);
301 conn->conn.errbuf = sdb_strbuf_create(0);
302 conn->write_buf = sdb_strbuf_create(64);
303 if ((! conn->conn.buf) || (! conn->conn.errbuf) || (! conn->write_buf)) {
304 mock_conn_destroy(CONN(conn));
305 fail("INTERNAL ERROR: failed to allocate connection object");
306 return NULL;
307 }
309 conn->conn.read = mock_conn_read;
310 conn->conn.write = mock_conn_write;
312 conn->conn.username = "mock_user";
313 conn->conn.cmd = SDB_CONNECTION_IDLE;
314 conn->conn.cmd_len = 0;
315 return CONN(conn);
316 } /* mock_conn_create */
318 /* TODO: move this into a test helper module */
319 static void
320 fail_if_strneq(const char *got, const char *expected, size_t n, const char *fmt, ...)
321 {
322 sdb_strbuf_t *buf;
323 va_list ap;
325 size_t len1 = strlen(got);
326 size_t len2 = strlen(expected);
328 size_t i;
329 int pos = -1;
331 if (n) {
332 len1 = SDB_MIN(len1, n);
333 len2 = SDB_MIN(len2, n);
334 }
336 if (len1 != len2)
337 pos = (int)SDB_MIN(len1, len2);
339 for (i = 0; i < SDB_MIN(len1, len2); ++i) {
340 if (got[i] != expected[i]) {
341 pos = (int)i;
342 break;
343 }
344 }
346 if (pos == -1)
347 return;
349 buf = sdb_strbuf_create(64);
350 va_start(ap, fmt);
351 sdb_strbuf_vsprintf(buf, fmt, ap);
353 fail("%s\n got: %s\n %*s\n expected: %s",
354 sdb_strbuf_string(buf), got, pos + 1, "^", expected);
355 } /* fail_if_strneq */
357 /*
358 * tests
359 */
361 #define VALUE "\0\0\0\4""v1"
362 #define VALUE_LEN 7
364 static struct {
365 uint32_t cmd;
366 const char *query;
367 int query_len;
368 int expected;
369 uint32_t code;
370 size_t len;
371 uint32_t type;
372 const char *data;
373 } query_data[] = {
374 /* hosts */
375 {
376 SDB_CONNECTION_QUERY, "LIST hosts", -1,
377 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
378 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
379 },
380 {
381 SDB_CONNECTION_LIST, "\0\0\0\1", 4,
382 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
383 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
384 },
385 {
386 SDB_CONNECTION_LIST, "", 0, /* LIST defaults to hosts */
387 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
388 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
389 },
390 {
391 SDB_CONNECTION_QUERY, "LIST hosts; LIST hosts", -1, /* ignore second (and later) commands */
392 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
393 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
394 },
395 {
396 SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 'h1'", -1,
397 0, SDB_CONNECTION_DATA, 105, SDB_CONNECTION_LIST, "["HOST_H1_LISTING"]",
398 },
399 {
400 SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 's1'", -1,
401 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
402 },
403 /* SDB_CONNECTION_LIST doesn't support filters yet */
404 {
405 SDB_CONNECTION_QUERY, "FETCH host 'h1'", -1,
406 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
407 },
408 {
409 SDB_CONNECTION_FETCH, "\0\0\0\1""h1", 7,
410 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
411 },
412 {
413 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1'", -1,
414 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
415 },
416 {
417 SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'h1'", 16,
418 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
419 },
420 {
421 SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age >= 0s", -1, /* always matches */
422 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
423 },
424 /* SDB_CONNECTION_FETCH doesn't support filters yet */
425 {
426 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age >= 0s", -1, /* always matches */
427 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
428 },
429 {
430 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend = 'b'", -1,
431 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
432 },
433 {
434 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING ANY backend || 'b' = 'b'", -1,
435 0, SDB_CONNECTION_DATA, 2205, SDB_CONNECTION_LOOKUP, HOST_H12_ARRAY,
436 },
437 {
438 SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age < 0s", -1, /* never matches */
439 -1, UINT32_MAX, 0, 0, NULL, /* FETCH fails if the object doesn't exist */
440 },
441 /* SDB_CONNECTION_FETCH doesn't support filters yet */
442 {
443 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age < 0s", -1, /* never matches */
444 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
445 },
446 /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
447 {
448 SDB_CONNECTION_QUERY, "FETCH host 'x1'", -1, /* does not exist */
449 -1, UINT32_MAX, 0, 0, NULL,
450 },
451 {
452 SDB_CONNECTION_FETCH, "\0\0\0\1x1", 7,
453 -1, UINT32_MAX, 0, 0, NULL,
454 },
455 {
456 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'x1'", -1, /* does not exist */
457 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
458 },
459 {
460 SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'x1'", 16, /* does not exist */
461 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
462 },
463 {
464 SDB_CONNECTION_QUERY, "FETCH host 'h1'.'s1'", -1, /* invalid args */
465 -1, UINT32_MAX, 0, 0, NULL,
466 },
467 {
468 SDB_CONNECTION_QUERY, "LOOKUP hosts BY name = 'x1'", -1, /* does not exist */
469 -1, UINT32_MAX, 0, 0, NULL,
470 },
471 /* services */
472 {
473 SDB_CONNECTION_QUERY, "LIST services", -1,
474 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
475 },
476 {
477 SDB_CONNECTION_LIST, "\0\0\0\2", 4,
478 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
479 },
480 {
481 SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h2'", -1,
482 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
483 },
484 {
485 SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h1'", -1,
486 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
487 },
488 /* SDB_CONNECTION_LIST doesn't support filters yet */
489 {
490 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1'", -1,
491 0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
492 },
493 /* SDB_CONNECTION_FETCH doesn't support services yet */
494 {
495 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1'", -1,
496 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
497 },
498 {
499 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING host.name = 'h2'", -1,
500 0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
501 },
502 {
503 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.name = 'm1'", -1,
504 0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
505 },
506 {
507 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.last_update = 10s", -1,
508 0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
509 },
510 {
511 /* stupid but valid ;-) */
512 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.host.metric.metric.interval = 5s", -1,
513 0, SDB_CONNECTION_DATA, 825, SDB_CONNECTION_LOOKUP, "["SERVICE_H2_S12"]",
514 },
515 {
516 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING ANY host.metric.name = 'mX'", -1,
517 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
518 },
519 {
520 SDB_CONNECTION_LOOKUP, "\0\0\0\2""name = 's1'", 16,
521 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
522 },
523 {
524 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age >= 0s", -1, /* always matches */
525 0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
526 },
527 /* SDB_CONNECTION_FETCH doesn't support services yet */
528 {
529 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age >= 0s", -1, /* always matches */
530 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
531 },
532 {
533 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age < 0s", -1, /* never matches */
534 -1, UINT32_MAX, 0, 0, NULL,
535 },
536 /* SDB_CONNECTION_FETCH doesn't support services yet */
537 {
538 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age < 0s", -1, /* never matches */
539 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
540 },
541 /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
542 {
543 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER name = 'h2'", -1, /* only matches host */
544 -1, UINT32_MAX, 0, 0, NULL,
545 },
546 /* SDB_CONNECTION_FETCH doesn't support services yet */
547 {
548 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER name = 'h2'", -1, /* only matches host */
549 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
550 },
551 {
552 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'x1'", -1, /* does not exist */
553 -1, UINT32_MAX, 0, 0, NULL,
554 },
555 /* SDB_CONNECTION_FETCH doesn't support services yet */
556 {
557 SDB_CONNECTION_QUERY, "FETCH service 'x2'.'s1'", -1, /* does not exist */
558 -1, UINT32_MAX, 0, 0, NULL,
559 },
560 /* SDB_CONNECTION_FETCH doesn't support services yet */
561 {
562 SDB_CONNECTION_QUERY, "FETCH service 'h2'", -1, /* invalid args */
563 -1, UINT32_MAX, 0, 0, NULL,
564 },
565 /* SDB_CONNECTION_FETCH doesn't support services yet */
566 /* metrics */
567 {
568 SDB_CONNECTION_QUERY, "LIST metrics", -1,
569 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
570 },
571 {
572 SDB_CONNECTION_LIST, "\0\0\0\3", 4,
573 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
574 },
575 {
576 SDB_CONNECTION_QUERY, "LIST metrics FILTER age > 0s", -1,
577 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
578 },
579 {
580 SDB_CONNECTION_QUERY, "LIST metrics FILTER age < 0s", -1,
581 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
582 },
583 /* SDB_CONNECTION_LIST doesn't support filters yet */
584 {
585 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1'", -1,
586 0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
587 },
588 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
589 {
590 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1'", -1,
591 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
592 },
593 {
594 /* stupid but valid ;-) */
595 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING metric.metric.name = 'm1'", -1,
596 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
597 },
598 {
599 /* also stupid but valid ;-) */
600 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING metric.metric.host.host.last_update = 3s", -1,
601 0, SDB_CONNECTION_DATA, 378, SDB_CONNECTION_LOOKUP, "["METRIC_H2_M1"]",
602 },
603 {
604 SDB_CONNECTION_LOOKUP, "\0\0\0\3""name = 'm1'", 16,
605 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
606 },
607 {
608 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age >= 0s", -1, /* always matches */
609 0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
610 },
611 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
612 {
613 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age >= 0s", -1, /* always matches */
614 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
615 },
616 {
617 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age < 0s", -1, /* never matches */
618 -1, UINT32_MAX, 0, 0, NULL,
619 },
620 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
621 {
622 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age < 0s", -1, /* never matches */
623 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
624 },
625 /* SDB_CONEECTION_LOOKUP doesn't support filters yet */
626 {
627 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER name = 'h1'", -1, /* only matches host */
628 -1, UINT32_MAX, 0, 0, NULL,
629 },
630 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
631 {
632 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER name = 'h1'", -1, /* only matches host */
633 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
634 },
635 {
636 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'x1'", -1, /* does not exist */
637 -1, UINT32_MAX, 0, 0, NULL,
638 },
639 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
640 {
641 SDB_CONNECTION_QUERY, "FETCH metric 'x1'.'m1'", -1, /* does not exist */
642 -1, UINT32_MAX, 0, 0, NULL,
643 },
644 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
645 {
646 SDB_CONNECTION_QUERY, "FETCH metric 'x1'", -1, /* invalid args */
647 -1, UINT32_MAX, 0, 0, NULL,
648 },
649 /* SDB_CONNECTION_FETCH doesn't support metrics yet */
650 /* timeseries */
651 {
652 SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'m1'", -1,
653 -1, UINT32_MAX, 0, 0, NULL, /* no data-store available */
654 },
655 {
656 SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'x1'", -1,
657 -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
658 },
659 {
660 SDB_CONNECTION_QUERY, "TIMESERIES 'x1'.'m1'", -1,
661 -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
662 },
663 /* store commands */
664 {
665 SDB_CONNECTION_QUERY, "STORE host 'hA' LAST UPDATE 01:00", -1,
666 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
667 },
668 {
669 SDB_CONNECTION_STORE, "\0\0\0\1""\0\0\0\0\xd6\x93\xa4\0""hA", 15,
670 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
671 },
672 {
673 SDB_CONNECTION_QUERY, "STORE host 'hA'", -1,
674 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
675 },
676 {
677 SDB_CONNECTION_QUERY, "STORE host attribute 'h1'.'aA' 'vA'", -1,
678 0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
679 },
680 {
681 SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""h1\0aA\0"VALUE, 18+VALUE_LEN,
682 0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
683 },
684 {
685 SDB_CONNECTION_QUERY, "STORE host attribute 'x1'.'aA' 'vA'", -1,
686 -1, UINT32_MAX, 0, 0, NULL,
687 },
688 {
689 SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""x1\0aA\0"VALUE, 18+VALUE_LEN,
690 -1, UINT32_MAX, 0, 0, NULL,
691 },
692 {
693 SDB_CONNECTION_QUERY, "STORE service 'h1'.'sA'", -1,
694 0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
695 },
696 {
697 SDB_CONNECTION_STORE, "\0\0\0\2""\0\0\0\0\xd6\x93\xa4\0""h1\0sA", 18,
698 0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
699 },
700 {
701 SDB_CONNECTION_QUERY, "STORE service 'x1'.'sA'", -1,
702 -1, UINT32_MAX, 0, 0, NULL,
703 },
704 {
705 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""x1\0sA", 18,
706 -1, UINT32_MAX, 0, 0, NULL,
707 },
708 {
709 SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'s1'.'aA' 'vA'", -1,
710 0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
711 },
712 {
713 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0s1\0aA\0"VALUE,27+VALUE_LEN,
714 0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
715 },
716 {
717 SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'x1'.'aA' 'vA'", -1,
718 -1, UINT32_MAX, 0, 0, NULL,
719 },
720 {
721 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0x1\0aA\0"VALUE,27+VALUE_LEN,
722 -1, UINT32_MAX, 0, 0, NULL,
723 },
724 {
725 SDB_CONNECTION_QUERY, "STORE metric 'h1'.'mA'", -1,
726 0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
727 },
728 {
729 SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""h1\0mA", 18,
730 0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
731 },
732 {
733 SDB_CONNECTION_QUERY, "STORE metric 'x1'.'mA'", -1,
734 -1, UINT32_MAX, 0, 0, NULL,
735 },
736 {
737 SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""x1\0mA", 18,
738 -1, UINT32_MAX, 0, 0, NULL,
739 },
740 {
741 SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'m1'.'aA' 'vA'", -1,
742 0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
743 },
744 {
745 SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0m1\0aA\0"VALUE, 27+VALUE_LEN,
746 0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
747 },
748 {
749 SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'x1'.'aA' 'vA'", -1,
750 -1, UINT32_MAX, 0, 0, NULL,
751 },
752 {
753 SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0x1\0aA\0"VALUE, 27+VALUE_LEN,
754 -1, UINT32_MAX, 0, 0, NULL,
755 },
756 };
758 START_TEST(test_query)
759 {
760 sdb_conn_t *conn = mock_conn_create();
762 uint32_t code = UINT32_MAX, msg_len = UINT32_MAX;
763 const char *data;
764 ssize_t tmp;
765 size_t len;
766 int check = -1;
768 conn->cmd = query_data[_i].cmd;
769 if (query_data[_i].query_len < 0)
770 conn->cmd_len = (uint32_t)strlen(query_data[_i].query);
771 else
772 conn->cmd_len = (uint32_t)query_data[_i].query_len;
773 sdb_strbuf_memcpy(conn->buf, query_data[_i].query, conn->cmd_len);
775 switch (conn->cmd) {
776 case SDB_CONNECTION_QUERY:
777 check = sdb_conn_query(conn);
778 break;
779 case SDB_CONNECTION_FETCH:
780 check = sdb_conn_fetch(conn);
781 break;
782 case SDB_CONNECTION_LIST:
783 check = sdb_conn_list(conn);
784 break;
785 case SDB_CONNECTION_LOOKUP:
786 check = sdb_conn_lookup(conn);
787 break;
788 /* SDB_CONNECTION_TIMESERIES not supported yet */
789 case SDB_CONNECTION_STORE:
790 check = sdb_conn_store(conn);
791 break;
792 default:
793 fail("Invalid command %#x", conn->cmd);
794 }
796 fail_unless(check == query_data[_i].expected,
797 "sdb_conn_query(%s) = %d; expected: %d (err: %s)",
798 query_data[_i].query, check, query_data[_i].expected,
799 sdb_strbuf_string(conn->errbuf));
801 data = sdb_strbuf_string(MOCK_CONN(conn)->write_buf);
802 len = sdb_strbuf_len(MOCK_CONN(conn)->write_buf);
804 if (query_data[_i].code == UINT32_MAX) {
805 fail_unless(len == 0,
806 "sdb_conn_query(%s) returned data on error: '%s'",
807 query_data[_i].query, data);
808 mock_conn_destroy(conn);
809 return;
810 }
812 tmp = sdb_proto_unmarshal_header(data, len, &code, &msg_len);
813 ck_assert_msg(tmp == (ssize_t)(2 * sizeof(uint32_t)));
814 data += tmp;
815 len -= tmp;
817 fail_unless((code == query_data[_i].code)
818 && ((size_t)msg_len == query_data[_i].len),
819 "sdb_conn_query(%s) returned %u, %u; expected: %u, %zu",
820 query_data[_i].query, code, msg_len,
821 query_data[_i].code, query_data[_i].len);
823 if (code == SDB_CONNECTION_DATA) {
824 tmp = sdb_proto_unmarshal_int32(data, len, &code);
825 fail_unless(code == query_data[_i].type,
826 "sdb_conn_query(%s) returned %s object; expected: %s",
827 query_data[_i].query, SDB_CONN_MSGTYPE_TO_STRING((int)code),
828 SDB_CONN_MSGTYPE_TO_STRING((int)query_data[_i].type));
829 data += tmp;
830 len -= tmp;
831 }
833 fail_if_strneq(data, query_data[_i].data, (size_t)msg_len,
834 "sdb_conn_query(%s) returned unexpected data",
835 query_data[_i].query, data, query_data[_i].data);
837 mock_conn_destroy(conn);
838 }
839 END_TEST
841 TEST_MAIN("frontend::query")
842 {
843 TCase *tc = tcase_create("core");
844 tcase_add_checked_fixture(tc, populate, turndown);
845 TC_ADD_LOOP_TEST(tc, query);
846 ADD_TCASE(tc);
847 }
848 TEST_MAIN_END
850 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */