Code

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