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