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