Code

store_lookup: Added "tostring" methods for matcher objects.
authorSebastian Harl <sh@tokkee.org>
Wed, 9 Apr 2014 15:34:56 +0000 (17:34 +0200)
committerSebastian Harl <sh@tokkee.org>
Wed, 9 Apr 2014 15:34:56 +0000 (17:34 +0200)
This is meant for logging and debugging. For now, it's used in tests to check
parsed and compiled matchers.

src/core/store_lookup.c
src/include/core/store.h
t/Makefile.am
t/core/store_lookup_test.c
t/libsysdb_test.h
t/libsysdb_testutils.c [new file with mode: 0644]
t/libsysdb_testutils.h [new file with mode: 0644]

index e5735d3728e8157ebc90d3157c0278ea6b42acdb..bb32157402d8c047a20326aab81e069a4073e5f1 100644 (file)
@@ -103,6 +103,106 @@ match_name(name_matcher_t *m, const char *name)
        return 1;
 } /* match_name */
 
+static char *
+name_tostring(name_matcher_t *m, char *buf, size_t buflen)
+{
+       snprintf(buf, buflen, "{ %s%s%s, %p }",
+                       m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "",
+                       m->name_re);
+       return buf;
+} /* name_tostring */
+
+static char *
+logical_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       char left[buflen + 1], right[buflen + 1];
+
+       if (! m) {
+               /* this should not happen */
+               snprintf(buf, buflen, "()");
+               return buf;
+       }
+
+       assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND));
+       snprintf(buf, buflen, "(%s, %s, %s)",
+                       m->type == MATCHER_OR ? "OR" : "AND",
+                       sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)),
+                       sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right)));
+       return buf;
+} /* logical_tostring */
+
+static char *
+unary_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       char op[buflen + 1];
+
+       if (! m) {
+               /* this should not happen */
+               snprintf(buf, buflen, "()");
+               return buf;
+       }
+
+       assert(m->type == MATCHER_NOT);
+       snprintf(buf, buflen, "(NOT, %s)",
+                       sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op)));
+       return buf;
+} /* unary_tostring */
+
+static char *
+attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       char name[buflen + 1], value[buflen + 1];
+
+       if (! m) {
+               snprintf(buf, buflen, "ATTR{}");
+               return buf;
+       }
+
+       assert(m->type == MATCHER_ATTR);
+       snprintf(buf, buflen, "ATTR{ NAME%s, VALUE%s }",
+                       name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+                       name_tostring(&ATTR_M(m)->value, value, sizeof(value)));
+       return buf;
+} /* attr_tostring */
+
+static char *
+service_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       char name[buflen + 1], attr[buflen + 1];
+
+       if (! m) {
+               snprintf(buf, buflen, "SERVICE{}");
+               return buf;
+       }
+
+       assert(m->type == MATCHER_SERVICE);
+       snprintf(buf, buflen, "SERVICE{ NAME%s, %s }",
+                       name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+                       attr_tostring(SDB_STORE_MATCHER(SERVICE_M(m)->attr),
+                               attr, sizeof(attr)));
+       return buf;
+} /* service_tostring */
+
+static char *
+host_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       char name[buflen + 1], service[buflen + 1], attr[buflen + 1];
+
+       if (! m) {
+               snprintf(buf, buflen, "HOST{}");
+               return buf;
+       }
+
+       assert(m->type == MATCHER_HOST);
+       snprintf(buf, buflen, "HOST{ NAME%s, %s, %s }",
+                       name_tostring(&OBJ_M(m)->name, name, sizeof(name)),
+                       service_tostring(SDB_STORE_MATCHER(HOST_M(m)->service),
+                               service, sizeof(service)),
+                       attr_tostring(SDB_STORE_MATCHER(HOST_M(m)->attr),
+                               attr, sizeof(attr)));
+       return buf;
+} /* host_tostring */
+
 /* match attribute specific values;
  * always call this function through match_obj() */
 static int
