1 /*
2 * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "test_runner_client.h"
8 #include <protocols/rpc/common/packed-c/status.h>
9 #include <protocols/service/test_runner/packed-c/opcodes.h>
10 #include <protocols/service/test_runner/packed-c/status.h>
11 #include <protocols/service/test_runner/packed-c/run_tests.h>
12 #include <protocols/service/test_runner/packed-c/list_tests.h>
13 #include <rpc_caller.h>
14 #include <common/tlv/tlv.h>
15 #include <cstddef>
16 #include <cstring>
17 #include <string>
18
test_runner_client()19 test_runner_client::test_runner_client() :
20 m_client()
21 {
22 service_client_init(&m_client, NULL);
23 }
24
test_runner_client(struct rpc_caller_session * session)25 test_runner_client::test_runner_client(struct rpc_caller_session *session) :
26 m_client()
27 {
28 service_client_init(&m_client, session);
29 }
30
~test_runner_client()31 test_runner_client::~test_runner_client()
32 {
33 service_client_deinit(&m_client);
34 }
35
set_caller(struct rpc_caller_session * session)36 void test_runner_client::set_caller(struct rpc_caller_session *session)
37 {
38 m_client.session = session;
39 }
40
err_rpc_status() const41 int test_runner_client::err_rpc_status() const
42 {
43 return m_client.rpc_status;
44 }
45
run_tests(const struct test_spec & spec,struct test_summary & summary,std::vector<struct test_result> & results)46 int test_runner_client::run_tests(
47 const struct test_spec &spec,
48 struct test_summary &summary,
49 std::vector<struct test_result> &results)
50 {
51 return iterate_over_tests(spec, false, summary, results);
52 }
53
list_tests(const struct test_spec & spec,struct test_summary & summary,std::vector<struct test_result> & results)54 int test_runner_client::list_tests(
55 const struct test_spec &spec,
56 struct test_summary &summary,
57 std::vector<struct test_result> &results)
58 {
59 return iterate_over_tests(spec, true, summary, results);
60 }
61
iterate_over_tests(const struct test_spec & spec,bool list_only,struct test_summary & summary,std::vector<struct test_result> & results)62 int test_runner_client::iterate_over_tests(
63 const struct test_spec &spec, bool list_only,
64 struct test_summary &summary,
65 std::vector<struct test_result> &results)
66 {
67 int test_status = TS_TEST_RUNNER_STATUS_ERROR;
68 m_client.rpc_status = RPC_ERROR_RESOURCE_FAILURE;
69 rpc_call_handle call_handle;
70 uint8_t *req_buf;
71 std::vector<uint8_t> req_param;
72
73 serialize_test_spec(req_param, spec);
74
75 size_t req_len = req_param.size();
76 size_t resp_len = 1024;
77 call_handle = rpc_caller_session_begin(m_client.session, &req_buf, req_len, resp_len);
78
79 if (call_handle) {
80
81 uint8_t *resp_buf;
82 size_t resp_len;
83 service_status_t service_status;
84
85 memcpy(req_buf, req_param.data(), req_len);
86
87 uint32_t opcode = (list_only) ?
88 TS_TEST_RUNNER_OPCODE_LIST_TESTS :
89 TS_TEST_RUNNER_OPCODE_RUN_TESTS;
90
91 m_client.rpc_status = rpc_caller_session_invoke(call_handle,
92 opcode, &resp_buf, &resp_len, &service_status);
93
94 if (m_client.rpc_status == TS_RPC_CALL_ACCEPTED) {
95
96 test_status = service_status;
97
98 if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
99
100 test_status = deserialize_results(resp_buf, resp_len, summary, results);
101 }
102 }
103
104 rpc_caller_session_end(call_handle);
105 }
106
107 return test_status;
108 }
109
serialize_test_spec(std::vector<uint8_t> & serialized_data,const struct test_spec & spec) const110 void test_runner_client::serialize_test_spec(
111 std::vector<uint8_t> &serialized_data,
112 const struct test_spec &spec) const
113 {
114 size_t name_len = strlen(spec.name);
115 size_t group_len = strlen(spec.group);
116 size_t tlv_space = 0;
117
118 /* First determine buffer space needed for TLV parameters */
119 if (name_len) tlv_space += tlv_required_space(name_len);
120 if (group_len) tlv_space += tlv_required_space(group_len);
121
122 /* Extend the params vector and write the tlv records */
123 if (tlv_space) {
124
125 serialized_data.resize(tlv_space);
126 struct tlv_iterator iter;
127 uint8_t *buf = serialized_data.data();
128
129 tlv_iterator_begin(&iter, buf, tlv_space);
130
131 if (name_len) {
132
133 struct tlv_record record;
134 record.tag = TS_TEST_RUNNER_TEST_SPEC_TAG_NAME;
135 record.length = name_len;
136 record.value = (const uint8_t*)spec.name;
137 tlv_encode(&iter, &record);
138 }
139
140 if (group_len) {
141
142 struct tlv_record record;
143 record.tag = TS_TEST_RUNNER_TEST_SPEC_TAG_GROUP;
144 record.length = group_len;
145 record.value = (const uint8_t*)spec.group;
146 tlv_encode(&iter, &record);
147 }
148 }
149 }
150
deserialize_results(const uint8_t * resp_buf,size_t resp_len,struct test_summary & summary,std::vector<struct test_result> & results) const151 int test_runner_client::deserialize_results(
152 const uint8_t *resp_buf, size_t resp_len,
153 struct test_summary &summary,
154 std::vector<struct test_result> &results) const
155 {
156 int test_status = TS_TEST_RUNNER_STATUS_SUCCESS;
157 size_t fixed_size = sizeof(ts_test_runner_result_summary);
158
159 if (resp_len >= fixed_size) {
160
161 /* Deserialize fixed size summary structure */
162 struct ts_test_runner_result_summary packed_summary;
163 memcpy(&packed_summary, resp_buf, fixed_size);
164
165 summary.num_tests = packed_summary.num_tests;
166 summary.num_passed = packed_summary.num_passed;
167 summary.num_failed = packed_summary.num_failed;
168 summary.num_results = 0;
169
170 /* Deserialize any test result records */
171 struct tlv_const_iterator tlv_iter;
172 struct tlv_record result_record;
173 tlv_const_iterator_begin(&tlv_iter, &resp_buf[fixed_size], resp_len - fixed_size);
174
175 while (tlv_find_decode(&tlv_iter, TS_TEST_RUNNER_TEST_RESULT_TAG, &result_record)) {
176
177 struct test_result result;
178
179 test_status = deserialize_result(result_record.value, result_record.length, result);
180
181 if (test_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
182
183 results.push_back(result);
184 ++summary.num_results;
185 }
186 else {
187 /* Failed to decode result record */
188 break;
189 }
190 }
191 }
192 else {
193 /* Failed to mandatory test summary */
194 test_status = TS_TEST_RUNNER_STATUS_INVALID_TEST_RESULTS;
195 }
196
197 return test_status;
198 }
199
deserialize_result(const uint8_t * value_buf,size_t value_len,struct test_result & result) const200 int test_runner_client::deserialize_result(
201 const uint8_t *value_buf, size_t value_len,
202 struct test_result &result) const
203 {
204 int test_status = TS_TEST_RUNNER_STATUS_SUCCESS;
205 size_t fixed_size = sizeof(ts_test_runner_test_result);
206
207 if (value_len >= fixed_size) {
208
209 struct ts_test_runner_test_result packed_result;
210 memcpy(&packed_result, value_buf, fixed_size);
211
212 memset(&result, 0, sizeof(result));
213 result.run_state = (enum test_run_state)packed_result.run_state;
214
215 /* Deserialize name and group if present */
216 struct tlv_const_iterator req_iter;
217 struct tlv_record decoded_record;
218
219 tlv_const_iterator_begin(&req_iter, &value_buf[fixed_size], value_len - fixed_size);
220
221 if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_RESULT_TAG_NAME, &decoded_record)) {
222
223 if ((decoded_record.length > 0) && (decoded_record.length < TEST_NAME_MAX_LEN)) {
224
225 memcpy(result.name, decoded_record.value, decoded_record.length);
226 result.name[decoded_record.length] = 0;
227 }
228 }
229
230 if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_RESULT_TAG_GROUP, &decoded_record)) {
231
232 if ((decoded_record.length > 0) && (decoded_record.length < TEST_GROUP_MAX_LEN)) {
233
234 memcpy(result.group, decoded_record.value, decoded_record.length);
235 result.group[decoded_record.length] = 0;
236 }
237 }
238
239 if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE, &decoded_record)) {
240
241 if (decoded_record.length == sizeof(ts_test_runner_test_failure)) {
242
243 struct ts_test_runner_test_failure deserialized_failure;
244 memcpy(&deserialized_failure, decoded_record.value, decoded_record.length);
245 result.failure.line_num = deserialized_failure.line_num;
246 result.failure.info = deserialized_failure.info;
247 }
248 }
249 }
250 else {
251 /* Invalid test result */
252 test_status = TS_TEST_RUNNER_STATUS_INVALID_TEST_RESULTS;
253 }
254
255 return test_status;
256 }
257