Code

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