Code

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