]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / test / unit / lib / jsonrpc / jsonrpc_server.c / jsonrpc_server_ut.c
CommitLineData
7c673cae
FG
1/*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
11fdf7f2 34#include "spdk/stdinc.h"
7c673cae 35
11fdf7f2 36#include "spdk_cunit.h"
7c673cae 37
11fdf7f2 38#include "jsonrpc/jsonrpc_server.c"
7c673cae 39
9f95a23c
TL
40static struct spdk_jsonrpc_request *g_request;
41static int g_parse_error;
42const struct spdk_json_val *g_method;
43const struct spdk_json_val *g_params;
44
45const struct spdk_json_val *g_cur_param;
7c673cae
FG
46
47#define PARSE_PASS(in, trailing) \
9f95a23c
TL
48 CU_ASSERT(g_cur_param == NULL); \
49 g_cur_param = NULL; \
f67539c2 50 CU_ASSERT(jsonrpc_parse_request(conn, in, sizeof(in) - 1) == sizeof(in) - sizeof(trailing))
9f95a23c
TL
51
52#define REQ_BEGIN(expected_error) \
53 if (expected_error != 0 ) { \
54 CU_ASSERT(g_parse_error == expected_error); \
55 CU_ASSERT(g_params == NULL); \
11fdf7f2 56 }
7c673cae
FG
57
58#define PARSE_FAIL(in) \
f67539c2 59 CU_ASSERT(jsonrpc_parse_request(conn, in, sizeof(in) - 1) < 0);
7c673cae 60
9f95a23c
TL
61#define REQ_BEGIN_VALID() \
62 REQ_BEGIN(0); \
63 SPDK_CU_ASSERT_FATAL(g_params != NULL);
64
65#define REQ_BEGIN_INVALID(expected_error) \
66 REQ_BEGIN(expected_error); \
67 REQ_METHOD_MISSING(); \
68 REQ_ID_MISSING(); \
69 REQ_PARAMS_MISSING()
7c673cae 70
7c673cae
FG
71
72#define REQ_METHOD(name) \
9f95a23c 73 CU_ASSERT(g_method && spdk_json_strequal(g_method, name) == true)
7c673cae
FG
74
75#define REQ_METHOD_MISSING() \
9f95a23c 76 CU_ASSERT(g_method == NULL)
7c673cae
FG
77
78#define REQ_ID_NUM(num) \
9f95a23c
TL
79 CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_NUMBER); \
80 CU_ASSERT(g_request->id && memcmp(g_request->id->start, num, sizeof(num) - 1) == 0)
81
7c673cae
FG
82
83#define REQ_ID_STRING(str) \
9f95a23c
TL
84 CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_STRING); \
85 CU_ASSERT(g_request->id && memcmp(g_request->id->start, num, strlen(num) - 1) == 0))
7c673cae 86
11fdf7f2 87#define REQ_ID_NULL() \
9f95a23c 88 CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_NULL)
11fdf7f2 89
7c673cae 90#define REQ_ID_MISSING() \
9f95a23c 91 CU_ASSERT(g_request->id == NULL)
7c673cae
FG
92
93#define REQ_PARAMS_MISSING() \
9f95a23c 94 CU_ASSERT(g_params == NULL)
7c673cae
FG
95
96#define REQ_PARAMS_BEGIN() \
9f95a23c
TL
97 SPDK_CU_ASSERT_FATAL(g_params != NULL); \
98 CU_ASSERT(g_cur_param == NULL); \
99 g_cur_param = g_params
7c673cae
FG
100
101#define PARAM_ARRAY_BEGIN() \
9f95a23c
TL
102 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_ARRAY_BEGIN); \
103 g_cur_param++
7c673cae
FG
104
105#define PARAM_ARRAY_END() \
9f95a23c
TL
106 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_ARRAY_END); \
107 g_cur_param++
7c673cae
FG
108
109#define PARAM_OBJECT_BEGIN() \
9f95a23c
TL
110 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_OBJECT_BEGIN); \
111 g_cur_param++
7c673cae
FG
112
113#define PARAM_OBJECT_END() \
9f95a23c
TL
114 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_OBJECT_END); \
115 g_cur_param++
7c673cae
FG
116
117#define PARAM_NUM(num) \
9f95a23c
TL
118 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_NUMBER); \
119 CU_ASSERT(g_cur_param->len == sizeof(num) - 1); \
120 CU_ASSERT(memcmp(g_cur_param->start, num, sizeof(num) - 1) == 0); \
121 g_cur_param++
7c673cae
FG
122
123#define PARAM_NAME(str) \
9f95a23c
TL
124 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_NAME); \
125 CU_ASSERT(g_cur_param->len == sizeof(str) - 1); \
126 CU_ASSERT(g_cur_param && memcmp(g_cur_param->start, str, sizeof(str) - 1) == 0); \
127 g_cur_param++
7c673cae
FG
128
129#define PARAM_STRING(str) \
9f95a23c
TL
130 CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_STRING); \
131 CU_ASSERT(g_cur_param->len == sizeof(str) - 1); \
132 CU_ASSERT(memcmp(g_cur_param->start, str, g_params->len) == 0); \
133 g_cur_param++
7c673cae 134
11fdf7f2 135#define FREE_REQUEST() \
f67539c2 136 ut_jsonrpc_free_request(g_request, g_parse_error); \
9f95a23c
TL
137 g_request = NULL; \
138 g_cur_param = NULL; \
139 g_parse_error = 0; \
140 g_method = NULL; \
141 g_cur_param = g_params = NULL
142
f67539c2
TL
143static void
144ut_jsonrpc_free_request(struct spdk_jsonrpc_request *request, int err)
145{
146 struct spdk_json_write_ctx *w;
147
148 if (!request) {
149 return;
150 }
151
152 /* Need to emulate response to get the response write contex free */
153 if (err == 0) {
154 w = spdk_jsonrpc_begin_result(request);
155 spdk_json_write_string(w, "UT PASS response");
156 spdk_jsonrpc_end_result(request, w);
157 } else {
158 spdk_jsonrpc_send_error_response_fmt(request, err, "UT error response");
159 }
160
161 jsonrpc_free_request(request);
162}
11fdf7f2 163
7c673cae 164static void
11fdf7f2
TL
165ut_handle(struct spdk_jsonrpc_request *request, int error, const struct spdk_json_val *method,
166 const struct spdk_json_val *params)
7c673cae 167{
9f95a23c
TL
168 CU_ASSERT(g_request == NULL);
169 g_request = request;
170 g_parse_error = error;
171 g_method = method;
172 g_params = params;
7c673cae
FG
173}
174
175void
f67539c2 176jsonrpc_server_handle_error(struct spdk_jsonrpc_request *request, int error)
7c673cae 177{
11fdf7f2 178 ut_handle(request, error, NULL, NULL);
7c673cae
FG
179}
180
181void
f67539c2
TL
182jsonrpc_server_handle_request(struct spdk_jsonrpc_request *request,
183 const struct spdk_json_val *method, const struct spdk_json_val *params)
7c673cae 184{
11fdf7f2 185 ut_handle(request, 0, method, params);
7c673cae
FG
186}
187
11fdf7f2 188void
f67539c2 189jsonrpc_server_send_response(struct spdk_jsonrpc_request *request)
7c673cae 190{
7c673cae
FG
191}
192
193static void
194test_parse_request(void)
195{
196 struct spdk_jsonrpc_server *server;
197 struct spdk_jsonrpc_server_conn *conn;
198
199 server = calloc(1, sizeof(*server));
200 SPDK_CU_ASSERT_FATAL(server != NULL);
201
202 conn = calloc(1, sizeof(*conn));
203 SPDK_CU_ASSERT_FATAL(conn != NULL);
204
205 conn->server = server;
206
9f95a23c
TL
207 /* rpc call with no parameters. */
208 PARSE_PASS("{ }", "");
209 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
210 FREE_REQUEST();
211
212 /* rpc call with method that is not a string. */
213 PARSE_PASS("{\"jsonrpc\":\"2.0\", \"method\": null }", "");
214 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
215 FREE_REQUEST();
216
217 /* rpc call with invalid JSON RPC version. */
218 PARSE_PASS("{\"jsonrpc\":\"42\", \"method\": \"subtract\"}", "");
219 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
220 FREE_REQUEST();
221
222 /* rpc call with embedded zeros. */
223 PARSE_FAIL("{\"jsonrpc\":\"2.0\",\"method\":\"foo\",\"params\":{\"bar\": \"\0\0baz\"}}");
224 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
225 FREE_REQUEST();
226
7c673cae
FG
227 /* rpc call with positional parameters */
228 PARSE_PASS("{\"jsonrpc\":\"2.0\",\"method\":\"subtract\",\"params\":[42,23],\"id\":1}", "");
229 REQ_BEGIN_VALID();
230 REQ_METHOD("subtract");
231 REQ_ID_NUM("1");
232 REQ_PARAMS_BEGIN();
233 PARAM_ARRAY_BEGIN();
234 PARAM_NUM("42");
235 PARAM_NUM("23");
236 PARAM_ARRAY_END();
11fdf7f2 237 FREE_REQUEST();
7c673cae
FG
238
239 /* rpc call with named parameters */
240 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": {\"subtrahend\": 23, \"minuend\": 42}, \"id\": 3}",
241 "");
242 REQ_BEGIN_VALID();
243 REQ_METHOD("subtract");
244 REQ_ID_NUM("3");
245 REQ_PARAMS_BEGIN();
246 PARAM_OBJECT_BEGIN();
247 PARAM_NAME("subtrahend");
248 PARAM_NUM("23");
249 PARAM_NAME("minuend");
250 PARAM_NUM("42");
251 PARAM_OBJECT_END();
11fdf7f2 252 FREE_REQUEST();
7c673cae
FG
253
254 /* notification */
255 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"update\", \"params\": [1,2,3,4,5]}", "");
256 REQ_BEGIN_VALID();
257 REQ_METHOD("update");
258 REQ_ID_MISSING();
259 REQ_PARAMS_BEGIN();
260 PARAM_ARRAY_BEGIN();
261 PARAM_NUM("1");
262 PARAM_NUM("2");
263 PARAM_NUM("3");
264 PARAM_NUM("4");
265 PARAM_NUM("5");
266 PARAM_ARRAY_END();
11fdf7f2 267 FREE_REQUEST();
7c673cae 268
9f95a23c
TL
269 /* notification with explicit NULL ID. This is discouraged by JSON RPC spec but allowed. */
270 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"update\", \"params\": [1,2,3,4,5], \"id\": null}",
271 "");
272 REQ_BEGIN_VALID();
273 REQ_METHOD("update");
274 REQ_ID_NULL();
275 REQ_PARAMS_BEGIN();
276 PARAM_ARRAY_BEGIN();
277 PARAM_NUM("1");
278 PARAM_NUM("2");
279 PARAM_NUM("3");
280 PARAM_NUM("4");
281 PARAM_NUM("5");
282 PARAM_ARRAY_END();
283 FREE_REQUEST();
284
7c673cae
FG
285 /* invalid JSON */
286 PARSE_FAIL("{\"jsonrpc\": \"2.0\", \"method\": \"foobar, \"params\": \"bar\", \"baz]");
287 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
11fdf7f2 288 FREE_REQUEST();
7c673cae
FG
289
290 /* invalid request (method must be a string; params must be array or object) */
291 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": 1, \"params\": \"bar\"}", "");
292 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
11fdf7f2 293 FREE_REQUEST();
7c673cae
FG
294
295 /* batch, invalid JSON */
296 PARSE_FAIL(
297 "["
298 "{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"},"
299 "{\"jsonrpc\": \"2.0\", \"method\""
300 "]");
301 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
11fdf7f2 302 FREE_REQUEST();
7c673cae
FG
303
304 /* empty array */
305 PARSE_PASS("[]", "");
306 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
11fdf7f2 307 FREE_REQUEST();
7c673cae 308
11fdf7f2 309 /* batch - not supported */
7c673cae
FG
310 PARSE_PASS(
311 "["
312 "{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"},"
313 "{\"jsonrpc\": \"2.0\", \"method\": \"notify_hello\", \"params\": [7]},"
314 "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42,23], \"id\": \"2\"},"
315 "{\"foo\": \"boo\"},"
316 "{\"jsonrpc\": \"2.0\", \"method\": \"foo.get\", \"params\": {\"name\": \"myself\"}, \"id\": \"5\"},"
317 "{\"jsonrpc\": \"2.0\", \"method\": \"get_data\", \"id\": \"9\"}"
318 "]", "");
319
7c673cae 320 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
11fdf7f2 321 FREE_REQUEST();
7c673cae 322
9f95a23c 323 CU_ASSERT(conn->outstanding_requests == 0);
7c673cae
FG
324 free(conn);
325 free(server);
326}
327
328static void
329test_parse_request_streaming(void)
330{
331 struct spdk_jsonrpc_server *server;
332 struct spdk_jsonrpc_server_conn *conn;
9f95a23c 333 const char *json_req;
7c673cae
FG
334 size_t len, i;
335
336 server = calloc(1, sizeof(*server));
337 SPDK_CU_ASSERT_FATAL(server != NULL);
338
339 conn = calloc(1, sizeof(*conn));
340 SPDK_CU_ASSERT_FATAL(conn != NULL);
341
342 conn->server = server;
343
9f95a23c 344
7c673cae
FG
345 /*
346 * Two valid requests end to end in the same buffer.
347 * Parse should return the first one and point to the beginning of the second one.
348 */
349 PARSE_PASS(
350 "{\"jsonrpc\":\"2.0\",\"method\":\"a\",\"params\":[1],\"id\":1}"
351 "{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}",
352 "{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}");
9f95a23c 353
7c673cae
FG
354 REQ_BEGIN_VALID();
355 REQ_METHOD("a");
356 REQ_ID_NUM("1");
357 REQ_PARAMS_BEGIN();
358 PARAM_ARRAY_BEGIN();
359 PARAM_NUM("1");
360 PARAM_ARRAY_END();
11fdf7f2 361 FREE_REQUEST();
7c673cae
FG
362
363 /* Partial (but not invalid) requests - parse should not consume anything. */
9f95a23c
TL
364 json_req = " {\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}";
365 len = strlen(json_req);
7c673cae
FG
366
367 /* Try every partial length up to the full request length */
368 for (i = 0; i < len; i++) {
f67539c2 369 int rc = jsonrpc_parse_request(conn, json_req, i);
7c673cae
FG
370 /* Partial request - no data consumed */
371 CU_ASSERT(rc == 0);
9f95a23c
TL
372 CU_ASSERT(g_request == NULL);
373
374 /* In case of faile, don't fload console with ussless CU assert fails. */
11fdf7f2 375 FREE_REQUEST();
7c673cae
FG
376 }
377
378 /* Verify that full request can be parsed successfully */
f67539c2 379 CU_ASSERT(jsonrpc_parse_request(conn, json_req, len) == (ssize_t)len);
11fdf7f2 380 FREE_REQUEST();
7c673cae 381
9f95a23c 382 CU_ASSERT(conn->outstanding_requests == 0);
7c673cae
FG
383 free(conn);
384 free(server);
385}
386
387int main(int argc, char **argv)
388{
389 CU_pSuite suite = NULL;
390 unsigned int num_failures;
391
f67539c2
TL
392 CU_set_error_action(CUEA_ABORT);
393 CU_initialize_registry();
7c673cae
FG
394
395 suite = CU_add_suite("jsonrpc", NULL, NULL);
7c673cae 396
f67539c2
TL
397 CU_ADD_TEST(suite, test_parse_request);
398 CU_ADD_TEST(suite, test_parse_request_streaming);
7c673cae
FG
399 CU_basic_set_mode(CU_BRM_VERBOSE);
400
401 CU_basic_run_tests();
402
403 num_failures = CU_get_number_of_failures();
404 CU_cleanup_registry();
405
9f95a23c
TL
406 /* This is for ASAN. Don't know why but if pointer is left in global varaible
407 * it won't be detected as leak. */
408 g_request = NULL;
7c673cae
FG
409 return num_failures;
410}