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