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