Add test for ffarpc RPC caller implementation

Cover the RPC caller implementation of ffarpc with unit tests and
harden error handling code.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I5ec0eb355de314e105278acb4b2ec38578b176ae
diff --git a/components/rpc/ffarpc/caller/sp/ffarpc_caller.c b/components/rpc/ffarpc/caller/sp/ffarpc_caller.c
index 17e80a6..78c769e 100644
--- a/components/rpc/ffarpc/caller/sp/ffarpc_caller.c
+++ b/components/rpc/ffarpc/caller/sp/ffarpc_caller.c
@@ -39,6 +39,11 @@
 		goto out;
 	}
 
+	if (this_context->dest_partition_id == 0) {
+		EMSG("the caller is not open");
+		goto out;
+	}
+
 	this_context->is_call_transaction_in_progess = true;
 	handle = this_context;
 
@@ -60,8 +65,8 @@
 	struct sp_msg resp = { 0 };
 	rpc_status_t status = TS_RPC_ERROR_INTERNAL;
 
-	if (handle != this_context || opstatus == NULL ||
-		resp_buf == NULL || resp_len == NULL) {
+	if (context == NULL || handle != this_context || opstatus == NULL ||
+	    resp_buf == NULL || resp_len == NULL) {
 		EMSG("invalid arguments");
 		status = TS_RPC_ERROR_INVALID_PARAMETER;
 		goto out;
@@ -99,14 +104,14 @@
 	}
 
 	this_context->resp_len = (size_t)resp.args.args32[SP_CALL_ARGS_RESP_DATA_LEN];
-	status = resp.args.args32[SP_CALL_ARGS_RESP_RPC_STATUS];
-	*opstatus = (rpc_status_t)((int32_t)resp.args.args32[SP_CALL_ARGS_RESP_OP_STATUS]);
-
 	if (this_context->resp_len > this_context->shared_mem_required_size) {
 		EMSG("invalid response length");
 		goto out;
 	}
 
+	status = resp.args.args32[SP_CALL_ARGS_RESP_RPC_STATUS];
+	*opstatus = (rpc_status_t)((int32_t)resp.args.args32[SP_CALL_ARGS_RESP_OP_STATUS]);
+
 	if (this_context->resp_len > 0)
 		this_context->resp_buf = shared_buffer;
 	else
@@ -122,7 +127,7 @@
 {
 	struct ffarpc_caller *this_context = (struct ffarpc_caller *)context;
 
-	if (handle != this_context) {
+	if (context == NULL || handle != this_context) {
 		EMSG("invalid arguments");
 		return;
 	}
diff --git a/components/rpc/ffarpc/caller/sp/test/test_ffarpc_caller.cpp b/components/rpc/ffarpc/caller/sp/test/test_ffarpc_caller.cpp
index b18530b..61d7065 100644
--- a/components/rpc/ffarpc/caller/sp/test/test_ffarpc_caller.cpp
+++ b/components/rpc/ffarpc/caller/sp/test/test_ffarpc_caller.cpp
@@ -321,3 +321,302 @@
 	expect_sp_memory_reclaim(caller.shared_mem_handle, 0, SP_RESULT_OK);
 	LONGS_EQUAL(0, ffarpc_caller_close(&caller));
 }
+
+TEST(ffarpc_caller, begin_null_context)
+{
+	uint8_t *buffer = NULL;
+
+	rpc_caller_instance->context = NULL;
+
+	POINTERS_EQUAL(NULL,  rpc_caller_begin(rpc_caller_instance, &buffer, 0));
+}
+
+TEST(ffarpc_caller, begin_null_buffer)
+{
+	POINTERS_EQUAL(NULL, rpc_caller_begin(rpc_caller_instance, NULL, 0));
+}
+
+TEST(ffarpc_caller, begin_transaction_in_progress)
+{
+	uint8_t *buffer = NULL;
+
+	caller.is_call_transaction_in_progess = true;
+	POINTERS_EQUAL(NULL, rpc_caller_begin(rpc_caller_instance, &buffer, 0));
+}
+
+TEST(ffarpc_caller, begin_too_large_req)
+{
+	uint8_t *buffer = NULL;
+
+	POINTERS_EQUAL(NULL, rpc_caller_begin(rpc_caller_instance, &buffer,
+					      sizeof(shared_buffer) + 1));
+}
+
+TEST(ffarpc_caller, begin_not_opened)
+{
+	uint8_t *buffer = NULL;
+
+	rpc_call_handle handle = rpc_caller_begin(rpc_caller_instance, &buffer,
+						  0);
+	POINTERS_EQUAL(NULL, handle);
+}
+
+TEST(ffarpc_caller, begin_with_buffer)
+{
+	uint8_t *buffer = NULL;
+
+	caller.dest_partition_id = 1;
+	rpc_call_handle handle = rpc_caller_begin(rpc_caller_instance, &buffer,
+						  sizeof(shared_buffer));
+	CHECK_TRUE(handle != NULL);
+	POINTERS_EQUAL(shared_buffer, buffer);
+}
+
+TEST(ffarpc_caller, begin_without_buffer)
+{
+	uint8_t *buffer = NULL;
+
+	caller.dest_partition_id = 1;
+	rpc_call_handle handle = rpc_caller_begin(rpc_caller_instance, &buffer,
+						  0);
+	CHECK_TRUE(handle != NULL);
+	POINTERS_EQUAL(NULL, buffer);
+}
+
+TEST(ffarpc_caller, invoke_null_context)
+{
+	rpc_call_handle handle = &caller;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	rpc_caller_instance->context = NULL;
+	LONGS_EQUAL(TS_RPC_ERROR_INVALID_PARAMETER,
+		    rpc_caller_invoke(rpc_caller_instance, NULL, 0, &opstatus,
+				      &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_handle_context_diff)
+{
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	LONGS_EQUAL(TS_RPC_ERROR_INVALID_PARAMETER,
+		    rpc_caller_invoke(rpc_caller_instance, NULL, 0, &opstatus,
+				      &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_opstatus_null)
+{
+	rpc_call_handle handle = &caller;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	LONGS_EQUAL(TS_RPC_ERROR_INVALID_PARAMETER,
+		    rpc_caller_invoke(rpc_caller_instance, handle, 0, NULL,
+				      &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_resp_buf_null)
+{
+	rpc_call_handle handle = &caller;
+	rpc_opstatus_t opstatus = 0;
+	size_t resp_len = 0;
+
+	LONGS_EQUAL(TS_RPC_ERROR_INVALID_PARAMETER,
+		    rpc_caller_invoke(rpc_caller_instance, handle, 0,
+				      &opstatus, NULL, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_resp_len_null)
+{
+	rpc_call_handle handle = &caller;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+
+	LONGS_EQUAL(TS_RPC_ERROR_INVALID_PARAMETER,
+		    rpc_caller_invoke(rpc_caller_instance, handle, 0,
+				      &opstatus, &resp_buf, NULL));
+}
+
+TEST(ffarpc_caller, invoke_resp_no_begin)
+{
+	rpc_call_handle handle = &caller;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	LONGS_EQUAL(TS_RPC_ERROR_NOT_READY,
+		    rpc_caller_invoke(rpc_caller_instance, handle, 0,
+				      &opstatus, &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_resp_long_req)
+{
+	rpc_call_handle handle = &caller;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	caller.is_call_transaction_in_progess = true;
+	caller.req_len = (size_t)UINT32_MAX + 1;
+	LONGS_EQUAL(TS_RPC_ERROR_INTERNAL,
+		    rpc_caller_invoke(rpc_caller_instance, handle, 0,
+				      &opstatus, &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_send_direct_req_fail)
+{
+	rpc_call_handle handle = &caller;
+	uint16_t opcode = 0xfedc;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	caller.is_call_transaction_in_progess = true;
+	caller.shared_mem_handle = 0x56789abcdef01234ULL;
+	caller.dest_partition_id = 0x1234;
+	caller.req_len = 0x3456789a;
+	caller.rpc_caller.encoding = 0xabcdef12;
+
+	req.source_id = own_id;
+	req.destination_id = caller.dest_partition_id;
+	req.args.args32[0] = opcode;
+	req.args.args32[1] = caller.req_len;
+	req.args.args32[2] = 0;
+	req.args.args32[3] = caller.rpc_caller.encoding;
+
+	expect_sp_msg_send_direct_req(&req, &resp, SP_RESULT_INTERNAL_ERROR);
+	LONGS_EQUAL(TS_RPC_ERROR_INTERNAL,
+		    rpc_caller_invoke(rpc_caller_instance, handle, opcode,
+				      &opstatus, &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_invalid_resp_len)
+{
+	rpc_call_handle handle = &caller;
+	uint16_t opcode = 0xfedc;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	caller.is_call_transaction_in_progess = true;
+	caller.shared_mem_handle = 0x56789abcdef01234ULL;
+	caller.dest_partition_id = 0x1234;
+	caller.req_len = 0x3456789a;
+	caller.rpc_caller.encoding = 0xabcdef12;
+
+	req.source_id = own_id;
+	req.destination_id = caller.dest_partition_id;
+	req.args.args32[0] = opcode;
+	req.args.args32[1] = caller.req_len;
+	req.args.args32[2] = 0;
+	req.args.args32[3] = caller.rpc_caller.encoding;
+
+	resp.source_id = caller.dest_partition_id;
+	resp.destination_id = own_id;
+	resp.args.args32[0] = opcode;
+	resp.args.args32[1] = sizeof(shared_buffer) + 1;
+	resp.args.args32[2] = TS_RPC_CALL_ACCEPTED;
+	resp.args.args32[3] = 0;
+
+	expect_sp_msg_send_direct_req(&req, &resp, SP_RESULT_OK);
+	LONGS_EQUAL(TS_RPC_ERROR_INTERNAL,
+		    rpc_caller_invoke(rpc_caller_instance, handle, opcode,
+				      &opstatus, &resp_buf, &resp_len));
+}
+
+TEST(ffarpc_caller, invoke_with_response)
+{
+	rpc_call_handle handle = &caller;
+	uint16_t opcode = 0xfedc;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = NULL;
+	size_t resp_len = 0;
+
+	caller.is_call_transaction_in_progess = true;
+	caller.shared_mem_handle = 0x56789abcdef01234ULL;
+	caller.dest_partition_id = 0x1234;
+	caller.req_len = 0x3456789a;
+	caller.rpc_caller.encoding = 0xabcdef12;
+
+	req.source_id = own_id;
+	req.destination_id = caller.dest_partition_id;
+	req.args.args32[0] = opcode;
+	req.args.args32[1] = caller.req_len;
+	req.args.args32[2] = 0;
+	req.args.args32[3] = caller.rpc_caller.encoding;
+
+	resp.source_id = caller.dest_partition_id;
+	resp.destination_id = own_id;
+	resp.args.args32[0] = opcode;
+	resp.args.args32[1] = sizeof(shared_buffer);
+	resp.args.args32[2] = TS_RPC_CALL_ACCEPTED;
+	resp.args.args32[3] = 0;
+
+	expect_sp_msg_send_direct_req(&req, &resp, SP_RESULT_OK);
+	LONGS_EQUAL(TS_RPC_CALL_ACCEPTED,
+		    rpc_caller_invoke(rpc_caller_instance, handle, opcode,
+				      &opstatus, &resp_buf, &resp_len));
+	POINTERS_EQUAL(shared_buffer, resp_buf);
+	UNSIGNED_LONGS_EQUAL(sizeof(shared_buffer), resp_len);
+}
+
+TEST(ffarpc_caller, invoke_without_response)
+{
+	rpc_call_handle handle = &caller;
+	uint16_t opcode = 0xfedc;
+	rpc_opstatus_t opstatus = 0;
+	uint8_t *resp_buf = (uint8_t *)0x123;
+	size_t resp_len = 1;
+
+	caller.is_call_transaction_in_progess = true;
+	caller.shared_mem_handle = 0x56789abcdef01234ULL;
+	caller.dest_partition_id = 0x1234;
+	caller.req_len = 0x3456789a;
+	caller.rpc_caller.encoding = 0xabcdef12;
+
+	req.source_id = own_id;
+	req.destination_id = caller.dest_partition_id;
+	req.args.args32[0] = opcode;
+	req.args.args32[1] = caller.req_len;
+	req.args.args32[2] = 0;
+	req.args.args32[3] = caller.rpc_caller.encoding;
+
+	resp.source_id = caller.dest_partition_id;
+	resp.destination_id = own_id;
+	resp.args.args32[0] = opcode;
+	resp.args.args32[1] = 0;
+	resp.args.args32[2] = TS_RPC_CALL_ACCEPTED;
+	resp.args.args32[3] = 0;
+
+	expect_sp_msg_send_direct_req(&req, &resp, SP_RESULT_OK);
+	LONGS_EQUAL(TS_RPC_CALL_ACCEPTED,
+		    rpc_caller_invoke(rpc_caller_instance, handle, opcode,
+				      &opstatus, &resp_buf, &resp_len));
+	POINTERS_EQUAL(NULL, resp_buf);
+	UNSIGNED_LONGS_EQUAL(0, resp_len);
+}
+
+TEST(ffarpc_caller, end_null_context)
+{
+	rpc_call_handle handle = &caller;
+
+	caller.rpc_caller.context = NULL;
+	rpc_caller_end(rpc_caller_instance, handle);
+}
+
+TEST(ffarpc_caller, end_null_handle)
+{
+	rpc_caller_end(rpc_caller_instance, NULL);
+}
+
+TEST(ffarpc_caller, end)
+{
+	rpc_call_handle handle = &caller;
+
+	caller.is_call_transaction_in_progess = true;
+	rpc_caller_end(rpc_caller_instance, handle);
+	CHECK_FALSE(caller.is_call_transaction_in_progess);
+}