@@ -218,6 +318,17 @@ static matcher_cb matchers[] = {
        match_obj,
 };
 
+typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t);
+
+static matcher_tostring_cb matchers_tostring[] = {
+       logical_tostring,
+       logical_tostring,
+       unary_tostring,
+       attr_tostring,
+       service_tostring,
+       host_tostring,
+};
+
 static int
 match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj)
 {
@@ -613,6 +724,18 @@ sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj)
        return matchers[m->type](m, obj);
 } /* sdb_store_matcher_matches */
 
+char *
+sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen)
+{
+       if (! m)
+               return NULL;
+
+       if ((m->type < 0)
+                       || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring))))
+               return NULL;
+       return matchers_tostring[m->type](m, buf, buflen);
+} /* sdb_store_matcher_tostring */
+
 int
 sdb_store_lookup(sdb_store_matcher_t *m, sdb_store_lookup_cb cb,
                void *user_data)
index cde6ad0b8c2763dd15b4759b27f005b87441db5a..6106b3fdbe2490629a6b1e42d02ee85184d134dc 100644 (file)
@@ -213,6 +213,14 @@ sdb_store_inv_matcher(sdb_store_matcher_t *m);
 int
 sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj);
 
+/*
+ * sdb_store_matcher_tostring:
+ * Format a matcher object as string. This is meant for logging or debugging
+ * purposes.
+ */
+char *
+sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen);
+
 /*
  * sdb_store_lookup_cb:
  * Lookup callback. It is called for each matching object when looking up data
index c63a2bb21d0c8f9a8e1ee25836723266f70fbebe..cc2607f75e2b09d9129cc9ff77cfe08630649932 100644 (file)
@@ -10,6 +10,7 @@ check_PROGRAMS = libsysdb_test libsysdb_net_test
 
 libsysdb_test_SOURCES = \
                libsysdb_test.c libsysdb_test.h \
+               libsysdb_testutils.c libsysdb_testutils.h \
                core/data_test.c \
                core/object_test.c \
                core/store_test.c \
@@ -25,7 +26,8 @@ libsysdb_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@
 libsysdb_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@
 
 libsysdb_net_test_SOURCES = \
-               libsysdb_net_test.c libsysdb_test.h
+               libsysdb_net_test.c libsysdb_test.h \
+               libsysdb_testutils.c libsysdb_testutils.h
 if BUILD_WITH_FOPENCOOKIE
 libsysdb_net_test_SOURCES += utils/unixsock_test.c
 endif
index 8aa730b1bdcf2d3ed29608c3a1913aab72cee2d7..6365b6b259a101feed4d0f9fded3491e5d28c383 100644 (file)
@@ -420,22 +420,52 @@ lookup_cb(sdb_store_base_t *obj, void *user_data)
 
 START_TEST(test_lookup)
 {
+#define PTR_RE "0x[0-9a-f]+"
        struct {
                const char *query;
                int expected;
+               const char *tostring_re;
        } golden_data[] = {
-               { "host.name = 'a'",       1 },
-               { "host.name =~ 'a|b'",    2 },
-               { "host.name =~ 'host'",   0 },
-               { "host.name =~ '.'",      3 },
-               { "service.name = 's1'",   2 },
-               { "service.name =~ 's'",   2 },
-               { "service.name !~ 's'",   1 },
-               { "attribute.name = 'k1'", 1 },
-               { "attribute.name = 'x'",  0 },
-               { "attribute.k1 = 'v1'",   1 },
-               { "attribute.k1 != 'v1'",  2 },
-               { "attribute.k1 != 'v2'",  3 },
+               { "host.name = 'a'",       1,
+                       "HOST\\{ NAME\\{ 'a', \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+               { "host.name =~ 'a|b'",    2,
+                       "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+               { "host.name =~ 'host'",   0,
+                       "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+               { "host.name =~ '.'",      3,
+                       "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" },
+               { "service.name = 's1'",   2,
+                       "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+                                       "NAME\\{ 's1', \\(nil\\) }, ATTR\\{\\} "
+                               "\\}, ATTR\\{\\} \\}" },
+               { "service.name =~ 's'",   2,
+                       "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+                                       "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} "
+                               "\\}, ATTR\\{\\} \\}" },
+               { "service.name !~ 's'",   1,
+                       "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ "
+                                       "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} "
+                               "\\}, ATTR\\{\\} \\})" },
+               { "attribute.name = 'k1'", 1,
+                       "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+                                       "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} "
+                               "\\} \\}" },
+               { "attribute.name = 'x'",  0,
+                       "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+                                       "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} "
+                               "\\} \\}" },
+               { "attribute.k1 = 'v1'",   1,
+                       "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+                                       "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} "
+                               "\\} \\}" },
+               { "attribute.k1 != 'v1'",  2,
+                       "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+                                       "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} "
+                               "\\} \\})" },
+               { "attribute.k1 != 'v2'",  3,
+                       "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ "
+                                       "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v2', \\(nil\\) \\} "
+                               "\\} \\})" },
        };
 
        int check, n;
@@ -449,10 +479,19 @@ START_TEST(test_lookup)
                        "sdb_store_lookup called callback %d times; expected: 3", (int)n);
 
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
-               sdb_store_matcher_t *m = sdb_fe_parse_matcher(golden_data[i].query, -1);
+               sdb_store_matcher_t *m;
+               char buf[4096];
+
+               m = sdb_fe_parse_matcher(golden_data[i].query, -1);
                fail_unless(m != NULL,
                                "sdb_fe_parse_matcher(%s, -1) = NULL; expected: <matcher>",
                                golden_data[i].query);
+               fail_unless(sdb_regmatches(golden_data[i].tostring_re,
+                                       sdb_store_matcher_tostring(m, buf, sizeof(buf))) == 0,
+                               "sdb_fe_parse_matcher(%s, -1) = %s; expected: %s",
+                               golden_data[i].query,
+                               sdb_store_matcher_tostring(m, buf, sizeof(buf)),
+                               golden_data[i].tostring_re);
 
                n = 0;
                sdb_store_lookup(m, lookup_cb, &n);
index 3357260f6a52559ac0d70906aff2e5a927cd08cf..5f0e1b486eda09647e1fdd9cbd72d38c8f7af0b2 100644 (file)
@@ -31,6 +31,8 @@
 #include "sysdb.h"
 #include "core/object.h"
 
+#include "libsysdb_testutils.h"
+
 #include <check.h>
 #include <string.h>
 
diff --git a/t/libsysdb_testutils.c b/t/libsysdb_testutils.c
new file mode 100644 (file)
index 0000000..964afdb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SysDB - t/libsysdb_testutils.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "libsysdb_testutils.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <regex.h>
+
+int
+sdb_regmatches(const char *regex, const char *string)
+{
+       regex_t reg;
+       int status;
+
+       status = regcomp(&reg, regex, REG_EXTENDED | REG_NOSUB);
+       if (status)
+               return status;
+
+       status = regexec(&reg, string, /* matches = */ 0, NULL, /* flags = */ 0);
+       regfree(&reg);
+       return status;
+} /* sdb_regmatches */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/t/libsysdb_testutils.h b/t/libsysdb_testutils.h
new file mode 100644 (file)
index 0000000..3f828a9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SysDB - t/libsysdb_testutils.h
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Utility functions for test suites.
+ */
+
+#ifndef T_LIBSYSDB_UTILS_H
+#define T_LIBSYSDB_UTILS_H 1
+
+/*
+ * sdb_regmatches:
+ * Check if a regex matches a string.
+ *
+ * Returns:
+ *  - 0 if the regex matches
+ *  - a non-zero error value else (see regcomp(3) for details)
+ */
+int
+sdb_regmatches(const char *regex, const char *string);
+
+#endif /* T_LIBSYSDB_UTILS_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+