Code

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