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