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