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 34 #include "spdk/stdinc.h" 35 36 #include "spdk_cunit.h" 37 38 #include "jsonrpc_server.c" 39 40 #define MAX_PARAMS 100 41 #define MAX_REQS 100 42 43 struct req { 44 int error; 45 bool got_method; 46 bool got_id; 47 bool got_params; 48 struct spdk_json_val method; 49 struct spdk_json_val id; 50 struct spdk_json_val params[MAX_PARAMS]; 51 }; 52 53 static uint8_t g_buf[1000]; 54 static struct req g_reqs[MAX_REQS]; 55 static struct req *g_cur_req; 56 static struct spdk_json_val *g_params; 57 static size_t g_num_reqs; 58 59 #define PARSE_PASS(in, trailing) \ 60 memcpy(g_buf, in, sizeof(in) - 1); \ 61 g_num_reqs = 0; \ 62 g_cur_req = NULL; \ 63 CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) == sizeof(in) - sizeof(trailing)) 64 65 #define PARSE_FAIL(in) \ 66 memcpy(g_buf, in, sizeof(in) - 1); \ 67 g_num_reqs = 0; \ 68 g_cur_req = 0; \ 69 CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, sizeof(in) - 1) < 0) 70 71 72 #define REQ_BEGIN(expected_error) \ 73 if (g_cur_req == NULL) { \ 74 g_cur_req = g_reqs; \ 75 } else { \ 76 g_cur_req++; \ 77 } \ 78 CU_ASSERT(g_cur_req - g_reqs <= (ptrdiff_t)g_num_reqs); \ 79 CU_ASSERT(g_cur_req->error == expected_error) 80 81 #define REQ_BEGIN_VALID() REQ_BEGIN(0) 82 #define REQ_BEGIN_INVALID(expected_error) REQ_BEGIN(expected_error) 83 84 #define REQ_METHOD(name) \ 85 CU_ASSERT(g_cur_req->got_method); \ 86 CU_ASSERT(spdk_json_strequal(&g_cur_req->method, name) == true) 87 88 #define REQ_METHOD_MISSING() \ 89 CU_ASSERT(g_cur_req->got_method == false) 90 91 #define REQ_ID_NUM(num) \ 92 CU_ASSERT(g_cur_req->got_id); \ 93 CU_ASSERT(g_cur_req->id.type == SPDK_JSON_VAL_NUMBER); \ 94 CU_ASSERT(memcmp(g_cur_req->id.start, num, sizeof(num) - 1) == 0) 95 96 #define REQ_ID_STRING(str) \ 97 CU_ASSERT(g_cur_req->got_id); \ 98 CU_ASSERT(g_cur_req->id.type == SPDK_JSON_VAL_STRING); \ 99 CU_ASSERT(memcmp(g_cur_req->id.start, str, sizeof(str) - 1) == 0) 100 101 #define REQ_ID_MISSING() \ 102 CU_ASSERT(g_cur_req->got_id == false) 103 104 #define REQ_PARAMS_MISSING() \ 105 CU_ASSERT(g_cur_req->got_params == false) 106 107 #define REQ_PARAMS_BEGIN() \ 108 CU_ASSERT(g_cur_req->got_params); \ 109 g_params = g_cur_req->params 110 111 #define PARAM_ARRAY_BEGIN() \ 112 CU_ASSERT(g_params->type == SPDK_JSON_VAL_ARRAY_BEGIN); \ 113 g_params++ 114 115 #define PARAM_ARRAY_END() \ 116 CU_ASSERT(g_params->type == SPDK_JSON_VAL_ARRAY_END); \ 117 g_params++ 118 119 #define PARAM_OBJECT_BEGIN() \ 120 CU_ASSERT(g_params->type == SPDK_JSON_VAL_OBJECT_BEGIN); \ 121 g_params++ 122 123 #define PARAM_OBJECT_END() \ 124 CU_ASSERT(g_params->type == SPDK_JSON_VAL_OBJECT_END); \ 125 g_params++ 126 127 #define PARAM_NUM(num) \ 128 CU_ASSERT(g_params->type == SPDK_JSON_VAL_NUMBER); \ 129 CU_ASSERT(g_params->len == sizeof(num) - 1); \ 130 CU_ASSERT(memcmp(g_params->start, num, g_params->len) == 0); \ 131 g_params++ 132 133 #define PARAM_NAME(str) \ 134 CU_ASSERT(g_params->type == SPDK_JSON_VAL_NAME); \ 135 CU_ASSERT(g_params->len == sizeof(str) - 1); \ 136 CU_ASSERT(memcmp(g_params->start, str, g_params->len) == 0); \ 137 g_params++ 138 139 #define PARAM_STRING(str) \ 140 CU_ASSERT(g_params->type == SPDK_JSON_VAL_STRING); \ 141 CU_ASSERT(g_params->len == sizeof(str) - 1); \ 142 CU_ASSERT(memcmp(g_params->start, str, g_params->len) == 0); \ 143 g_params++ 144 145 static void 146 ut_handle(struct spdk_jsonrpc_server_conn *conn, int error, const struct spdk_json_val *method, 147 const struct spdk_json_val *params, const struct spdk_json_val *id) 148 { 149 struct req *r; 150 151 SPDK_CU_ASSERT_FATAL(g_num_reqs != MAX_REQS); 152 r = &g_reqs[g_num_reqs++]; 153 154 r->error = error; 155 156 if (method) { 157 r->got_method = true; 158 r->method = *method; 159 } else { 160 r->got_method = false; 161 } 162 163 if (params) { 164 r->got_params = true; 165 SPDK_CU_ASSERT_FATAL(spdk_json_val_len(params) < MAX_PARAMS); 166 memcpy(r->params, params, spdk_json_val_len(params) * sizeof(struct spdk_json_val)); 167 } else { 168 r->got_params = false; 169 } 170 171 if (id) { 172 r->got_id = true; 173 r->id = *id; 174 } else { 175 r->got_id = false; 176 } 177 } 178 179 void 180 spdk_jsonrpc_server_handle_error(struct spdk_jsonrpc_server_conn *conn, int error, 181 const struct spdk_json_val *method, const struct spdk_json_val *params, 182 const struct spdk_json_val *id) 183 { 184 ut_handle(conn, error, method, params, id); 185 } 186 187 void 188 spdk_jsonrpc_server_handle_request(struct spdk_jsonrpc_server_conn *conn, 189 const struct spdk_json_val *method, const struct spdk_json_val *params, 190 const struct spdk_json_val *id) 191 { 192 ut_handle(conn, 0, method, params, id); 193 } 194 195 int 196 spdk_jsonrpc_server_write_cb(void *cb_ctx, const void *data, size_t size) 197 { 198 /* TODO */ 199 return -1; 200 } 201 202 static void 203 test_parse_request(void) 204 { 205 struct spdk_jsonrpc_server *server; 206 struct spdk_jsonrpc_server_conn *conn; 207 208 server = calloc(1, sizeof(*server)); 209 SPDK_CU_ASSERT_FATAL(server != NULL); 210 211 conn = calloc(1, sizeof(*conn)); 212 SPDK_CU_ASSERT_FATAL(conn != NULL); 213 214 conn->server = server; 215 216 /* rpc call with positional parameters */ 217 PARSE_PASS("{\"jsonrpc\":\"2.0\",\"method\":\"subtract\",\"params\":[42,23],\"id\":1}", ""); 218 REQ_BEGIN_VALID(); 219 REQ_METHOD("subtract"); 220 REQ_ID_NUM("1"); 221 REQ_PARAMS_BEGIN(); 222 PARAM_ARRAY_BEGIN(); 223 PARAM_NUM("42"); 224 PARAM_NUM("23"); 225 PARAM_ARRAY_END(); 226 227 /* rpc call with named parameters */ 228 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": {\"subtrahend\": 23, \"minuend\": 42}, \"id\": 3}", 229 ""); 230 REQ_BEGIN_VALID(); 231 REQ_METHOD("subtract"); 232 REQ_ID_NUM("3"); 233 REQ_PARAMS_BEGIN(); 234 PARAM_OBJECT_BEGIN(); 235 PARAM_NAME("subtrahend"); 236 PARAM_NUM("23"); 237 PARAM_NAME("minuend"); 238 PARAM_NUM("42"); 239 PARAM_OBJECT_END(); 240 241 /* notification */ 242 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"update\", \"params\": [1,2,3,4,5]}", ""); 243 REQ_BEGIN_VALID(); 244 REQ_METHOD("update"); 245 REQ_ID_MISSING(); 246 REQ_PARAMS_BEGIN(); 247 PARAM_ARRAY_BEGIN(); 248 PARAM_NUM("1"); 249 PARAM_NUM("2"); 250 PARAM_NUM("3"); 251 PARAM_NUM("4"); 252 PARAM_NUM("5"); 253 PARAM_ARRAY_END(); 254 255 /* invalid JSON */ 256 PARSE_FAIL("{\"jsonrpc\": \"2.0\", \"method\": \"foobar, \"params\": \"bar\", \"baz]"); 257 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR); 258 REQ_METHOD_MISSING(); 259 REQ_ID_MISSING(); 260 REQ_PARAMS_MISSING(); 261 262 /* invalid request (method must be a string; params must be array or object) */ 263 PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": 1, \"params\": \"bar\"}", ""); 264 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 265 REQ_METHOD_MISSING(); 266 REQ_ID_MISSING(); 267 REQ_PARAMS_MISSING(); 268 269 /* batch, invalid JSON */ 270 PARSE_FAIL( 271 "[" 272 "{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"}," 273 "{\"jsonrpc\": \"2.0\", \"method\"" 274 "]"); 275 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR); 276 REQ_METHOD_MISSING(); 277 REQ_ID_MISSING(); 278 REQ_PARAMS_MISSING(); 279 280 /* empty array */ 281 PARSE_PASS("[]", ""); 282 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 283 REQ_METHOD_MISSING(); 284 REQ_ID_MISSING(); 285 REQ_PARAMS_MISSING(); 286 287 /* invalid batch */ 288 PARSE_PASS("[1]", ""); 289 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 290 REQ_METHOD_MISSING(); 291 REQ_ID_MISSING(); 292 REQ_PARAMS_MISSING(); 293 294 /* invalid batch */ 295 PARSE_PASS("[1,2,3]", ""); 296 297 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 298 REQ_METHOD_MISSING(); 299 REQ_ID_MISSING(); 300 REQ_PARAMS_MISSING(); 301 302 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 303 REQ_METHOD_MISSING(); 304 REQ_ID_MISSING(); 305 REQ_PARAMS_MISSING(); 306 307 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 308 REQ_METHOD_MISSING(); 309 REQ_ID_MISSING(); 310 REQ_PARAMS_MISSING(); 311 312 /* batch */ 313 PARSE_PASS( 314 "[" 315 "{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"}," 316 "{\"jsonrpc\": \"2.0\", \"method\": \"notify_hello\", \"params\": [7]}," 317 "{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42,23], \"id\": \"2\"}," 318 "{\"foo\": \"boo\"}," 319 "{\"jsonrpc\": \"2.0\", \"method\": \"foo.get\", \"params\": {\"name\": \"myself\"}, \"id\": \"5\"}," 320 "{\"jsonrpc\": \"2.0\", \"method\": \"get_data\", \"id\": \"9\"}" 321 "]", ""); 322 323 REQ_BEGIN_VALID(); 324 REQ_METHOD("sum"); 325 REQ_ID_STRING("1"); 326 REQ_PARAMS_BEGIN(); 327 PARAM_ARRAY_BEGIN(); 328 PARAM_NUM("1"); 329 PARAM_NUM("2"); 330 PARAM_NUM("4"); 331 PARAM_ARRAY_END(); 332 333 REQ_BEGIN_VALID(); 334 REQ_METHOD("notify_hello"); 335 REQ_ID_MISSING(); 336 REQ_PARAMS_BEGIN(); 337 PARAM_ARRAY_BEGIN(); 338 PARAM_NUM("7"); 339 PARAM_ARRAY_END(); 340 341 REQ_BEGIN_VALID(); 342 REQ_METHOD("subtract"); 343 REQ_ID_STRING("2"); 344 REQ_PARAMS_BEGIN(); 345 PARAM_ARRAY_BEGIN(); 346 PARAM_NUM("42"); 347 PARAM_NUM("23"); 348 PARAM_ARRAY_END(); 349 350 REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST); 351 REQ_METHOD_MISSING(); 352 REQ_ID_MISSING(); 353 REQ_PARAMS_MISSING(); 354 355 REQ_BEGIN_VALID(); 356 REQ_METHOD("foo.get"); 357 REQ_ID_STRING("5"); 358 REQ_PARAMS_BEGIN(); 359 PARAM_OBJECT_BEGIN(); 360 PARAM_NAME("name"); 361 PARAM_STRING("myself"); 362 PARAM_OBJECT_END(); 363 364 REQ_BEGIN_VALID(); 365 REQ_METHOD("get_data"); 366 REQ_ID_STRING("9"); 367 REQ_PARAMS_MISSING(); 368 369 free(conn); 370 free(server); 371 } 372 373 static void 374 test_parse_request_streaming(void) 375 { 376 struct spdk_jsonrpc_server *server; 377 struct spdk_jsonrpc_server_conn *conn; 378 size_t len, i; 379 380 server = calloc(1, sizeof(*server)); 381 SPDK_CU_ASSERT_FATAL(server != NULL); 382 383 conn = calloc(1, sizeof(*conn)); 384 SPDK_CU_ASSERT_FATAL(conn != NULL); 385 386 conn->server = server; 387 388 /* 389 * Two valid requests end to end in the same buffer. 390 * Parse should return the first one and point to the beginning of the second one. 391 */ 392 PARSE_PASS( 393 "{\"jsonrpc\":\"2.0\",\"method\":\"a\",\"params\":[1],\"id\":1}" 394 "{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}", 395 "{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}"); 396 REQ_BEGIN_VALID(); 397 REQ_METHOD("a"); 398 REQ_ID_NUM("1"); 399 REQ_PARAMS_BEGIN(); 400 PARAM_ARRAY_BEGIN(); 401 PARAM_NUM("1"); 402 PARAM_ARRAY_END(); 403 404 /* Partial (but not invalid) requests - parse should not consume anything. */ 405 strcpy(g_buf, "{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}"); 406 len = strlen(g_buf); 407 408 /* Try every partial length up to the full request length */ 409 for (i = 0; i < len; i++) { 410 int rc = spdk_jsonrpc_parse_request(conn, g_buf, i); 411 /* Partial request - no data consumed */ 412 CU_ASSERT(rc == 0); 413 } 414 415 /* Verify that full request can be parsed successfully */ 416 CU_ASSERT(spdk_jsonrpc_parse_request(conn, g_buf, len) == (ssize_t)len); 417 418 free(conn); 419 free(server); 420 } 421 422 int main(int argc, char **argv) 423 { 424 CU_pSuite suite = NULL; 425 unsigned int num_failures; 426 427 if (CU_initialize_registry() != CUE_SUCCESS) { 428 return CU_get_error(); 429 } 430 431 suite = CU_add_suite("jsonrpc", NULL, NULL); 432 if (suite == NULL) { 433 CU_cleanup_registry(); 434 return CU_get_error(); 435 } 436 437 if ( 438 CU_add_test(suite, "parse_request", test_parse_request) == NULL || 439 CU_add_test(suite, "parse_request_streaming", test_parse_request_streaming) == NULL) { 440 CU_cleanup_registry(); 441 return CU_get_error(); 442 } 443 444 CU_basic_set_mode(CU_BRM_VERBOSE); 445 446 CU_basic_run_tests(); 447 448 num_failures = CU_get_number_of_failures(); 449 CU_cleanup_registry(); 450 451 return num_failures; 452 } 453