curl_json plugin: Refactor the way trees/keys are stored.
[collectd.git] / src / curl_json_test.c
1 /**
2  * collectd - src/curl_json.c
3  * Copyright (C) 2017  Florian octo Forster
4  *
5  * Licensed under the same terms and conditions as src/curl_json.c.
6  *
7  * Authors:
8  *   Florian octo Forster <octo at collectd.org>
9  **/
10
11 #include "curl_json.c"
12
13 #include "testing.h"
14
15 static void test_submit(cj_t *db, cj_key_t *key, value_t *value) {
16   /* hack: we repurpose db->curl to store received values. */
17   c_avl_tree_t *values = (void *)db->curl;
18
19   value_t *value_copy = calloc(1, sizeof(*value_copy));
20   memmove(value_copy, value, sizeof(*value_copy));
21
22   assert(c_avl_insert(values, key->path, value_copy) == 0);
23 }
24
25 static derive_t test_metric(cj_t *db, char const *path) {
26   c_avl_tree_t *values = (void *)db->curl;
27
28   value_t *ret = NULL;
29   if (c_avl_get(values, path, (void *)&ret) == 0) {
30     return ret->derive;
31   }
32
33   return -1;
34 }
35
36 static cj_t *test_setup(char *json, char *key_path) {
37   cj_t *db = calloc(1, sizeof(*db));
38   db->yajl = yajl_alloc(&ycallbacks,
39 #if HAVE_YAJL_V2
40                         /* alloc funcs = */ NULL,
41 #else
42                         /* alloc funcs = */ NULL, NULL,
43 #endif
44                         /* context = */ (void *)db);
45
46   /* hack; see above. */
47   db->curl = (void *)cj_avl_create();
48
49   cj_key_t *key = calloc(1, sizeof(*key));
50   key->path = strdup(key_path);
51   key->type = strdup("MAGIC");
52
53   assert(cj_append_key(db, key) == 0);
54
55   db->state[0].entry = &(cj_tree_entry_t){
56       .type = TREE, .tree = db->tree,
57   };
58
59   cj_curl_callback(json, strlen(json), 1, db);
60 #if HAVE_YAJL_V2
61   yajl_complete_parse(db->yajl);
62 #else
63   yajl_parse_complete(db->yajl);
64 #endif
65
66   db->state[0].entry = NULL;
67
68   return db;
69 }
70
71 static void test_teardown(cj_t *db) {
72   c_avl_tree_t *values = (void *)db->curl;
73   db->curl = NULL;
74
75   void *key;
76   void *value;
77   while (c_avl_pick(values, &key, &value) == 0) {
78     /* key will be freed by cj_free. */
79     free(value);
80   }
81   c_avl_destroy(values);
82
83   yajl_free(db->yajl);
84   db->yajl = NULL;
85
86   cj_free(db);
87 }
88
89 DEF_TEST(parse) {
90   struct {
91     char *json;
92     char *key_path;
93     derive_t want;
94   } cases[] = {
95       /* simple map */
96       {"{\"foo\":42,\"bar\":23}", "foo", 42},
97       {"{\"foo\":42,\"bar\":23}", "bar", 23},
98       /* nested map */
99       {"{\"a\":{\"b\":{\"c\":123}}", "a/b/c", 123},
100       {"{\"x\":{\"y\":{\"z\":789}}", "x/*/z", 789},
101       /* simple array */
102       {"[10,11,12,13]", "0", 10},
103       {"[10,11,12,13]", "1", 11},
104       {"[10,11,12,13]", "2", 12},
105       {"[10,11,12,13]", "3", 13},
106       /* array index after non-numeric entry */
107       {"[true,11]", "1", 11},
108       {"[null,11]", "1", 11},
109       {"[\"s\",11]", "1", 11},
110       {"[{\"k\":\"v\"},11]", "1", 11},
111       {"[[0,1,2],11]", "1", 11},
112       /* nested array */
113       {"[[0,1,2],[3,4,5],[6,7,8]]", "0/0", 0},
114       {"[[0,1,2],[3,4,5],[6,7,8]]", "0/1", 1},
115       {"[[0,1,2],[3,4,5],[6,7,8]]", "0/2", 2},
116       {"[[0,1,2],[3,4,5],[6,7,8]]", "1/0", 3},
117       {"[[0,1,2],[3,4,5],[6,7,8]]", "1/1", 4},
118       {"[[0,1,2],[3,4,5],[6,7,8]]", "1/2", 5},
119       {"[[0,1,2],[3,4,5],[6,7,8]]", "2/0", 6},
120       {"[[0,1,2],[3,4,5],[6,7,8]]", "2/1", 7},
121       {"[[0,1,2],[3,4,5],[6,7,8]]", "2/2", 8},
122       /* testcase from #2266 */
123       {"{\"a\":[[10,11,12,13,14]]}", "a/0/0", 10},
124       {"{\"a\":[[10,11,12,13,14]]}", "a/0/1", 11},
125       {"{\"a\":[[10,11,12,13,14]]}", "a/0/2", 12},
126       {"{\"a\":[[10,11,12,13,14]]}", "a/0/3", 13},
127       {"{\"a\":[[10,11,12,13,14]]}", "a/0/4", 14},
128   };
129
130   for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
131     cj_t *db = test_setup(cases[i].json, cases[i].key_path);
132
133     EXPECT_EQ_INT(cases[i].want, test_metric(db, cases[i].key_path));
134
135     test_teardown(db);
136   }
137
138   return 0;
139 }
140
141 int main(int argc, char **argv) {
142   cj_submit = test_submit;
143
144   RUN_TEST(parse);
145
146   END_TEST;
147 }