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