Code

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