curl_json plugin: Implement a unit test.
authorFlorian Forster <octo@collectd.org>
Mon, 15 May 2017 12:40:56 +0000 (14:40 +0200)
committerFlorian Forster <octo@collectd.org>
Tue, 16 May 2017 07:07:09 +0000 (09:07 +0200)
Issue: #2266

Makefile.am
src/curl_json.c
src/curl_json_test.c [new file with mode: 0644]

index 1f18d23..d1d5071 100644 (file)
@@ -691,6 +691,15 @@ curl_json_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
 curl_json_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
 curl_json_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
 curl_json_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBYAJL_LIBS)
+
+test_plugin_curl_json_SOURCES = src/curl_json_test.c \
+                               src/utils_curl_stats.c \
+                               src/daemon/configfile.c \
+                               src/daemon/types_list.c
+test_plugin_curl_json_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+test_plugin_curl_json_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+test_plugin_curl_json_LDADD = libavltree.la liboconfig.la libplugin_mock.la $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBYAJL_LIBS)
+check_PROGRAMS += test_plugin_curl_json
 endif
 
 if BUILD_PLUGIN_CURL_XML
index cb0505b..a590e7b 100644 (file)
@@ -106,7 +106,11 @@ typedef unsigned int yajl_len_t;
 #endif
 
 static int cj_read(user_data_t *ud);
-static void cj_submit(cj_t *db, cj_key_t *key, value_t *value);
+static void cj_submit_impl(cj_t *db, cj_key_t *key, value_t *value);
+
+/* cj_submit is a function pointer to cj_submit_impl, allowing the unit-test to
+ * overwrite which function is called. */
+static void (*cj_submit)(cj_t *, cj_key_t *, value_t *) = cj_submit_impl;
 
 static size_t cj_curl_callback(void *buf, /* {{{ */
                                size_t size, size_t nmemb, void *user_data) {
@@ -773,7 +777,7 @@ static const char *cj_host(cj_t *db) /* {{{ */
   return db->host;
 } /* }}} cj_host */
 
-static void cj_submit(cj_t *db, cj_key_t *key, value_t *value) /* {{{ */
+static void cj_submit_impl(cj_t *db, cj_key_t *key, value_t *value) /* {{{ */
 {
   value_list_t vl = VALUE_LIST_INIT;
 
@@ -797,7 +801,7 @@ static void cj_submit(cj_t *db, cj_key_t *key, value_t *value) /* {{{ */
     vl.interval = db->interval;
 
   plugin_dispatch_values(&vl);
-} /* }}} int cj_submit */
+} /* }}} int cj_submit_impl */
 
 static int cj_sock_perform(cj_t *db) /* {{{ */
 {
diff --git a/src/curl_json_test.c b/src/curl_json_test.c
new file mode 100644 (file)
index 0000000..255d14b
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * collectd - src/curl_json.c
+ * Copyright (C) 2017  Florian octo Forster
+ *
+ * Licensed under the same terms and conditions as src/curl_json.c.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "curl_json.c"
+
+#include "testing.h"
+
+static void test_submit(cj_t *db, cj_key_t *key, value_t *value) {
+  /* hack: we repurpose db->curl to store received values. */
+  c_avl_tree_t *values = (void *)db->curl;
+
+  value_t *value_copy = calloc(1, sizeof(*value_copy));
+  memmove(value_copy, value, sizeof(*value_copy));
+
+  assert(c_avl_insert(values, key->path, value_copy) == 0);
+}
+
+static derive_t test_metric(cj_t *db, char const *path) {
+  c_avl_tree_t *values = (void *)db->curl;
+
+  value_t *ret = NULL;
+  if (c_avl_get(values, path, (void *)&ret) == 0) {
+    return ret->derive;
+  }
+
+  return -1;
+}
+
+static cj_t *test_setup(char *json, char *key_path) {
+  cj_t *db = calloc(1, sizeof(*db));
+  db->yajl = yajl_alloc(&ycallbacks,
+#if HAVE_YAJL_V2
+                        /* alloc funcs = */ NULL,
+#else
+                        /* alloc funcs = */ NULL, NULL,
+#endif
+                        /* context = */ (void *)db);
+
+  /* hack; see above. */
+  db->curl = (void *)cj_avl_create();
+
+  cj_key_t *key = calloc(1, sizeof(*key));
+  key->magic = CJ_KEY_MAGIC;
+  key->path = strdup(key_path);
+  key->type = strdup("MAGIC");
+
+  assert(cj_append_key(db, key) == 0);
+
+  db->state[0].tree = db->tree;
+
+  cj_curl_callback(json, strlen(json), 1, db);
+#if HAVE_YAJL_V2
+  yajl_complete_parse(db->yajl);
+#else
+  yajl_parse_complete(db->yajl);
+#endif
+
+  return db;
+}
+
+static void test_teardown(cj_t *db) {
+  c_avl_tree_t *values = (void *)db->curl;
+  db->curl = NULL;
+
+  void *key;
+  void *value;
+  while (c_avl_pick(values, &key, &value) == 0) {
+    /* key will be freed by cj_free. */
+    free(value);
+  }
+  c_avl_destroy(values);
+
+  yajl_free(db->yajl);
+  db->yajl = NULL;
+
+  cj_free(db);
+}
+
+DEF_TEST(parse) {
+  struct {
+    char *json;
+    char *key_path;
+    derive_t want;
+  } cases[] = {
+      {"{\"foo\":42,\"bar\":23}", "foo", 42},
+      {"{\"foo\":42,\"bar\":23}", "bar", 23},
+      {"{\"a\":{\"b\":{\"c\":123}}", "a/b/c", 123},
+      {"{\"x\":{\"y\":{\"z\":789}}", "x/*/z", 789},
+      // {"[10,11,12,13]", "0", 10},
+      // {"{\"a\":[[10,11,12,13,14]]}", "a/0/0", 10},
+      // {"{\"a\":[[10,11,12,13,14]]}", "a/0/1", 11},
+      // {"{\"a\":[[10,11,12,13,14]]}", "a/0/2", 12},
+      // {"{\"a\":[[10,11,12,13,14]]}", "a/0/3", 13},
+      // {"{\"a\":[[10,11,12,13,14]]}", "a/0/4", 14},
+  };
+
+  for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
+    cj_t *db = test_setup(cases[i].json, cases[i].key_path);
+
+    EXPECT_EQ_INT(cases[i].want, test_metric(db, cases[i].key_path));
+
+    test_teardown(db);
+  }
+
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  cj_submit = test_submit;
+
+  RUN_TEST(parse);
+
+  END_TEST;
+}