xref: /spdk/test/unit/lib/jsonrpc/jsonrpc_server.c/jsonrpc_server_ut.c (revision 34edd9f1bf5fda4c987f4500ddc3c9f50be32e7d)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation.
36f7bf931SDaniel Verkamp  *   All rights reserved.
46f7bf931SDaniel Verkamp  */
56f7bf931SDaniel Verkamp 
66f7bf931SDaniel Verkamp #include "spdk/stdinc.h"
76f7bf931SDaniel Verkamp 
8ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
96f7bf931SDaniel Verkamp 
10f8ad4dcaSJim Harris #include "jsonrpc/jsonrpc_server.c"
116f7bf931SDaniel Verkamp 
1263978010SPawel Wodkowski static struct spdk_jsonrpc_request *g_request;
1363978010SPawel Wodkowski static int g_parse_error;
1463978010SPawel Wodkowski const struct spdk_json_val *g_method;
1563978010SPawel Wodkowski const struct spdk_json_val *g_params;
166f7bf931SDaniel Verkamp 
1763978010SPawel Wodkowski const struct spdk_json_val *g_cur_param;
186f7bf931SDaniel Verkamp 
196f7bf931SDaniel Verkamp #define PARSE_PASS(in, trailing) \
2063978010SPawel Wodkowski 	CU_ASSERT(g_cur_param == NULL); \
2163978010SPawel Wodkowski 	g_cur_param = NULL; \
22134590a2SSeth Howell 	CU_ASSERT(jsonrpc_parse_request(conn, in, sizeof(in) - 1) == sizeof(in) - sizeof(trailing))
2363978010SPawel Wodkowski 
2463978010SPawel Wodkowski #define REQ_BEGIN(expected_error) \
2563978010SPawel Wodkowski 	if (expected_error != 0 ) { \
2663978010SPawel Wodkowski 		CU_ASSERT(g_parse_error == expected_error); \
2763978010SPawel Wodkowski 		CU_ASSERT(g_params == NULL); \
28c7852cf9SDaniel Verkamp 	}
296f7bf931SDaniel Verkamp 
306f7bf931SDaniel Verkamp #define PARSE_FAIL(in) \
31134590a2SSeth Howell 	CU_ASSERT(jsonrpc_parse_request(conn, in, sizeof(in) - 1) < 0);
326f7bf931SDaniel Verkamp 
3363978010SPawel Wodkowski #define REQ_BEGIN_VALID() \
3463978010SPawel Wodkowski 		REQ_BEGIN(0); \
3563978010SPawel Wodkowski 		SPDK_CU_ASSERT_FATAL(g_params != NULL);
366f7bf931SDaniel Verkamp 
3763978010SPawel Wodkowski #define REQ_BEGIN_INVALID(expected_error) \
3863978010SPawel Wodkowski 	REQ_BEGIN(expected_error); \
3963978010SPawel Wodkowski 	REQ_METHOD_MISSING(); \
4063978010SPawel Wodkowski 	REQ_ID_MISSING(); \
4163978010SPawel Wodkowski 	REQ_PARAMS_MISSING()
4263978010SPawel Wodkowski 
436f7bf931SDaniel Verkamp 
446f7bf931SDaniel Verkamp #define REQ_METHOD(name) \
4563978010SPawel Wodkowski 	CU_ASSERT(g_method && spdk_json_strequal(g_method, name) == true)
466f7bf931SDaniel Verkamp 
476f7bf931SDaniel Verkamp #define REQ_METHOD_MISSING() \
4863978010SPawel Wodkowski 	CU_ASSERT(g_method == NULL)
496f7bf931SDaniel Verkamp 
506f7bf931SDaniel Verkamp #define REQ_ID_NUM(num) \
5163978010SPawel Wodkowski 	CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_NUMBER); \
5263978010SPawel Wodkowski 	CU_ASSERT(g_request->id && memcmp(g_request->id->start, num, sizeof(num) - 1) == 0)
5363978010SPawel Wodkowski 
546f7bf931SDaniel Verkamp 
556f7bf931SDaniel Verkamp #define REQ_ID_STRING(str) \
5663978010SPawel Wodkowski 	CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_STRING); \
5763978010SPawel Wodkowski 	CU_ASSERT(g_request->id && memcmp(g_request->id->start, num, strlen(num) - 1) == 0))
586f7bf931SDaniel Verkamp 
59977fd230SDaniel Verkamp #define REQ_ID_NULL() \
6063978010SPawel Wodkowski 	CU_ASSERT(g_request->id && g_request->id->type == SPDK_JSON_VAL_NULL)
61977fd230SDaniel Verkamp 
626f7bf931SDaniel Verkamp #define REQ_ID_MISSING() \
6363978010SPawel Wodkowski 	CU_ASSERT(g_request->id == NULL)
646f7bf931SDaniel Verkamp 
656f7bf931SDaniel Verkamp #define REQ_PARAMS_MISSING() \
6663978010SPawel Wodkowski 	CU_ASSERT(g_params == NULL)
676f7bf931SDaniel Verkamp 
686f7bf931SDaniel Verkamp #define REQ_PARAMS_BEGIN() \
6963978010SPawel Wodkowski 	SPDK_CU_ASSERT_FATAL(g_params != NULL); \
7063978010SPawel Wodkowski 	CU_ASSERT(g_cur_param == NULL); \
7163978010SPawel Wodkowski 	g_cur_param = g_params
726f7bf931SDaniel Verkamp 
736f7bf931SDaniel Verkamp #define PARAM_ARRAY_BEGIN() \
7463978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_ARRAY_BEGIN); \
7563978010SPawel Wodkowski 	g_cur_param++
766f7bf931SDaniel Verkamp 
776f7bf931SDaniel Verkamp #define PARAM_ARRAY_END() \
7863978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_ARRAY_END); \
7963978010SPawel Wodkowski 	g_cur_param++
806f7bf931SDaniel Verkamp 
816f7bf931SDaniel Verkamp #define PARAM_OBJECT_BEGIN() \
8263978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_OBJECT_BEGIN); \
8363978010SPawel Wodkowski 	g_cur_param++
846f7bf931SDaniel Verkamp 
856f7bf931SDaniel Verkamp #define PARAM_OBJECT_END() \
8663978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_OBJECT_END); \
8763978010SPawel Wodkowski 	g_cur_param++
886f7bf931SDaniel Verkamp 
896f7bf931SDaniel Verkamp #define PARAM_NUM(num) \
9063978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_NUMBER); \
9163978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->len == sizeof(num) - 1); \
9263978010SPawel Wodkowski 	CU_ASSERT(memcmp(g_cur_param->start, num, sizeof(num) - 1) == 0); \
9363978010SPawel Wodkowski 	g_cur_param++
946f7bf931SDaniel Verkamp 
956f7bf931SDaniel Verkamp #define PARAM_NAME(str) \
9663978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_NAME); \
9763978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->len == sizeof(str) - 1); \
9863978010SPawel Wodkowski 	CU_ASSERT(g_cur_param && memcmp(g_cur_param->start, str, sizeof(str) - 1) == 0); \
9963978010SPawel Wodkowski 	g_cur_param++
1006f7bf931SDaniel Verkamp 
1016f7bf931SDaniel Verkamp #define PARAM_STRING(str) \
10263978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->type == SPDK_JSON_VAL_STRING); \
10363978010SPawel Wodkowski 	CU_ASSERT(g_cur_param->len == sizeof(str) - 1); \
10463978010SPawel Wodkowski 	CU_ASSERT(memcmp(g_cur_param->start, str, g_params->len) == 0); \
10563978010SPawel Wodkowski 	g_cur_param++
1066f7bf931SDaniel Verkamp 
107977fd230SDaniel Verkamp #define FREE_REQUEST() \
108a15dcb0bSPawel Kaminski 	ut_jsonrpc_free_request(g_request, g_parse_error); \
10963978010SPawel Wodkowski 	g_request = NULL; \
11063978010SPawel Wodkowski 	g_cur_param = NULL; \
11163978010SPawel Wodkowski 	g_parse_error = 0; \
11263978010SPawel Wodkowski 	g_method = NULL; \
11363978010SPawel Wodkowski 	g_cur_param = g_params = NULL
11463978010SPawel Wodkowski 
115a15dcb0bSPawel Kaminski static void
116a15dcb0bSPawel Kaminski ut_jsonrpc_free_request(struct spdk_jsonrpc_request *request, int err)
117a15dcb0bSPawel Kaminski {
118a15dcb0bSPawel Kaminski 	struct spdk_json_write_ctx *w;
119a15dcb0bSPawel Kaminski 
120a15dcb0bSPawel Kaminski 	if (!request) {
121a15dcb0bSPawel Kaminski 		return;
122a15dcb0bSPawel Kaminski 	}
123a15dcb0bSPawel Kaminski 
124*34edd9f1SKamil Godzwon 	/* Need to emulate response to get the response write context free */
125a15dcb0bSPawel Kaminski 	if (err == 0) {
126a15dcb0bSPawel Kaminski 		w = spdk_jsonrpc_begin_result(request);
127a15dcb0bSPawel Kaminski 		spdk_json_write_string(w, "UT PASS response");
128a15dcb0bSPawel Kaminski 		spdk_jsonrpc_end_result(request, w);
129a15dcb0bSPawel Kaminski 	} else {
130a15dcb0bSPawel Kaminski 		spdk_jsonrpc_send_error_response_fmt(request, err, "UT error response");
131a15dcb0bSPawel Kaminski 	}
132a15dcb0bSPawel Kaminski 
133134590a2SSeth Howell 	jsonrpc_free_request(request);
134a15dcb0bSPawel Kaminski }
135977fd230SDaniel Verkamp 
1366f7bf931SDaniel Verkamp static void
1372bdec64fSDaniel Verkamp ut_handle(struct spdk_jsonrpc_request *request, int error, const struct spdk_json_val *method,
1382bdec64fSDaniel Verkamp 	  const struct spdk_json_val *params)
1396f7bf931SDaniel Verkamp {
14063978010SPawel Wodkowski 	CU_ASSERT(g_request == NULL);
14163978010SPawel Wodkowski 	g_request = request;
14263978010SPawel Wodkowski 	g_parse_error = error;
14363978010SPawel Wodkowski 	g_method = method;
14463978010SPawel Wodkowski 	g_params = params;
1456f7bf931SDaniel Verkamp }
1466f7bf931SDaniel Verkamp 
1476f7bf931SDaniel Verkamp void
148134590a2SSeth Howell jsonrpc_server_handle_error(struct spdk_jsonrpc_request *request, int error)
1496f7bf931SDaniel Verkamp {
1502bdec64fSDaniel Verkamp 	ut_handle(request, error, NULL, NULL);
1516f7bf931SDaniel Verkamp }
1526f7bf931SDaniel Verkamp 
1536f7bf931SDaniel Verkamp void
154134590a2SSeth Howell jsonrpc_server_handle_request(struct spdk_jsonrpc_request *request,
1552bdec64fSDaniel Verkamp 			      const struct spdk_json_val *method, const struct spdk_json_val *params)
1566f7bf931SDaniel Verkamp {
1572bdec64fSDaniel Verkamp 	ut_handle(request, 0, method, params);
1586f7bf931SDaniel Verkamp }
1596f7bf931SDaniel Verkamp 
1604e003b67SDaniel Verkamp void
161134590a2SSeth Howell jsonrpc_server_send_response(struct spdk_jsonrpc_request *request)
1626f7bf931SDaniel Verkamp {
1636f7bf931SDaniel Verkamp }
1646f7bf931SDaniel Verkamp 
1656f7bf931SDaniel Verkamp static void
1666f7bf931SDaniel Verkamp test_parse_request(void)
1676f7bf931SDaniel Verkamp {
1686f7bf931SDaniel Verkamp 	struct spdk_jsonrpc_server *server;
1696f7bf931SDaniel Verkamp 	struct spdk_jsonrpc_server_conn *conn;
1706f7bf931SDaniel Verkamp 
1716f7bf931SDaniel Verkamp 	server = calloc(1, sizeof(*server));
1726f7bf931SDaniel Verkamp 	SPDK_CU_ASSERT_FATAL(server != NULL);
1736f7bf931SDaniel Verkamp 
1746f7bf931SDaniel Verkamp 	conn = calloc(1, sizeof(*conn));
1756f7bf931SDaniel Verkamp 	SPDK_CU_ASSERT_FATAL(conn != NULL);
1762fb672afSKrzysztof Karas 	pthread_spin_init(&conn->queue_lock, PTHREAD_PROCESS_PRIVATE);
1772fb672afSKrzysztof Karas 	STAILQ_INIT(&conn->outstanding_queue);
1786f7bf931SDaniel Verkamp 
1796f7bf931SDaniel Verkamp 	conn->server = server;
1806f7bf931SDaniel Verkamp 
18163978010SPawel Wodkowski 	/* rpc call with no parameters. */
18263978010SPawel Wodkowski 	PARSE_PASS("{   }", "");
18363978010SPawel Wodkowski 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
18463978010SPawel Wodkowski 	FREE_REQUEST();
18563978010SPawel Wodkowski 
18663978010SPawel Wodkowski 	/* rpc call with method that is not a string. */
18763978010SPawel Wodkowski 	PARSE_PASS("{\"jsonrpc\":\"2.0\", \"method\": null  }", "");
18863978010SPawel Wodkowski 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
18963978010SPawel Wodkowski 	FREE_REQUEST();
19063978010SPawel Wodkowski 
19163978010SPawel Wodkowski 	/* rpc call with invalid JSON RPC version. */
19263978010SPawel Wodkowski 	PARSE_PASS("{\"jsonrpc\":\"42\", \"method\": \"subtract\"}", "");
19363978010SPawel Wodkowski 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
19463978010SPawel Wodkowski 	FREE_REQUEST();
19563978010SPawel Wodkowski 
19663978010SPawel Wodkowski 	/* rpc call with embedded zeros. */
19763978010SPawel Wodkowski 	PARSE_FAIL("{\"jsonrpc\":\"2.0\",\"method\":\"foo\",\"params\":{\"bar\": \"\0\0baz\"}}");
19863978010SPawel Wodkowski 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
19963978010SPawel Wodkowski 	FREE_REQUEST();
20063978010SPawel Wodkowski 
2016f7bf931SDaniel Verkamp 	/* rpc call with positional parameters */
2026f7bf931SDaniel Verkamp 	PARSE_PASS("{\"jsonrpc\":\"2.0\",\"method\":\"subtract\",\"params\":[42,23],\"id\":1}", "");
2036f7bf931SDaniel Verkamp 	REQ_BEGIN_VALID();
2046f7bf931SDaniel Verkamp 	REQ_METHOD("subtract");
2056f7bf931SDaniel Verkamp 	REQ_ID_NUM("1");
2066f7bf931SDaniel Verkamp 	REQ_PARAMS_BEGIN();
2076f7bf931SDaniel Verkamp 	PARAM_ARRAY_BEGIN();
2086f7bf931SDaniel Verkamp 	PARAM_NUM("42");
2096f7bf931SDaniel Verkamp 	PARAM_NUM("23");
2106f7bf931SDaniel Verkamp 	PARAM_ARRAY_END();
211977fd230SDaniel Verkamp 	FREE_REQUEST();
2126f7bf931SDaniel Verkamp 
2136f7bf931SDaniel Verkamp 	/* rpc call with named parameters */
2146f7bf931SDaniel Verkamp 	PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": {\"subtrahend\": 23, \"minuend\": 42}, \"id\": 3}",
2156f7bf931SDaniel Verkamp 		   "");
2166f7bf931SDaniel Verkamp 	REQ_BEGIN_VALID();
2176f7bf931SDaniel Verkamp 	REQ_METHOD("subtract");
2186f7bf931SDaniel Verkamp 	REQ_ID_NUM("3");
2196f7bf931SDaniel Verkamp 	REQ_PARAMS_BEGIN();
2206f7bf931SDaniel Verkamp 	PARAM_OBJECT_BEGIN();
2216f7bf931SDaniel Verkamp 	PARAM_NAME("subtrahend");
2226f7bf931SDaniel Verkamp 	PARAM_NUM("23");
2236f7bf931SDaniel Verkamp 	PARAM_NAME("minuend");
2246f7bf931SDaniel Verkamp 	PARAM_NUM("42");
2256f7bf931SDaniel Verkamp 	PARAM_OBJECT_END();
226977fd230SDaniel Verkamp 	FREE_REQUEST();
2276f7bf931SDaniel Verkamp 
2286f7bf931SDaniel Verkamp 	/* notification */
2296f7bf931SDaniel Verkamp 	PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"update\", \"params\": [1,2,3,4,5]}", "");
2306f7bf931SDaniel Verkamp 	REQ_BEGIN_VALID();
2316f7bf931SDaniel Verkamp 	REQ_METHOD("update");
2326f7bf931SDaniel Verkamp 	REQ_ID_MISSING();
2336f7bf931SDaniel Verkamp 	REQ_PARAMS_BEGIN();
2346f7bf931SDaniel Verkamp 	PARAM_ARRAY_BEGIN();
2356f7bf931SDaniel Verkamp 	PARAM_NUM("1");
2366f7bf931SDaniel Verkamp 	PARAM_NUM("2");
2376f7bf931SDaniel Verkamp 	PARAM_NUM("3");
2386f7bf931SDaniel Verkamp 	PARAM_NUM("4");
2396f7bf931SDaniel Verkamp 	PARAM_NUM("5");
2406f7bf931SDaniel Verkamp 	PARAM_ARRAY_END();
241977fd230SDaniel Verkamp 	FREE_REQUEST();
2426f7bf931SDaniel Verkamp 
24363978010SPawel Wodkowski 	/* notification with explicit NULL ID. This is discouraged by JSON RPC spec but allowed. */
24463978010SPawel Wodkowski 	PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": \"update\", \"params\": [1,2,3,4,5], \"id\": null}",
24563978010SPawel Wodkowski 		   "");
24663978010SPawel Wodkowski 	REQ_BEGIN_VALID();
24763978010SPawel Wodkowski 	REQ_METHOD("update");
24863978010SPawel Wodkowski 	REQ_ID_NULL();
24963978010SPawel Wodkowski 	REQ_PARAMS_BEGIN();
25063978010SPawel Wodkowski 	PARAM_ARRAY_BEGIN();
25163978010SPawel Wodkowski 	PARAM_NUM("1");
25263978010SPawel Wodkowski 	PARAM_NUM("2");
25363978010SPawel Wodkowski 	PARAM_NUM("3");
25463978010SPawel Wodkowski 	PARAM_NUM("4");
25563978010SPawel Wodkowski 	PARAM_NUM("5");
25663978010SPawel Wodkowski 	PARAM_ARRAY_END();
25763978010SPawel Wodkowski 	FREE_REQUEST();
25863978010SPawel Wodkowski 
2596f7bf931SDaniel Verkamp 	/* invalid JSON */
2606f7bf931SDaniel Verkamp 	PARSE_FAIL("{\"jsonrpc\": \"2.0\", \"method\": \"foobar, \"params\": \"bar\", \"baz]");
2616f7bf931SDaniel Verkamp 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
262977fd230SDaniel Verkamp 	FREE_REQUEST();
2636f7bf931SDaniel Verkamp 
2646f7bf931SDaniel Verkamp 	/* invalid request (method must be a string; params must be array or object) */
2656f7bf931SDaniel Verkamp 	PARSE_PASS("{\"jsonrpc\": \"2.0\", \"method\": 1, \"params\": \"bar\"}", "");
2666f7bf931SDaniel Verkamp 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
267977fd230SDaniel Verkamp 	FREE_REQUEST();
2686f7bf931SDaniel Verkamp 
2696f7bf931SDaniel Verkamp 	/* batch, invalid JSON */
2706f7bf931SDaniel Verkamp 	PARSE_FAIL(
2716f7bf931SDaniel Verkamp 		"["
2726f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"},"
2736f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\""
2746f7bf931SDaniel Verkamp 		"]");
2756f7bf931SDaniel Verkamp 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_PARSE_ERROR);
276977fd230SDaniel Verkamp 	FREE_REQUEST();
2776f7bf931SDaniel Verkamp 
2786f7bf931SDaniel Verkamp 	/* empty array */
2796f7bf931SDaniel Verkamp 	PARSE_PASS("[]", "");
2806f7bf931SDaniel Verkamp 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
281977fd230SDaniel Verkamp 	FREE_REQUEST();
2826f7bf931SDaniel Verkamp 
28335d46267SDaniel Verkamp 	/* batch - not supported */
2846f7bf931SDaniel Verkamp 	PARSE_PASS(
2856f7bf931SDaniel Verkamp 		"["
2866f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [1,2,4], \"id\": \"1\"},"
2876f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"notify_hello\", \"params\": [7]},"
2886f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42,23], \"id\": \"2\"},"
2896f7bf931SDaniel Verkamp 		"{\"foo\": \"boo\"},"
2906f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"foo.get\", \"params\": {\"name\": \"myself\"}, \"id\": \"5\"},"
2916f7bf931SDaniel Verkamp 		"{\"jsonrpc\": \"2.0\", \"method\": \"get_data\", \"id\": \"9\"}"
2926f7bf931SDaniel Verkamp 		"]", "");
2936f7bf931SDaniel Verkamp 
2946f7bf931SDaniel Verkamp 	REQ_BEGIN_INVALID(SPDK_JSONRPC_ERROR_INVALID_REQUEST);
295977fd230SDaniel Verkamp 	FREE_REQUEST();
2966f7bf931SDaniel Verkamp 
29763978010SPawel Wodkowski 	CU_ASSERT(conn->outstanding_requests == 0);
2986f7bf931SDaniel Verkamp 	free(conn);
2996f7bf931SDaniel Verkamp 	free(server);
3006f7bf931SDaniel Verkamp }
3016f7bf931SDaniel Verkamp 
3026f7bf931SDaniel Verkamp static void
3036f7bf931SDaniel Verkamp test_parse_request_streaming(void)
3046f7bf931SDaniel Verkamp {
3056f7bf931SDaniel Verkamp 	struct spdk_jsonrpc_server *server;
3066f7bf931SDaniel Verkamp 	struct spdk_jsonrpc_server_conn *conn;
30763978010SPawel Wodkowski 	const char *json_req;
3086f7bf931SDaniel Verkamp 	size_t len, i;
3096f7bf931SDaniel Verkamp 
3106f7bf931SDaniel Verkamp 	server = calloc(1, sizeof(*server));
3116f7bf931SDaniel Verkamp 	SPDK_CU_ASSERT_FATAL(server != NULL);
3126f7bf931SDaniel Verkamp 
3136f7bf931SDaniel Verkamp 	conn = calloc(1, sizeof(*conn));
3146f7bf931SDaniel Verkamp 	SPDK_CU_ASSERT_FATAL(conn != NULL);
3152fb672afSKrzysztof Karas 	pthread_spin_init(&conn->queue_lock, PTHREAD_PROCESS_PRIVATE);
3162fb672afSKrzysztof Karas 	STAILQ_INIT(&conn->outstanding_queue);
3176f7bf931SDaniel Verkamp 
3186f7bf931SDaniel Verkamp 	conn->server = server;
3196f7bf931SDaniel Verkamp 
32063978010SPawel Wodkowski 
3216f7bf931SDaniel Verkamp 	/*
3226f7bf931SDaniel Verkamp 	 * Two valid requests end to end in the same buffer.
3236f7bf931SDaniel Verkamp 	 * Parse should return the first one and point to the beginning of the second one.
3246f7bf931SDaniel Verkamp 	 */
3256f7bf931SDaniel Verkamp 	PARSE_PASS(
3266f7bf931SDaniel Verkamp 		"{\"jsonrpc\":\"2.0\",\"method\":\"a\",\"params\":[1],\"id\":1}"
3276f7bf931SDaniel Verkamp 		"{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}",
3286f7bf931SDaniel Verkamp 		"{\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}");
32963978010SPawel Wodkowski 
3306f7bf931SDaniel Verkamp 	REQ_BEGIN_VALID();
3316f7bf931SDaniel Verkamp 	REQ_METHOD("a");
3326f7bf931SDaniel Verkamp 	REQ_ID_NUM("1");
3336f7bf931SDaniel Verkamp 	REQ_PARAMS_BEGIN();
3346f7bf931SDaniel Verkamp 	PARAM_ARRAY_BEGIN();
3356f7bf931SDaniel Verkamp 	PARAM_NUM("1");
3366f7bf931SDaniel Verkamp 	PARAM_ARRAY_END();
337977fd230SDaniel Verkamp 	FREE_REQUEST();
3386f7bf931SDaniel Verkamp 
3396f7bf931SDaniel Verkamp 	/* Partial (but not invalid) requests - parse should not consume anything. */
34063978010SPawel Wodkowski 	json_req = "    {\"jsonrpc\":\"2.0\",\"method\":\"b\",\"params\":[2],\"id\":2}";
34163978010SPawel Wodkowski 	len = strlen(json_req);
3426f7bf931SDaniel Verkamp 
3436f7bf931SDaniel Verkamp 	/* Try every partial length up to the full request length */
3446f7bf931SDaniel Verkamp 	for (i = 0; i < len; i++) {
345134590a2SSeth Howell 		int rc = jsonrpc_parse_request(conn, json_req, i);
3466f7bf931SDaniel Verkamp 		/* Partial request - no data consumed */
3476f7bf931SDaniel Verkamp 		CU_ASSERT(rc == 0);
34863978010SPawel Wodkowski 		CU_ASSERT(g_request == NULL);
34963978010SPawel Wodkowski 
350c9c7c281SJosh Soref 		/* In case of failed, don't fload console with useless CU assert fails. */
351977fd230SDaniel Verkamp 		FREE_REQUEST();
3526f7bf931SDaniel Verkamp 	}
3536f7bf931SDaniel Verkamp 
3546f7bf931SDaniel Verkamp 	/* Verify that full request can be parsed successfully */
355134590a2SSeth Howell 	CU_ASSERT(jsonrpc_parse_request(conn, json_req, len) == (ssize_t)len);
356977fd230SDaniel Verkamp 	FREE_REQUEST();
3576f7bf931SDaniel Verkamp 
35863978010SPawel Wodkowski 	CU_ASSERT(conn->outstanding_requests == 0);
3596f7bf931SDaniel Verkamp 	free(conn);
3606f7bf931SDaniel Verkamp 	free(server);
3616f7bf931SDaniel Verkamp }
3626f7bf931SDaniel Verkamp 
3638dd1cd21SBen Walker int
3648dd1cd21SBen Walker main(int argc, char **argv)
3656f7bf931SDaniel Verkamp {
3666f7bf931SDaniel Verkamp 	CU_pSuite	suite = NULL;
3676f7bf931SDaniel Verkamp 	unsigned int	num_failures;
3686f7bf931SDaniel Verkamp 
36978b696bcSVitaliy Mysak 	CU_initialize_registry();
3706f7bf931SDaniel Verkamp 
3716f7bf931SDaniel Verkamp 	suite = CU_add_suite("jsonrpc", NULL, NULL);
3726f7bf931SDaniel Verkamp 
373dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, test_parse_request);
374dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, test_parse_request_streaming);
3756f7bf931SDaniel Verkamp 
376ea941caeSKonrad Sztyber 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
3776f7bf931SDaniel Verkamp 
3786f7bf931SDaniel Verkamp 	CU_cleanup_registry();
3796f7bf931SDaniel Verkamp 
380c9c7c281SJosh Soref 	/* This is for ASAN. Don't know why but if pointer is left in global variable
38163978010SPawel Wodkowski 	 * it won't be detected as leak. */
38263978010SPawel Wodkowski 	g_request = NULL;
3836f7bf931SDaniel Verkamp 	return num_failures;
3846f7bf931SDaniel Verkamp }
385