1 /*
2  * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <string>
8 #include <cstring>
9 #include <service/common/provider/service_provider.h>
10 #include <protocols/rpc/common/packed-c/status.h>
11 #include <rpc/direct/direct_caller.h>
12 #include "rpc/common/caller/rpc_caller_session.h"
13 #include <CppUTest/TestHarness.h>
14 
15 
TEST_GROUP(ServiceFrameworkTests)16 TEST_GROUP(ServiceFrameworkTests)
17 {
18 	static rpc_status_t handlerThatSucceeds(void *context, struct rpc_request* req)
19 	{
20 		(void)context;
21 
22 		struct rpc_buffer *respBuf = &req->response;
23 
24 		std::string responseString("Yay!");
25 		respBuf->data_length = responseString.copy((char*)respBuf->data, respBuf->size);
26 
27 		req->service_status = SERVICE_SPECIFIC_SUCCESS_CODE;
28 
29 		return RPC_SUCCESS;
30 	}
31 
32 	static rpc_status_t handlerThatFails(void *context, struct rpc_request* req)
33 	{
34 		(void)context;
35 
36 		struct rpc_buffer *respBuf = &req->response;
37 
38 		std::string responseString("Ehh!");
39 		respBuf->data_length = responseString.copy((char*)respBuf->data, respBuf->size);
40 
41 		req->service_status = SERVICE_SPECIFIC_ERROR_CODE;
42 
43 		return RPC_SUCCESS;
44 	}
45 
46 	void setup()
47 	{
48 		memset(&m_direct_caller, 0, sizeof(m_direct_caller));
49 		memset(&m_session, 0, sizeof(m_session));
50 	}
51 
52 	void teardown()
53 	{
54 		rpc_caller_session_close(&m_session);
55 		direct_caller_deinit(&m_direct_caller);
56 	}
57 
58 	static const uint32_t SOME_ARBITRARY_OPCODE = 666;
59 	static const uint32_t ANOTHER_ARBITRARY_OPCODE = 901;
60 	static const uint32_t YET_ANOTHER_ARBITRARY_OPCODE = 7;
61 	static const int SERVICE_SPECIFIC_ERROR_CODE = 101;
62 	static const int SERVICE_SPECIFIC_SUCCESS_CODE = 100;
63 
64 	struct rpc_caller_interface m_direct_caller;
65 	struct rpc_caller_session m_session;
66 };
67 
TEST(ServiceFrameworkTests,serviceWithNoOps)68 TEST(ServiceFrameworkTests, serviceWithNoOps)
69 {
70 	/* Constructs a service endpoint with no handlers */
71 	struct rpc_uuid service_uuid = { .uuid = {
72 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
73 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
74 	struct service_provider service_provider;
75 	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
76 
77 	service_provider_init(&service_provider, &service_provider, &service_uuid, NULL, 0);
78 	rpc_status = direct_caller_init(&m_direct_caller,
79 					service_provider_get_rpc_interface(&service_provider));
80 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
81 
82 	rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
83 						      4096);
84 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
85 
86 	rpc_call_handle handle;
87 	uint8_t *req_buf;
88 	uint8_t *resp_buf;
89 	size_t req_len = 100;
90 	size_t resp_len;
91 	service_status_t service_status;
92 
93 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
94 	CHECK_TRUE(handle);
95 
96 	rpc_status = rpc_caller_session_invoke(handle, SOME_ARBITRARY_OPCODE, &resp_buf, &resp_len,
97 					       &service_status);
98 
99 	rpc_caller_session_end(handle);
100 
101 	LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
102 }
103 
TEST(ServiceFrameworkTests,serviceWithOps)104 TEST(ServiceFrameworkTests, serviceWithOps)
105 {
106 	/* Constructs a service endpoint with a couple of handlers */
107 	struct rpc_uuid service_uuid = { .uuid = {
108 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
109 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
110 	struct service_handler handlers[2];
111 	handlers[0].opcode = SOME_ARBITRARY_OPCODE;
112 	handlers[0].invoke = handlerThatSucceeds;
113 	handlers[1].opcode = ANOTHER_ARBITRARY_OPCODE;
114 	handlers[1].invoke = handlerThatFails;
115 
116 	struct service_provider service_provider;
117 	rpc_status_t rpc_status;
118 
119 	service_provider_init(&service_provider, &service_provider, &service_uuid, handlers, 2);
120 	rpc_status = direct_caller_init(&m_direct_caller,
121 					service_provider_get_rpc_interface(&service_provider));
122 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
123 
124 	rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
125 						      4096);
126 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
127 
128 	rpc_call_handle handle;
129 	uint8_t *req_buf;
130 	uint8_t *resp_buf;
131 	size_t req_len = 100;
132 	size_t resp_len;
133 	service_status_t service_status;
134 	std::string respString;
135 
136 	/* Expect this call transaction to succeed */
137 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
138 	CHECK_TRUE(handle);
139 
140 	rpc_status = rpc_caller_session_invoke(handle, SOME_ARBITRARY_OPCODE, &resp_buf, &resp_len,
141 					       &service_status);
142 
143 	respString = std::string((const char*)resp_buf, resp_len);
144 
145 	rpc_caller_session_end(handle);
146 
147 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
148 	LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
149 	STRCMP_EQUAL("Yay!", respString.c_str());
150 
151 	/* Expect this call transaction to fail */
152 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
153 	CHECK_TRUE(handle);
154 
155 	rpc_status = rpc_caller_session_invoke(handle, ANOTHER_ARBITRARY_OPCODE, &resp_buf,
156 					       &resp_len, &service_status);
157 
158 	respString = std::string((const char*)resp_buf, resp_len);
159 
160 	rpc_caller_session_end(handle);
161 
162 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
163 	LONGS_EQUAL(SERVICE_SPECIFIC_ERROR_CODE, service_status);
164 	STRCMP_EQUAL("Ehh!", respString.c_str());
165 
166 	/* Try an unsupported opcode */
167 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
168 	CHECK_TRUE(handle);
169 
170 	rpc_status = rpc_caller_session_invoke(handle, YET_ANOTHER_ARBITRARY_OPCODE, &resp_buf, &resp_len,
171 					       &service_status);
172 
173 	rpc_caller_session_end(handle);
174 
175 	LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
176 }
177 
TEST(ServiceFrameworkTests,serviceProviderChain)178 TEST(ServiceFrameworkTests, serviceProviderChain)
179 {
180 	struct rpc_uuid service_uuid = { .uuid = {
181 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
182 		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
183 	rpc_status_t rpc_status;
184 
185 	/* Construct the base service provider */
186 	struct service_handler base_handlers[1];
187 	base_handlers[0].opcode = 100;
188 	base_handlers[0].invoke = handlerThatSucceeds;
189 
190 	struct service_provider base_provider;
191 	service_provider_init(&base_provider, &base_provider, &service_uuid, base_handlers, 1);
192 
193 	/* Construct a sub provider and extend the base */
194 	struct service_handler sub0_handlers[1];
195 	sub0_handlers[0].opcode = 200;
196 	sub0_handlers[0].invoke = handlerThatSucceeds;
197 
198 	struct service_provider sub0_provider;
199 	service_provider_init(&sub0_provider, &sub0_provider, &service_uuid, sub0_handlers, 1);
200 	service_provider_extend(&base_provider, &sub0_provider);
201 
202 	/* Construct another sub provider and extend the base */
203 	struct service_handler sub1_handlers[1];
204 	sub1_handlers[0].opcode = 300;
205 	sub1_handlers[0].invoke = handlerThatSucceeds;
206 
207 	struct service_provider sub1_provider;
208 	service_provider_init(&sub1_provider, &sub1_provider, &service_uuid, sub1_handlers, 1);
209 	service_provider_extend(&base_provider, &sub1_provider);
210 
211 	/* Use a direct_caller to make RPC calls to the base provider at the head of the chain */
212 	rpc_status = direct_caller_init(&m_direct_caller,
213 					service_provider_get_rpc_interface(&base_provider));
214 	LONGS_EQUAL(rpc_status, RPC_SUCCESS);
215 
216 	rpc_status = rpc_caller_session_find_and_open(&m_session, &m_direct_caller, &service_uuid,
217 						      4096);
218 	LONGS_EQUAL(rpc_status, RPC_SUCCESS);
219 
220 	rpc_call_handle handle;
221 	uint8_t *req_buf;
222 	uint8_t *resp_buf;
223 	size_t req_len = 100;
224 	size_t resp_len;
225 	service_status_t service_status;
226 	std::string respString;
227 
228 	/* Expect calls that will be handled by all three chained service providers to succeed */
229 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
230 	CHECK_TRUE(handle);
231 
232 	rpc_status = rpc_caller_session_invoke(handle, 100, &resp_buf, &resp_len, &service_status);
233 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
234 
235 	respString = std::string((const char*)resp_buf, resp_len);
236 
237 	rpc_caller_session_end(handle);
238 
239 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
240 	LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
241 	STRCMP_EQUAL("Yay!", respString.c_str());
242 
243 	/* This one should beb handled by sub0 */
244 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
245 	CHECK_TRUE(handle);
246 
247 	rpc_status = rpc_caller_session_invoke(handle, 200, &resp_buf, &resp_len, &service_status);
248 
249 	respString = std::string((const char*)resp_buf, resp_len);
250 
251 	rpc_caller_session_end(handle);
252 
253 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
254 	LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
255 	STRCMP_EQUAL("Yay!", respString.c_str());
256 
257 	/* This one should beb handled by sub1 */
258 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
259 	CHECK_TRUE(handle);
260 
261 	rpc_status = rpc_caller_session_invoke(handle, 300, &resp_buf, &resp_len, &service_status);
262 
263 	respString = std::string((const char*)resp_buf, resp_len);
264 
265 	rpc_caller_session_end(handle);
266 
267 	LONGS_EQUAL(RPC_SUCCESS, rpc_status);
268 	LONGS_EQUAL(SERVICE_SPECIFIC_SUCCESS_CODE, service_status);
269 	STRCMP_EQUAL("Yay!", respString.c_str());
270 
271 	/* Try an unsupported opcode */
272 	handle = rpc_caller_session_begin(&m_session, &req_buf, req_len, 0);
273 	CHECK_TRUE(handle);
274 
275 	rpc_status = rpc_caller_session_invoke(handle, 400, &resp_buf, &resp_len, &service_status);
276 
277 	rpc_caller_session_end(handle);
278 
279 	LONGS_EQUAL(RPC_ERROR_INVALID_VALUE, rpc_status);
280 }
281