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