1 #include "ejdb_test.h"
2 #include <CUnit/Basic.h>
3 #include <curl/curl.h>
4
5 CURL *curl;
6
init_suite()7 int init_suite() {
8 curl_global_init(CURL_GLOBAL_ALL);
9 curl = curl_easy_init();
10 if (!curl) {
11 return 1;
12 }
13 int rc = ejdb_init();
14 return rc;
15 }
16
clean_suite()17 int clean_suite() {
18 curl_easy_cleanup(curl);
19 curl_global_cleanup();
20 return 0;
21 }
22
curl_write_xstr(void * contents,size_t size,size_t nmemb,void * op)23 static size_t curl_write_xstr(void *contents, size_t size, size_t nmemb, void *op) {
24 IWXSTR *xstr = op;
25 assert(xstr);
26 iwxstr_cat(xstr, contents, size * nmemb);
27 return size * nmemb;
28 }
29
jbr_test1_1()30 static void jbr_test1_1() {
31 char url[64];
32 uint32_t port = iwu_rand_range(20000) + 20000;
33
34 EJDB_OPTS opts = {
35 .kv = {
36 .path = "jbr_test1_1.db",
37 .oflags = IWKV_TRUNC
38 },
39 .no_wal = true,
40 .http = {
41 .bind = "127.0.0.1",
42 .blocking = false,
43 .enabled = true,
44 .port = port
45 }
46 };
47
48 long code;
49 EJDB db;
50 iwrc rc = ejdb_open(&opts, &db);
51 if (rc) {
52 iwlog_ecode_error3(rc);
53 }
54 CU_ASSERT_EQUAL_FATAL(rc, 0);
55
56 IWXSTR *xstr = iwxstr_new();
57 IWXSTR *hstr = iwxstr_new();
58 struct curl_slist *headers = curl_slist_append(0, "Content-Type: application/json");
59
60 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1/1", port);
61
62 // Check no element in collection
63 CURLcode cc = curl_easy_setopt(curl, CURLOPT_URL, url);
64 CU_ASSERT_EQUAL_FATAL(cc, 0);
65 cc = curl_easy_perform(curl);
66 CU_ASSERT_EQUAL_FATAL(cc, 0);
67 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
68 CU_ASSERT_EQUAL_FATAL(code, 404);
69
70
71 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1", port);
72
73 // Save a document using POST
74 curl_easy_reset(curl);
75 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
76 CU_ASSERT_EQUAL_FATAL(cc, 0);
77 curl_easy_setopt(curl, CURLOPT_URL, url);
78 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
79 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"foo\":\"bar\"}");
80 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
81 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
82 cc = curl_easy_perform(curl);
83 CU_ASSERT_EQUAL_FATAL(cc, 0);
84 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
85 CU_ASSERT_EQUAL_FATAL(code, 200);
86 CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr), "1");
87
88 // Now get document JSON using GET
89 curl_easy_reset(curl);
90 iwxstr_clear(xstr);
91 iwxstr_clear(hstr);
92
93 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1/1", port);
94
95 curl_easy_setopt(curl, CURLOPT_URL, url);
96 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
97 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
98 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_write_xstr);
99 curl_easy_setopt(curl, CURLOPT_HEADERDATA, hstr);
100 cc = curl_easy_perform(curl);
101 CU_ASSERT_EQUAL_FATAL(cc, 0);
102 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
103 CU_ASSERT_EQUAL_FATAL(code, 200);
104 CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr),
105 "{\n"
106 " \"foo\": \"bar\"\n"
107 "}"
108 );
109 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(hstr), "content-type:application/json"));
110 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(hstr), "content-length:17"));
111 CU_ASSERT_EQUAL(iwxstr_size(xstr), 17);
112
113 // PUT document under specific ID
114 curl_easy_reset(curl);
115 iwxstr_clear(xstr);
116 iwxstr_clear(hstr);
117 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
118 CU_ASSERT_EQUAL_FATAL(cc, 0);
119
120 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1/33", port);
121
122 curl_easy_setopt(curl, CURLOPT_URL, url);
123 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
124 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"foo\":\"b\nar\"}");
125 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
126 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
127 cc = curl_easy_perform(curl);
128 CU_ASSERT_EQUAL_FATAL(cc, 0);
129 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
130 CU_ASSERT_EQUAL_FATAL(code, 200);
131
132 // Check the last doc
133 curl_easy_reset(curl);
134 iwxstr_clear(xstr);
135 iwxstr_clear(hstr);
136 curl_easy_setopt(curl, CURLOPT_URL, url);
137 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
138 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
139 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_write_xstr);
140 curl_easy_setopt(curl, CURLOPT_HEADERDATA, hstr);
141 cc = curl_easy_perform(curl);
142 CU_ASSERT_EQUAL_FATAL(cc, 0);
143 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
144 CU_ASSERT_EQUAL_FATAL(code, 200);
145 CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr),
146 "{\n"
147 " \"foo\": \"b\\nar\"\n"
148 "}"
149 );
150 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(hstr), "content-type:application/json"));
151 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(hstr), "content-length:19"));
152 CU_ASSERT_EQUAL(iwxstr_size(xstr), 19);
153
154 // Perform a query
155 curl_easy_reset(curl);
156 iwxstr_clear(xstr);
157 iwxstr_clear(hstr);
158
159 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/", port);
160
161 curl_easy_setopt(curl, CURLOPT_URL, url);
162 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "@c1/foo");
163 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
164 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
165 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_write_xstr);
166 curl_easy_setopt(curl, CURLOPT_HEADERDATA, hstr);
167 cc = curl_easy_perform(curl);
168 CU_ASSERT_EQUAL_FATAL(cc, 0);
169 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
170 CU_ASSERT_EQUAL_FATAL(code, 200);
171
172 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "33\t{\"foo\":\"b\\nar\"}"));
173 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "1\t{\"foo\":\"bar\"}"));
174
175 // Query with explain
176 curl_easy_reset(curl);
177 iwxstr_clear(xstr);
178 iwxstr_clear(hstr);
179 curl_slist_free_all(headers);
180 headers = curl_slist_append(0, "X-Hints: explain");
181 curl_easy_setopt(curl, CURLOPT_URL, url);
182 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
183 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "@c1/foo");
184 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
185 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
186 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_write_xstr);
187 curl_easy_setopt(curl, CURLOPT_HEADERDATA, hstr);
188 cc = curl_easy_perform(curl);
189 CU_ASSERT_EQUAL_FATAL(cc, 0);
190 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
191 CU_ASSERT_EQUAL_FATAL(code, 200);
192 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "[INDEX] NO [COLLECTOR] PLAIN"));
193 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "--------------------"));
194 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "33\t{\"foo\":\"b\\nar\"}"));
195 CU_ASSERT_PTR_NOT_NULL(strstr(iwxstr_ptr(xstr), "1\t{\"foo\":\"bar\"}"));
196
197 // Delete resource
198 curl_easy_reset(curl);
199 iwxstr_clear(xstr);
200 iwxstr_clear(hstr);
201
202 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1/33", port);
203
204 curl_easy_setopt(curl, CURLOPT_URL, url);
205 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
206 cc = curl_easy_perform(curl);
207 CU_ASSERT_EQUAL_FATAL(cc, 0);
208 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
209 CU_ASSERT_EQUAL_FATAL(code, 200);
210
211 // Check the resource has been deleted
212 curl_easy_reset(curl);
213 iwxstr_clear(xstr);
214 iwxstr_clear(hstr);
215 curl_easy_setopt(curl, CURLOPT_URL, url);
216 cc = curl_easy_perform(curl);
217 CU_ASSERT_EQUAL_FATAL(cc, 0);
218 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
219 CU_ASSERT_EQUAL_FATAL(code, 404);
220
221 // Apply patch
222 curl_easy_reset(curl);
223 iwxstr_clear(xstr);
224 iwxstr_clear(hstr);
225 curl_slist_free_all(headers);
226 headers = curl_slist_append(0, "Content-Type: application/json");
227
228 snprintf(url, sizeof(url), "http://localhost:%" PRIu32 "/c1/1", port);
229
230 curl_easy_setopt(curl, CURLOPT_URL, url);
231 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
232 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
233 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "[{\"op\":\"replace\", \"path\":\"/foo\", \"value\":\"zzz\"}]");
234 cc = curl_easy_perform(curl);
235 CU_ASSERT_EQUAL_FATAL(cc, 0);
236 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
237 CU_ASSERT_EQUAL_FATAL(code, 200);
238
239 // Check patch applied
240 curl_easy_reset(curl);
241 iwxstr_clear(xstr);
242 iwxstr_clear(hstr);
243 curl_easy_setopt(curl, CURLOPT_URL, url);
244 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_xstr);
245 curl_easy_setopt(curl, CURLOPT_WRITEDATA, xstr);
246 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_write_xstr);
247 curl_easy_setopt(curl, CURLOPT_HEADERDATA, hstr);
248 cc = curl_easy_perform(curl);
249 CU_ASSERT_EQUAL_FATAL(cc, 0);
250 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
251 CU_ASSERT_EQUAL_FATAL(code, 200);
252 CU_ASSERT_STRING_EQUAL(iwxstr_ptr(xstr),
253 "{\n"
254 " \"foo\": \"zzz\"\n"
255 "}"
256 );
257
258
259 iwxstr_destroy(xstr);
260 iwxstr_destroy(hstr);
261 curl_slist_free_all(headers);
262 rc = ejdb_close(&db);
263 CU_ASSERT_EQUAL_FATAL(rc, 0);
264 }
265
main()266 int main() {
267 CU_pSuite pSuite = NULL;
268 if (CUE_SUCCESS != CU_initialize_registry()) {
269 return CU_get_error();
270 }
271 pSuite = CU_add_suite("jbr_test1", init_suite, clean_suite);
272 if (NULL == pSuite) {
273 CU_cleanup_registry();
274 return CU_get_error();
275 }
276 if (
277 (NULL == CU_add_test(pSuite, "jbr_test1_1", jbr_test1_1))) {
278 CU_cleanup_registry();
279 return CU_get_error();
280 }
281 CU_basic_set_mode(CU_BRM_VERBOSE);
282 CU_basic_run_tests();
283 int ret = CU_get_error() || CU_get_number_of_failures();
284 CU_cleanup_registry();
285 return ret;
286 }
287