Code

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