index c3aa09acb866d6083534989f6b94b98168e4b608..3d2e40cbc4df0b4e6c59e0415c421d3d996ae716 100644 (file)
#include "parser/parser.h"
#include "core/object.h"
#include "parser/parser.h"
#include "core/object.h"
+#include "core/store.h"
#include "testutils.h"
#include <check.h>
#include "testutils.h"
#include <check.h>
{ "TIMESERIES 'host'.'metric' "
"START 2014-02-02 "
"14:02", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
{ "TIMESERIES 'host'.'metric' "
"START 2014-02-02 "
"14:02", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
+ /* the end time has to be greater than the start time;
+ * we'll be safe for about 200 years ;-) */
{ "TIMESERIES 'host'.'metric' "
{ "TIMESERIES 'host'.'metric' "
- "END 2014-02-02", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
+ "END 2214-02-02", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
{ "TIMESERIES "
"'host'.'metric'", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
{ "TIMESERIES "
"'host'.'metric'", -1, 1, SDB_AST_TYPE_TIMESERIES, 0 },
{ "LOOKUP hosts MATCHING "
"name < ''", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
{ "LOOKUP hosts MATCHING "
"name < ''", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
- /* NULL */
+ /* typed expressions */
+ { "LOOKUP services MATCHING "
+ "host.attribute['a'] = 'a'",
+ -1, 1, SDB_AST_TYPE_LOOKUP, SDB_SERVICE },
+ /* TODO: this should work but the analyzer currently sees ATTRIBUTE
+ * (instead of SERVICE-ATTRIBUTE) as the child type
+ { "LOOKUP services MATCHING "
+ "ANY attribute.service.name = 's'",
+ -1, 1, SDB_AST_TYPE_LOOKUP, SDB_SERVICE },
+ */
+ { "LOOKUP hosts MATCHING "
+ "ANY service.service.name = 's'",
+ -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+
+ /* NULL / TRUE / FALSE */
{ "LOOKUP hosts MATCHING "
"attribute['foo'] "
"IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
{ "LOOKUP hosts MATCHING "
"attribute['foo'] "
"IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
"IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
{ "LOOKUP hosts MATCHING "
"ANY service.name IS NULL", -1, -1, 0, 0 },
"IS NULL", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
{ "LOOKUP hosts MATCHING "
"ANY service.name IS NULL", -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "attribute['foo'] "
+ "IS TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP hosts MATCHING "
+ "attribute['foo'] "
+ "IS NOT TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP hosts MATCHING "
+ "NOT attribute['foo'] "
+ "IS TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP hosts MATCHING "
+ "attribute['foo'] "
+ "IS FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP hosts MATCHING "
+ "attribute['foo'] "
+ "IS NOT FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP hosts MATCHING "
+ "NOT attribute['foo'] "
+ "IS FALSE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_HOST },
+ { "LOOKUP metrics MATCHING "
+ "timeseries IS TRUE", -1, 1, SDB_AST_TYPE_LOOKUP, SDB_METRIC },
/* invalid numeric constants */
{ "LOOKUP hosts MATCHING "
/* invalid numeric constants */
{ "LOOKUP hosts MATCHING "
* syntactically correct but semantically invalid commands
*/
* syntactically correct but semantically invalid commands
*/
-#if 0
/* invalid fields */
/* invalid fields */
+ { "LIST hosts FILTER "
+ "field = 'a'", -1, -1, 0, 0 },
+ { "LIST services FILTER "
+ "field = 'a'", -1, -1, 0, 0 },
+ { "LIST metrics FILTER "
+ "field = 'a'", -1, -1, 0, 0 },
{ "LIST hosts FILTER "
"value = 'a'", -1, -1, 0, 0 },
{ "LIST services FILTER "
"value = 'a'", -1, -1, 0, 0 },
{ "LIST metrics FILTER "
"value = 'a'", -1, -1, 0, 0 },
{ "LIST hosts FILTER "
"value = 'a'", -1, -1, 0, 0 },
{ "LIST services FILTER "
"value = 'a'", -1, -1, 0, 0 },
{ "LIST metrics FILTER "
"value = 'a'", -1, -1, 0, 0 },
+ { "LIST metrics FILTER "
+ "name.1 = 'a'", -1, -1, 0, 0 },
+ { "LIST hosts FILTER "
+ "timeseries IS TRUE", -1, -1, 0, 0 },
+ { "LIST services FILTER "
+ "timeseries IS TRUE", -1, -1, 0, 0 },
/* type mismatches */
{ "LOOKUP hosts MATCHING "
/* type mismatches */
{ "LOOKUP hosts MATCHING "
"1 IN backend ", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"1 NOT IN backend ", -1, -1, 0, 0 },
"1 IN backend ", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"1 NOT IN backend ", -1, -1, 0, 0 },
- { "LOOKUP hosts MATCHING "
- "ANY backend !~ backend",
- -1, -1, 0, 0 },
- { "LOOKUP hosts MATCHING "
- "ANY backend = 1", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"age > 0", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
{ "LOOKUP hosts MATCHING "
"age > 0", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"age + 1 > 0s", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"age - 1 > 0s", -1, -1, 0, 0 },
"age + 1 > 0s", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"age - 1 > 0s", -1, -1, 0, 0 },
+
/* datetime <mul/div> integer is allowed */
{ "LOOKUP hosts MATCHING "
"age || 1 > 0s", -1, -1, 0, 0 },
/* datetime <mul/div> integer is allowed */
{ "LOOKUP hosts MATCHING "
"age || 1 > 0s", -1, -1, 0, 0 },
"name + 1 IS NULL", -1, -1, 0, 0 },
{ "LOOKUP hosts FILTER "
"name + 1 IS NULL", -1, -1, 0, 0 },
"name + 1 IS NULL", -1, -1, 0, 0 },
{ "LOOKUP hosts FILTER "
"name + 1 IS NULL", -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "name + 1 IS TRUE", -1, -1, 0, 0 },
+ { "LOOKUP hosts FILTER "
+ "name + 1 IS TRUE", -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "name + 1 IS FALSE", -1, -1, 0, 0 },
+ { "LOOKUP hosts FILTER "
+ "name + 1 IS FALSE", -1, -1, 0, 0 },
+
+ /* invalid iterators */
+ { "LOOKUP hosts MATCHING "
+ "ANY backend !~ backend",
+ -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "ANY backend = 1", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"ANY 'patt' =~ 'p'", -1, -1, 0, 0 },
{ "LOOKUP hosts MATCHING "
"ANY 'patt' =~ 'p'", -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "ALL 1 || '2' < '3'", -1, -1, 0, 0 },
+ { "LOOKUP hosts MATCHING "
+ "ALL name =~ 'a'", -1, -1, 0, 0 },
+ /* this could work in theory but is not supported atm */
+ { "LOOKUP hosts MATCHING "
+ "ANY backend || 'a' = 'b'",
+ -1, -1, 0, 0 },
/* invalid LIST commands */
{ "LIST", -1, -1, 0, 0 },
/* invalid LIST commands */
{ "LIST", -1, -1, 0, 0 },
"2015-02-01", -1, -1, 0, 0 },
{ "STORE metric attribute "
"'metric'.'key' 123", -1, -1, 0, 0 },
"2015-02-01", -1, -1, 0, 0 },
{ "STORE metric attribute "
"'metric'.'key' 123", -1, -1, 0, 0 },
-#endif
};
START_TEST(test_parse)
};
START_TEST(test_parse)
sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
sdb_llist_t *check;
sdb_ast_node_t *node;
sdb_strbuf_t *errbuf = sdb_strbuf_create(64);
sdb_llist_t *check;
sdb_ast_node_t *node;
+ sdb_store_query_t *q;
_Bool ok;
check = sdb_parser_parse(parse_data[_i].query,
_Bool ok;
check = sdb_parser_parse(parse_data[_i].query,
SDB_STORE_TYPE_TO_NAME(parse_data[_i].expected_extra));
}
SDB_STORE_TYPE_TO_NAME(parse_data[_i].expected_extra));
}
+ /* TODO: this should move into front-end specific tests */
+ q = sdb_store_query_prepare(node);
+ fail_unless(q != NULL,
+ "sdb_store_query_prepare(AST<%s>) = NULL; expected: <query>",
+ parse_data[_i].query);
+
sdb_object_deref(SDB_OBJ(node));
sdb_object_deref(SDB_OBJ(node));
+ sdb_object_deref(SDB_OBJ(q));
sdb_llist_destroy(check);
sdb_strbuf_destroy(errbuf);
}
sdb_llist_destroy(check);
sdb_strbuf_destroy(errbuf);
}
{ "ALL attribute.name !~ 'pattern'", -1, SDB_AST_ALL },
{ "ALL attribute.name &^ 'pattern'", -1, -1 },
{ "ANY attribute !~ 'pattern'", -1, -1 },
{ "ALL attribute.name !~ 'pattern'", -1, SDB_AST_ALL },
{ "ALL attribute.name &^ 'pattern'", -1, -1 },
{ "ANY attribute !~ 'pattern'", -1, -1 },
+
/* composite expressions */
{ "name =~ 'pattern' AND "
/* composite expressions */
{ "name =~ 'pattern' AND "
- "ANY service.name =~ 'pattern'", -1, SDB_AST_AND },
+ "ANY service.name =~ 'pattern'", -1, SDB_AST_AND },
{ "name =~ 'pattern' OR "
{ "name =~ 'pattern' OR "
- "ANY service.name =~ 'pattern'", -1, SDB_AST_OR },
- { "NOT name = 'host'", -1, SDB_AST_NOT },
+ "ANY service.name =~ 'pattern'", -1, SDB_AST_OR },
+ { "NOT name = 'host'", -1, SDB_AST_NOT },
/* numeric expressions */
{ "attribute['foo'] < 123", -1, SDB_AST_LT },
{ "attribute['foo'] <= 123", -1, SDB_AST_LE },
/* numeric expressions */
{ "attribute['foo'] < 123", -1, SDB_AST_LT },
{ "attribute['foo'] <= 123", -1, SDB_AST_LE },
"2014-08-16 17:23", -1, SDB_AST_EQ },
{ "attribute['foo'] = "
"2014-08-16 17:23:53", -1, SDB_AST_EQ },
"2014-08-16 17:23", -1, SDB_AST_EQ },
{ "attribute['foo'] = "
"2014-08-16 17:23:53", -1, SDB_AST_EQ },
- /* NULL */
+ /* NULL / TRUE / FALSE */
{ "attribute['foo'] IS NULL", -1, SDB_AST_ISNULL },
{ "attribute['foo'] IS NOT NULL", -1, SDB_AST_NOT },
{ "attribute['foo'] IS NULL", -1, SDB_AST_ISNULL },
{ "attribute['foo'] IS NOT NULL", -1, SDB_AST_NOT },
+ { "attribute['foo'] IS TRUE", -1, SDB_AST_ISTRUE },
+ { "attribute['foo'] IS NOT TRUE", -1, SDB_AST_NOT },
+ { "attribute['foo'] IS FALSE", -1, SDB_AST_ISFALSE },
+ { "attribute['foo'] IS NOT FALSE", -1, SDB_AST_NOT },
/* array expressions */
{ "backend < ['a']", -1, SDB_AST_LT },
{ "backend <= ['a']", -1, SDB_AST_LE },
/* array expressions */
{ "backend < ['a']", -1, SDB_AST_LT },
{ "backend <= ['a']", -1, SDB_AST_LE },
{ "'be' NOT IN backend", -1, SDB_AST_NOT },
{ "['a','b'] IN backend", -1, SDB_AST_IN },
{ "['a','b'] NOT IN backend", -1, SDB_AST_NOT },
{ "'be' NOT IN backend", -1, SDB_AST_NOT },
{ "['a','b'] IN backend", -1, SDB_AST_IN },
{ "['a','b'] NOT IN backend", -1, SDB_AST_NOT },
+ { "timeseries IS TRUE", -1, SDB_AST_ISTRUE },
+ { "timeseries IS FALSE", -1, SDB_AST_ISFALSE },
+ { "timeseries IS NOT TRUE", -1, SDB_AST_NOT },
+ { "timeseries IS NOT FALSE", -1, SDB_AST_NOT },
+ { "timeseries > 0", -1, -1 },
+ { "timeseries = TRUE", -1, -1 },
+ { "timeseries != FALSE", -1, -1 },
/* check operator precedence */
{ "name = 'name' OR "
/* check operator precedence */
{ "name = 'name' OR "
"expected: %d", parse_conditional_data[_i].expr,
SDB_AST_ITER(node)->kind, parse_conditional_data[_i].expected);
"expected: %d", parse_conditional_data[_i].expr,
SDB_AST_ITER(node)->kind, parse_conditional_data[_i].expected);
+ fail_unless(node->data_type == -1,
+ "sdb_parser_parse_conditional(%s) returned conditional of data-type %s; "
+ "expected: %s", parse_conditional_data[_i].expr,
+ SDB_TYPE_TO_STRING(node->data_type), SDB_TYPE_TO_STRING(-1));
+
sdb_object_deref(SDB_OBJ(node));
sdb_strbuf_destroy(errbuf);
}
sdb_object_deref(SDB_OBJ(node));
sdb_strbuf_destroy(errbuf);
}
const char *expr;
int len;
int expected;
const char *expr;
int len;
int expected;
+ int data_type;
} parse_arith_data[] = {
/* empty expressions */
} parse_arith_data[] = {
/* empty expressions */
- { NULL, -1, -1 },
- { "", -1, -1 },
+ { NULL, -1, -1, -1 },
+ { "", -1, -1, -1 },
/* constant expressions */
/* constant expressions */
- { "'localhost'", -1, SDB_AST_TYPE_CONST },
- { "123", -1, SDB_AST_TYPE_CONST },
- { "2014-08-16", -1, SDB_AST_TYPE_CONST },
- { "17:23", -1, SDB_AST_TYPE_CONST },
- { "17:23:53", -1, SDB_AST_TYPE_CONST },
- { "17:23:53.123", -1, SDB_AST_TYPE_CONST },
- { "17:23:53.123456789", -1, SDB_AST_TYPE_CONST },
- { "2014-08-16 17:23", -1, SDB_AST_TYPE_CONST },
- { "2014-08-16 17:23:53", -1, SDB_AST_TYPE_CONST },
- { "10s", -1, SDB_AST_TYPE_CONST },
- { "60m", -1, SDB_AST_TYPE_CONST },
- { "10Y 24D 1h", -1, SDB_AST_TYPE_CONST },
+ { "'localhost'", -1, SDB_AST_TYPE_CONST, SDB_TYPE_STRING },
+ { "123", -1, SDB_AST_TYPE_CONST, SDB_TYPE_INTEGER },
+ { "42.3", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DECIMAL },
+ { "2014-08-16", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "17:23", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "17:23:53", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "17:23:53.123", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "17:23:53.123456789", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "2014-08-16 17:23", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "2014-08-16 17:23:53", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "10s", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "60m", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
+ { "10Y 24D 1h", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME },
/* TODO: the analyzer and/or optimizer should turn these into constants */
/* TODO: the analyzer and/or optimizer should turn these into constants */
- { "123 + 456", -1, SDB_AST_ADD },
- { "'foo' || 'bar'", -1, SDB_AST_CONCAT },
- { "456 - 123", -1, SDB_AST_SUB },
- { "1.2 * 3.4", -1, SDB_AST_MUL },
- { "1.2 / 3.4", -1, SDB_AST_DIV },
- { "5 % 2", -1, SDB_AST_MOD },
+ { "123 + 456", -1, SDB_AST_ADD, SDB_TYPE_INTEGER },
+ { "'foo' || 'bar'", -1, SDB_AST_CONCAT, SDB_TYPE_STRING },
+ { "456 - 123", -1, SDB_AST_SUB, SDB_TYPE_INTEGER },
+ { "1.2 * 3.4", -1, SDB_AST_MUL, SDB_TYPE_DECIMAL },
+ { "1.2 / 3.4", -1, SDB_AST_DIV, SDB_TYPE_DECIMAL },
+ { "5 % 2", -1, SDB_AST_MOD, SDB_TYPE_INTEGER },
/* queryable fields */
/* queryable fields */
- { "last_update", -1, SDB_AST_TYPE_VALUE },
- { "AGE", -1, SDB_AST_TYPE_VALUE },
- { "interval", -1, SDB_AST_TYPE_VALUE },
- { "Last_Update", -1, SDB_AST_TYPE_VALUE },
- { "backend", -1, SDB_AST_TYPE_VALUE },
+ { "last_update", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME },
+ { "AGE", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME },
+ { "interval", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME },
+ { "Last_Update", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME },
+ { "backend", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_ARRAY | SDB_TYPE_STRING },
/* attributes */
/* attributes */
- { "attribute['foo']", -1, SDB_AST_TYPE_VALUE },
+ { "attribute['foo']", -1, SDB_AST_TYPE_VALUE, -1 },
/* arithmetic expressions */
/* arithmetic expressions */
- { "age + age", -1, SDB_AST_ADD },
- { "age - age", -1, SDB_AST_SUB },
- { "age * age", -1, SDB_AST_MUL },
- { "age / age", -1, SDB_AST_DIV },
- { "age \% age", -1, SDB_AST_MOD },
- { "age || age", -1, SDB_AST_CONCAT },
+ { "age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME },
+ { "age - age", -1, SDB_AST_SUB, SDB_TYPE_DATETIME },
+ { "age * age", -1, SDB_AST_MUL, SDB_TYPE_DATETIME },
+ { "age / age", -1, SDB_AST_DIV, SDB_TYPE_DATETIME },
+ { "age \% age", -1, SDB_AST_MOD, SDB_TYPE_DATETIME },
/* operator precedence */
/* operator precedence */
- { "age + age * age", -1, SDB_AST_ADD },
- { "age * age + age", -1, SDB_AST_ADD },
- { "age + age - age", -1, SDB_AST_SUB },
- { "age - age + age", -1, SDB_AST_ADD },
- { "(age + age) * age", -1, SDB_AST_MUL },
- { "age + (age * age)", -1, SDB_AST_ADD },
+ { "age + age * age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME },
+ { "age * age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME },
+ { "age + age - age", -1, SDB_AST_SUB, SDB_TYPE_DATETIME },
+ { "age - age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME },
+ { "(age + age) * age", -1, SDB_AST_MUL, SDB_TYPE_DATETIME },
+ { "age + (age * age)", -1, SDB_AST_ADD, SDB_TYPE_DATETIME },
+
+ /* boolean expressions */
+ { "timeseries + 1", -1, -1, -1 },
+ { "timeseries - 1", -1, -1, -1 },
+ { "timeseries * 1", -1, -1, -1 },
+ { "timeseries / 1", -1, -1, -1 },
+ { "timeseries \% 1", -1, -1, -1 },
+ { "timeseries CONCAT 1", -1, -1, -1 },
+ { "timeseries + timeseries", -1, -1, -1 },
+ { "timeseries - timeseries", -1, -1, -1 },
+ { "timeseries * timeseries", -1, -1, -1 },
+ { "timeseries / timeseries", -1, -1, -1 },
+ { "timeseries \% timeseries", -1, -1, -1 },
+ { "timeseries CONCAT timeseries", -1, -1, -1 },
/* syntax errors */
/* syntax errors */
- { "LIST", -1, -1 },
- { "foo &^ bar", -1, -1 },
- { "invalid", -1, -1 },
+ { "LIST", -1, -1, -1 },
+ { "foo &^ bar", -1, -1, -1 },
+ { "invalid", -1, -1, -1 },
};
START_TEST(test_parse_arith)
};
START_TEST(test_parse_arith)
"expected: %d", parse_arith_data[_i].expr, node->type,
parse_arith_data[_i].expected);
"expected: %d", parse_arith_data[_i].expr, node->type,
parse_arith_data[_i].expected);
+ fail_unless(node->data_type == parse_arith_data[_i].data_type,
+ "sdb_parser_parse_arith(%s) returned expression of data-type %s; "
+ "expected: %s", parse_arith_data[_i].expr,
+ SDB_TYPE_TO_STRING(node->data_type),
+ SDB_TYPE_TO_STRING(parse_arith_data[_i].data_type));
+
sdb_object_deref(SDB_OBJ(node));
sdb_strbuf_destroy(errbuf);
}
sdb_object_deref(SDB_OBJ(node));
sdb_strbuf_destroy(errbuf);
}