Code

parser: Add support for metric timeseries fields.
[sysdb.git] / t / unit / parser / parser_test.c
index 68e152740368d029ba9dd3ad96acb5be9cd7c81d..3d2e40cbc4df0b4e6c59e0415c421d3d996ae716 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "parser/parser.h"
 #include "core/object.h"
+#include "core/store.h"
 #include "testutils.h"
 
 #include <check.h>
@@ -357,7 +358,21 @@ struct {
        { "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 },
@@ -369,6 +384,26 @@ struct {
          "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 "
@@ -409,14 +444,25 @@ struct {
         * syntactically correct but semantically invalid commands
         */
 
-#if 0
        /* 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 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 "
@@ -426,11 +472,6 @@ struct {
          "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 "
@@ -449,6 +490,7 @@ struct {
          "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 },
@@ -512,8 +554,31 @@ struct {
          "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 "
+         "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 },
@@ -595,7 +660,6 @@ struct {
          "2015-02-01",          -1, -1, 0, 0 },
        { "STORE metric attribute "
          "'metric'.'key' 123",  -1, -1, 0, 0 },
-#endif
 };
 
 START_TEST(test_parse)
@@ -603,6 +667,7 @@ START_TEST(test_parse)
        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,
@@ -664,7 +729,14 @@ START_TEST(test_parse)
                                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(q));
        sdb_llist_destroy(check);
        sdb_strbuf_destroy(errbuf);
 }
@@ -765,12 +837,13 @@ struct {
        { "ALL attribute.name !~ 'pattern'",   -1,  SDB_AST_ALL },
        { "ALL attribute.name &^ 'pattern'",   -1,  -1 },
        { "ANY attribute !~ 'pattern'",        -1,  -1 },
+
        /* composite expressions */
        { "name =~ 'pattern' AND "
-         "ANY service.name =~ 'pattern'",     -1,  SDB_AST_AND },
+         "ANY service.name =~ 'pattern'",  -1,  SDB_AST_AND },
        { "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 },
@@ -792,9 +865,13 @@ struct {
          "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 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 },
@@ -838,6 +915,13 @@ struct {
        { "'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 "
@@ -968,6 +1052,20 @@ struct {
        { "(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 */
        { "LIST",                 -1, -1, -1 },
        { "foo &^ bar",           -1, -1, -1 },