Code

frontend: Connection-specific functions now use the sdb_conn_ prefix.
[sysdb.git] / t / unit / frontend / query_test.c
1 /*
2  * SysDB - t/unit/frontend/query_test.c
3  * Copyright (C) 2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif
32 #include "core/plugin.h"
33 #include "frontend/connection.h"
34 #include "frontend/connection-private.h"
35 #include "testutils.h"
37 #include <check.h>
39 /*
40  * private helpers
41  */
43 static void
44 populate(void)
45 {
46         sdb_store_t *store;
47         sdb_data_t datum;
49         /* the frontend accesses the store via the plugin API */
50         store = sdb_store_create();
51         ck_assert(store != NULL);
52         ck_assert(sdb_plugin_register_writer("test-writer",
53                                 &sdb_store_writer, SDB_OBJ(store)) == 0);
54         ck_assert(sdb_plugin_register_reader("test-reader",
55                                 &sdb_store_reader, SDB_OBJ(store)) == 0);
56         sdb_object_deref(SDB_OBJ(store));
58         /* populate the store */
59         sdb_plugin_store_host("h1", 1 * SDB_INTERVAL_SECOND);
60         sdb_plugin_store_host("h2", 3 * SDB_INTERVAL_SECOND);
62         datum.type = SDB_TYPE_STRING;
63         datum.data.string = "v1";
64         sdb_plugin_store_attribute("h1", "k1", &datum, 1 * SDB_INTERVAL_SECOND);
65         datum.data.string = "v2";
66         sdb_plugin_store_attribute("h1", "k2", &datum, 2 * SDB_INTERVAL_SECOND);
67         datum.data.string = "v3";
68         sdb_plugin_store_attribute("h1", "k3", &datum, 2 * SDB_INTERVAL_SECOND);
70         sdb_plugin_store_metric("h1", "m1", /* store */ NULL, 2 * SDB_INTERVAL_SECOND);
71         sdb_plugin_store_metric("h1", "m2", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
72         sdb_plugin_store_metric("h2", "m1", /* store */ NULL, 1 * SDB_INTERVAL_SECOND);
74         datum.type = SDB_TYPE_INTEGER;
75         datum.data.integer = 42;
76         sdb_plugin_store_metric_attribute("h1", "m1", "k3",
77                         &datum, 2 * SDB_INTERVAL_SECOND);
79         sdb_plugin_store_service("h2", "s1", 1 * SDB_INTERVAL_SECOND);
80         sdb_plugin_store_service("h2", "s2", 2 * SDB_INTERVAL_SECOND);
82         datum.data.integer = 123;
83         sdb_plugin_store_service_attribute("h2", "s2", "k1",
84                         &datum, 2 * SDB_INTERVAL_SECOND);
85         datum.data.integer = 4711;
86         sdb_plugin_store_service_attribute("h2", "s2", "k2",
87                         &datum, 1 * SDB_INTERVAL_SECOND);
88 } /* populate */
90 static void
91 turndown(void)
92 {
93         sdb_plugin_unregister_all();
94 } /* turndown */
96 #define HOST_H1 \
97         "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
98                         "\"update_interval\": \"0s\", \"backends\": [], " \
99                 "\"attributes\": [" \
100                         "{\"name\": \"k1\", \"value\": \"v1\", " \
101                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
102                                 "\"update_interval\": \"0s\", \"backends\": []}," \
103                         "{\"name\": \"k2\", \"value\": \"v2\", " \
104                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
105                                 "\"update_interval\": \"0s\", \"backends\": []}," \
106                         "{\"name\": \"k3\", \"value\": \"v3\", " \
107                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
108                                 "\"update_interval\": \"0s\", \"backends\": []}], " \
109                 "\"metrics\": [" \
110                         "{\"name\": \"m1\", \"timeseries\": false, " \
111                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
112                                 "\"update_interval\": \"0s\", \"backends\": [], " \
113                                 "\"attributes\": [" \
114                                         "{\"name\": \"hostname\", \"value\": \"h1\", " \
115                                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
116                                                 "\"update_interval\": \"0s\", \"backends\": []}," \
117                                         "{\"name\": \"k3\", \"value\": 42, " \
118                                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
119                                                 "\"update_interval\": \"0s\", \"backends\": []}]}," \
120                         "{\"name\": \"m2\", \"timeseries\": false, " \
121                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
122                                 "\"update_interval\": \"0s\", \"backends\": [], " \
123                                 "\"attributes\": [" \
124                                         "{\"name\": \"hostname\", \"value\": \"h1\", " \
125                                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
126                                                 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
127 #define HOST_H1_ARRAY "["HOST_H1"]"
128 #define HOST_H1_LISTING \
129         "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
130                         "\"update_interval\": \"0s\", \"backends\": []}"
131 #define HOST_H2_LISTING \
132         "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
133                         "\"update_interval\": \"0s\", \"backends\": []}"
135 #define SERVICE_H2_S1 \
136         "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
137                         "\"update_interval\": \"0s\", \"backends\": [], " \
138                 "\"services\": [" \
139                         "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
140                                 "\"update_interval\": \"0s\", \"backends\": [], " \
141                                 "\"attributes\": [" \
142                                         "{\"name\": \"hostname\", \"value\": \"h2\", " \
143                                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
144                                                 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
145 #define SERVICE_H2_S1_ARRAY "["SERVICE_H2_S1"]"
146 #define SERVICE_H2_S12_LISTING \
147         "[{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
148                         "\"update_interval\": \"0s\", \"backends\": [], " \
149                 "\"services\": [" \
150                         "{\"name\": \"s1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
151                                 "\"update_interval\": \"0s\", \"backends\": []}," \
152                         "{\"name\": \"s2\", \"last_update\": \"1970-01-01 00:00:02 +0000\", " \
153                                 "\"update_interval\": \"0s\", \"backends\": []}]}]"
155 #define METRIC_H1_M1 \
156         "{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
157                         "\"update_interval\": \"0s\", \"backends\": [], " \
158                 "\"metrics\": [" \
159                         "{\"name\": \"m1\", \"timeseries\": false, " \
160                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
161                                 "\"update_interval\": \"0s\", \"backends\": [], " \
162                                 "\"attributes\": [" \
163                                         "{\"name\": \"hostname\", \"value\": \"h1\", " \
164                                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
165                                                 "\"update_interval\": \"0s\", \"backends\": []}," \
166                                         "{\"name\": \"k3\", \"value\": 42, " \
167                                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
168                                                 "\"update_interval\": \"0s\", \"backends\": []}]}]}"
169 #define METRIC_H12_M1_ARRAY \
170         "["METRIC_H1_M1"," \
171         "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
172                         "\"update_interval\": \"0s\", \"backends\": [], " \
173                 "\"metrics\": [" \
174                         "{\"name\": \"m1\", \"timeseries\": false, " \
175                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
176                                 "\"update_interval\": \"0s\", \"backends\": [], " \
177                                 "\"attributes\": [" \
178                                         "{\"name\": \"hostname\", \"value\": \"h2\", " \
179                                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
180                                                 "\"update_interval\": \"0s\", \"backends\": []}]}]}]"
181 #define METRIC_H12_M12_LISTING \
182         "[{\"name\": \"h1\", \"last_update\": \"1970-01-01 00:00:01 +0000\", " \
183                         "\"update_interval\": \"0s\", \"backends\": [], " \
184                 "\"metrics\": [" \
185                         "{\"name\": \"m1\", \"timeseries\": false, " \
186                                 "\"last_update\": \"1970-01-01 00:00:02 +0000\", " \
187                                 "\"update_interval\": \"0s\", \"backends\": []}," \
188                         "{\"name\": \"m2\", \"timeseries\": false, " \
189                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
190                                 "\"update_interval\": \"0s\", \"backends\": []}]}," \
191         "{\"name\": \"h2\", \"last_update\": \"1970-01-01 00:00:03 +0000\", " \
192                         "\"update_interval\": \"0s\", \"backends\": [], " \
193                 "\"metrics\": [" \
194                         "{\"name\": \"m1\", \"timeseries\": false, " \
195                                 "\"last_update\": \"1970-01-01 00:00:01 +0000\", " \
196                                 "\"update_interval\": \"0s\", \"backends\": []}]}]"
198 typedef struct {
199         sdb_conn_t conn;
200         sdb_strbuf_t *write_buf;
201 } mock_conn_t;
202 #define MOCK_CONN(obj) ((mock_conn_t *)(obj))
203 #define CONN(obj) ((sdb_conn_t *)(obj))
205 static void
206 mock_conn_destroy(sdb_conn_t *conn)
208         sdb_strbuf_destroy(conn->buf);
209         sdb_strbuf_destroy(conn->errbuf);
210         sdb_strbuf_destroy(MOCK_CONN(conn)->write_buf);
211         free(conn);
212 } /* mock_conn_destroy */
214 static ssize_t
215 mock_conn_read(sdb_conn_t *conn, size_t len)
217         if (! conn)
218                 return -1;
219         /* unused so far */
220         return len;
221 } /* conn_read */
223 static ssize_t
224 mock_conn_write(sdb_conn_t *conn, const void *buf, size_t len)
226         if (! conn)
227                 return -1;
228         return sdb_strbuf_memappend(MOCK_CONN(conn)->write_buf, buf, len);
229 } /* conn_write */
231 static sdb_conn_t *
232 mock_conn_create(void)
234         mock_conn_t *conn;
236         conn = calloc(1, sizeof(*conn));
237         if (! conn) {
238                 fail("INTERNAL ERROR: failed to allocate connection object");
239                 return NULL;
240         }
242         SDB_OBJ(conn)->name = "mock_connection";
243         SDB_OBJ(conn)->ref_cnt = 1;
245         conn->conn.buf = sdb_strbuf_create(0);
246         conn->conn.errbuf = sdb_strbuf_create(0);
247         conn->write_buf = sdb_strbuf_create(64);
248         if ((! conn->conn.buf) || (! conn->conn.errbuf) || (! conn->write_buf)) {
249                 mock_conn_destroy(CONN(conn));
250                 fail("INTERNAL ERROR: failed to allocate connection object");
251                 return NULL;
252         }
254         conn->conn.read = mock_conn_read;
255         conn->conn.write = mock_conn_write;
257         conn->conn.username = "mock_user";
258         conn->conn.cmd = SDB_CONNECTION_IDLE;
259         conn->conn.cmd_len = 0;
260         return CONN(conn);
261 } /* mock_conn_create */
263 /* TODO: move this into a test helper module */
264 static void
265 fail_if_strneq(const char *got, const char *expected, size_t n, const char *fmt, ...)
267         sdb_strbuf_t *buf;
268         va_list ap;
270         size_t len1 = strlen(got);
271         size_t len2 = strlen(expected);
273         size_t i;
274         int pos = -1;
276         if (n) {
277                 len1 = SDB_MIN(len1, n);
278                 len2 = SDB_MIN(len2, n);
279         }
281         if (len1 != len2)
282                 pos = (int)SDB_MIN(len1, len2);
284         for (i = 0; i < SDB_MIN(len1, len2); ++i) {
285                 if (got[i] != expected[i]) {
286                         pos = (int)i;
287                         break;
288                 }
289         }
291         if (pos == -1)
292                 return;
294         buf = sdb_strbuf_create(64);
295         va_start(ap, fmt);
296         sdb_strbuf_vsprintf(buf, fmt, ap);
298         fail("%s\n         got: %s\n              %*s\n    expected: %s",
299                         sdb_strbuf_string(buf), got, pos + 1, "^", expected);
300 } /* fail_if_strneq */
302 /*
303  * tests
304  */
306 #define VALUE "\0\0\0\4""v1"
307 #define VALUE_LEN 7
309 static struct {
310         uint32_t cmd;
311         const char *query;
312         int query_len;
313         int expected;
314         uint32_t code;
315         size_t len;
316         uint32_t type;
317         const char *data;
318 } query_data[] = {
319         /* hosts */
320         {
321                 SDB_CONNECTION_QUERY, "LIST hosts", -1,
322                 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
323                 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
324         },
325         {
326                 SDB_CONNECTION_LIST, "\0\0\0\1", 4,
327                 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
328                 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
329         },
330         {
331                 SDB_CONNECTION_LIST, "", 0, /* LIST defaults to hosts */
332                 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
333                 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
334         },
335         {
336                 SDB_CONNECTION_QUERY, "LIST hosts; LIST hosts", -1, /* ignore second (and later) commands */
337                 0, SDB_CONNECTION_DATA, 205, SDB_CONNECTION_LIST,
338                 "["HOST_H1_LISTING","HOST_H2_LISTING"]",
339         },
340         {
341                 SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 'h1'", -1,
342                 0, SDB_CONNECTION_DATA, 105, SDB_CONNECTION_LIST, "["HOST_H1_LISTING"]",
343         },
344         {
345                 SDB_CONNECTION_QUERY, "LIST hosts FILTER name = 's1'", -1,
346                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
347         },
348         /* SDB_CONNECTION_LIST doesn't support filters yet */
349         {
350                 SDB_CONNECTION_QUERY, "FETCH host 'h1'", -1,
351                 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
352         },
353         {
354                 SDB_CONNECTION_FETCH, "\0\0\0\1""h1", 7,
355                 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
356         },
357         {
358                 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1'", -1,
359                 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
360         },
361         {
362                 SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'h1'", 16,
363                 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
364         },
365         {
366                 SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age >= 0s", -1, /* always matches */
367                 0, SDB_CONNECTION_DATA, 1110, SDB_CONNECTION_FETCH, HOST_H1,
368         },
369         /* SDB_CONNECTION_FETCH doesn't support filters yet */
370         {
371                 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age >= 0s", -1, /* always matches */
372                 0, SDB_CONNECTION_DATA, 1112, SDB_CONNECTION_LOOKUP, HOST_H1_ARRAY,
373         },
374         {
375                 SDB_CONNECTION_QUERY, "FETCH host 'h1' FILTER age < 0s", -1, /* never matches */
376                 -1, UINT32_MAX, 0, 0, NULL, /* FETCH fails if the object doesn't exist */
377         },
378         /* SDB_CONNECTION_FETCH doesn't support filters yet */
379         {
380                 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'h1' FILTER age < 0s", -1, /* never matches */
381                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
382         },
383         /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
384         {
385                 SDB_CONNECTION_QUERY, "FETCH host 'x1'", -1, /* does not exist */
386                 -1, UINT32_MAX, 0, 0, NULL,
387         },
388         {
389                 SDB_CONNECTION_FETCH, "\0\0\0\1x1", 7,
390                 -1, UINT32_MAX, 0, 0, NULL,
391         },
392         {
393                 SDB_CONNECTION_QUERY, "LOOKUP hosts MATCHING name = 'x1'", -1, /* does not exist */
394                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
395         },
396         {
397                 SDB_CONNECTION_LOOKUP, "\0\0\0\1""name = 'x1'", 16, /* does not exist */
398                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
399         },
400         {
401                 SDB_CONNECTION_QUERY, "FETCH host 'h1'.'s1'", -1, /* invalid args */
402                 -1, UINT32_MAX, 0, 0, NULL,
403         },
404         {
405                 SDB_CONNECTION_QUERY, "LOOKUP hosts BY name = 'x1'", -1, /* does not exist */
406                 -1, UINT32_MAX, 0, 0, NULL,
407         },
408         /* services */
409         {
410                 SDB_CONNECTION_QUERY, "LIST services", -1,
411                 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
412         },
413         {
414                 SDB_CONNECTION_LIST, "\0\0\0\2", 4,
415                 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
416         },
417         {
418                 SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h2'", -1,
419                 0, SDB_CONNECTION_DATA, 320, SDB_CONNECTION_LIST, SERVICE_H2_S12_LISTING,
420         },
421         {
422                 SDB_CONNECTION_QUERY, "LIST services FILTER host.name = 'h1'", -1,
423                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
424         },
425         /* SDB_CONNECTION_LIST doesn't support filters yet */
426         {
427                 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1'", -1,
428                 0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
429         },
430         /* SDB_CONNECTION_FETCH doesn't support services yet */
431         {
432                 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1'", -1,
433                 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
434         },
435         {
436                 SDB_CONNECTION_LOOKUP, "\0\0\0\2""name = 's1'", 16,
437                 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
438         },
439         {
440                 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age >= 0s", -1, /* always matches */
441                 0, SDB_CONNECTION_DATA, 356, SDB_CONNECTION_FETCH, SERVICE_H2_S1,
442         },
443         /* SDB_CONNECTION_FETCH doesn't support services yet */
444         {
445                 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age >= 0s", -1, /* always matches */
446                 0, SDB_CONNECTION_DATA, 358, SDB_CONNECTION_LOOKUP, SERVICE_H2_S1_ARRAY,
447         },
448         {
449                 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER age < 0s", -1, /* never matches */
450                 -1, UINT32_MAX, 0, 0, NULL,
451         },
452         /* SDB_CONNECTION_FETCH doesn't support services yet */
453         {
454                 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER age < 0s", -1, /* never matches */
455                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
456         },
457         /* SDB_CONNECTION_LOOKUP doesn't support filters yet */
458         {
459                 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'s1' FILTER name = 'h2'", -1, /* only matches host */
460                 -1, UINT32_MAX, 0, 0, NULL,
461         },
462         /* SDB_CONNECTION_FETCH doesn't support services yet */
463         {
464                 SDB_CONNECTION_QUERY, "LOOKUP services MATCHING name = 's1' FILTER name = 'h2'", -1, /* only matches host */
465                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
466         },
467         {
468                 SDB_CONNECTION_QUERY, "FETCH service 'h2'.'x1'", -1, /* does not exist */
469                 -1, UINT32_MAX, 0, 0, NULL,
470         },
471         /* SDB_CONNECTION_FETCH doesn't support services yet */
472         {
473                 SDB_CONNECTION_QUERY, "FETCH service 'x2'.'s1'", -1, /* does not exist */
474                 -1, UINT32_MAX, 0, 0, NULL,
475         },
476         /* SDB_CONNECTION_FETCH doesn't support services yet */
477         {
478                 SDB_CONNECTION_QUERY, "FETCH service 'h2'", -1, /* invalid args */
479                 -1, UINT32_MAX, 0, 0, NULL,
480         },
481         /* SDB_CONNECTION_FETCH doesn't support services yet */
482         /* metrics */
483         {
484                 SDB_CONNECTION_QUERY, "LIST metrics", -1,
485                 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
486         },
487         {
488                 SDB_CONNECTION_LIST, "\0\0\0\3", 4,
489                 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
490         },
491         {
492                 SDB_CONNECTION_QUERY, "LIST metrics FILTER age > 0s", -1,
493                 0, SDB_CONNECTION_DATA, 596, SDB_CONNECTION_LIST, METRIC_H12_M12_LISTING,
494         },
495         {
496                 SDB_CONNECTION_QUERY, "LIST metrics FILTER age < 0s", -1,
497                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LIST, "[]",
498         },
499         /* SDB_CONNECTION_LIST doesn't support filters yet */
500         {
501                 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1'", -1,
502                 0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
503         },
504         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
505         {
506                 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1'", -1,
507                 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
508         },
509         {
510                 SDB_CONNECTION_LOOKUP, "\0\0\0\3""name = 'm1'", 16,
511                 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
512         },
513         {
514                 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age >= 0s", -1, /* always matches */
515                 0, SDB_CONNECTION_DATA, 489, SDB_CONNECTION_FETCH, METRIC_H1_M1,
516         },
517         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
518         {
519                 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age >= 0s", -1, /* always matches */
520                 0, SDB_CONNECTION_DATA, 864, SDB_CONNECTION_LOOKUP, METRIC_H12_M1_ARRAY,
521         },
522         {
523                 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER age < 0s", -1, /* never matches */
524                 -1, UINT32_MAX, 0, 0, NULL,
525         },
526         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
527         {
528                 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER age < 0s", -1, /* never matches */
529                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
530         },
531         /* SDB_CONEECTION_LOOKUP doesn't support filters yet */
532         {
533                 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'m1' FILTER name = 'h1'", -1, /* only matches host */
534                 -1, UINT32_MAX, 0, 0, NULL,
535         },
536         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
537         {
538                 SDB_CONNECTION_QUERY, "LOOKUP metrics MATCHING name = 'm1' FILTER name = 'h1'", -1, /* only matches host */
539                 0, SDB_CONNECTION_DATA, 6, SDB_CONNECTION_LOOKUP, "[]",
540         },
541         {
542                 SDB_CONNECTION_QUERY, "FETCH metric 'h1'.'x1'", -1, /* does not exist */
543                 -1, UINT32_MAX, 0, 0, NULL,
544         },
545         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
546         {
547                 SDB_CONNECTION_QUERY, "FETCH metric 'x1'.'m1'", -1, /* does not exist */
548                 -1, UINT32_MAX, 0, 0, NULL,
549         },
550         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
551         {
552                 SDB_CONNECTION_QUERY, "FETCH metric 'x1'", -1, /* invalid args */
553                 -1, UINT32_MAX, 0, 0, NULL,
554         },
555         /* SDB_CONNECTION_FETCH doesn't support metrics yet */
556         /* timeseries */
557         {
558                 SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'m1'", -1,
559                 -1, UINT32_MAX, 0, 0, NULL, /* no data-store available */
560         },
561         {
562                 SDB_CONNECTION_QUERY, "TIMESERIES 'h1'.'x1'", -1,
563                 -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
564         },
565         {
566                 SDB_CONNECTION_QUERY, "TIMESERIES 'x1'.'m1'", -1,
567                 -1, UINT32_MAX, 0, 0, NULL, /* does not exist */
568         },
569         /* store commands */
570         {
571                 SDB_CONNECTION_QUERY, "STORE host 'hA' LAST UPDATE 01:00", -1,
572                 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
573         },
574         {
575                 SDB_CONNECTION_STORE, "\0\0\0\1""\0\0\0\0\xd6\x93\xa4\0""hA", 15,
576                 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
577         },
578         {
579                 SDB_CONNECTION_QUERY, "STORE host 'hA'", -1,
580                 0, SDB_CONNECTION_OK, 27, 0, "Successfully stored host hA",
581         },
582         {
583                 SDB_CONNECTION_QUERY, "STORE host attribute 'h1'.'aA' 'vA'", -1,
584                 0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
585         },
586         {
587                 SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""h1\0aA\0"VALUE, 18+VALUE_LEN,
588                 0, SDB_CONNECTION_OK, 40, 0, "Successfully stored host attribute h1.aA",
589         },
590         {
591                 SDB_CONNECTION_QUERY, "STORE host attribute 'x1'.'aA' 'vA'", -1,
592                 -1, UINT32_MAX, 0, 0, NULL,
593         },
594         {
595                 SDB_CONNECTION_STORE, "\0\0\0\x11""\0\0\0\0\xd6\x93\xa4\0""x1\0aA\0"VALUE, 18+VALUE_LEN,
596                 -1, UINT32_MAX, 0, 0, NULL,
597         },
598         {
599                 SDB_CONNECTION_QUERY, "STORE service 'h1'.'sA'", -1,
600                 0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
601         },
602         {
603                 SDB_CONNECTION_STORE, "\0\0\0\2""\0\0\0\0\xd6\x93\xa4\0""h1\0sA", 18,
604                 0, SDB_CONNECTION_OK, 33, 0, "Successfully stored service h1.sA",
605         },
606         {
607                 SDB_CONNECTION_QUERY, "STORE service 'x1'.'sA'", -1,
608                 -1, UINT32_MAX, 0, 0, NULL,
609         },
610         {
611                 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""x1\0sA", 18,
612                 -1, UINT32_MAX, 0, 0, NULL,
613         },
614         {
615                 SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'s1'.'aA' 'vA'", -1,
616                 0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
617         },
618         {
619                 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0s1\0aA\0"VALUE,27+VALUE_LEN,
620                 0, SDB_CONNECTION_OK, 46, 0, "Successfully stored service attribute h2.s1.aA",
621         },
622         {
623                 SDB_CONNECTION_QUERY, "STORE service attribute 'h2'.'x1'.'aA' 'vA'", -1,
624                 -1, UINT32_MAX, 0, 0, NULL,
625         },
626         {
627                 SDB_CONNECTION_STORE, "\0\0\0\x12""\0\0\0\0\xd6\x93\xa4\0""h2\0x1\0aA\0"VALUE,27+VALUE_LEN,
628                 -1, UINT32_MAX, 0, 0, NULL,
629         },
630         {
631                 SDB_CONNECTION_QUERY, "STORE metric 'h1'.'mA'", -1,
632                 0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
633         },
634         {
635                 SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""h1\0mA", 18,
636                 0, SDB_CONNECTION_OK, 32, 0, "Successfully stored metric h1.mA",
637         },
638         {
639                 SDB_CONNECTION_QUERY, "STORE metric 'x1'.'mA'", -1,
640                 -1, UINT32_MAX, 0, 0, NULL,
641         },
642         {
643                 SDB_CONNECTION_STORE, "\0\0\0\3""\0\0\0\0\xd6\x93\xa4\0""x1\0mA", 18,
644                 -1, UINT32_MAX, 0, 0, NULL,
645         },
646         {
647                 SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'m1'.'aA' 'vA'", -1,
648                 0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
649         },
650         {
651                 SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0m1\0aA\0"VALUE, 27+VALUE_LEN,
652                 0, SDB_CONNECTION_OK, 45, 0, "Successfully stored metric attribute h1.m1.aA",
653         },
654         {
655                 SDB_CONNECTION_QUERY, "STORE metric attribute 'h1'.'x1'.'aA' 'vA'", -1,
656                 -1, UINT32_MAX, 0, 0, NULL,
657         },
658         {
659                 SDB_CONNECTION_STORE, "\0\0\0\x13""\0\0\0\0\xd6\x93\xa4\0""h1\0x1\0aA\0"VALUE, 27+VALUE_LEN,
660                 -1, UINT32_MAX, 0, 0, NULL,
661         },
662 };
664 START_TEST(test_query)
666         sdb_conn_t *conn = mock_conn_create();
668         uint32_t code = UINT32_MAX, msg_len = UINT32_MAX;
669         const char *data;
670         ssize_t tmp;
671         size_t len;
672         int check = -1;
674         conn->cmd = query_data[_i].cmd;
675         if (query_data[_i].query_len < 0)
676                 conn->cmd_len = (uint32_t)strlen(query_data[_i].query);
677         else
678                 conn->cmd_len = (uint32_t)query_data[_i].query_len;
679         sdb_strbuf_memcpy(conn->buf, query_data[_i].query, conn->cmd_len);
681         switch (conn->cmd) {
682         case SDB_CONNECTION_QUERY:
683                 check = sdb_conn_query(conn);
684                 break;
685         case SDB_CONNECTION_FETCH:
686                 check = sdb_conn_fetch(conn);
687                 break;
688         case SDB_CONNECTION_LIST:
689                 check = sdb_conn_list(conn);
690                 break;
691         case SDB_CONNECTION_LOOKUP:
692                 check = sdb_conn_lookup(conn);
693                 break;
694         /* SDB_CONNECTION_TIMESERIES not supported yet */
695         case SDB_CONNECTION_STORE:
696                 check = sdb_conn_store(conn);
697                 break;
698         default:
699                 fail("Invalid command %#x", conn->cmd);
700         }
702         fail_unless(check == query_data[_i].expected,
703                         "sdb_conn_query(%s) = %d; expected: %d (err: %s)",
704                         query_data[_i].query, check, query_data[_i].expected,
705                         sdb_strbuf_string(conn->errbuf));
707         data = sdb_strbuf_string(MOCK_CONN(conn)->write_buf);
708         len = sdb_strbuf_len(MOCK_CONN(conn)->write_buf);
710         if (query_data[_i].code == UINT32_MAX) {
711                 fail_unless(len == 0,
712                                 "sdb_conn_query(%s) returned data on error: '%s'",
713                         query_data[_i].query, data);
714                 mock_conn_destroy(conn);
715                 return;
716         }
718         tmp = sdb_proto_unmarshal_header(data, len, &code, &msg_len);
719         ck_assert_msg(tmp == (ssize_t)(2 * sizeof(uint32_t)));
720         data += tmp;
721         len -= tmp;
723         fail_unless((code == query_data[_i].code)
724                                 && ((size_t)msg_len == query_data[_i].len),
725                         "sdb_conn_query(%s) returned %u, %u; expected: %u, %zu",
726                         query_data[_i].query, code, msg_len,
727                         query_data[_i].code, query_data[_i].len);
729         if (code == SDB_CONNECTION_DATA) {
730                 tmp = sdb_proto_unmarshal_int32(data, len, &code);
731                 fail_unless(code == query_data[_i].type,
732                                 "sdb_conn_query(%s) returned %s object; expected: %s",
733                                 query_data[_i].query, SDB_CONN_MSGTYPE_TO_STRING((int)code),
734                                 SDB_CONN_MSGTYPE_TO_STRING((int)query_data[_i].type));
735                 data += tmp;
736                 len -= tmp;
737         }
739         fail_if_strneq(data, query_data[_i].data, (size_t)msg_len,
740                         "sdb_conn_query(%s) returned unexpected data",
741                         query_data[_i].query, data, query_data[_i].data);
743         mock_conn_destroy(conn);
745 END_TEST
747 TEST_MAIN("frontend::query")
749         TCase *tc = tcase_create("core");
750         tcase_add_checked_fixture(tc, populate, turndown);
751         TC_ADD_LOOP_TEST(tc, query);
752         ADD_TCASE(tc);
754 TEST_MAIN_END
756 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */