1 /*
2 * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include "packedc_test_runner_provider_serializer.h"
7
8 #include <common/tlv/tlv.h>
9 #include <protocols/rpc/common/packed-c/status.h>
10 #include <protocols/service/test_runner/packed-c/list_tests.h>
11 #include <protocols/service/test_runner/packed-c/run_tests.h>
12 #include <stddef.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 /* Common rerialization methods used for different operations */
deserialize_test_spec(const struct rpc_buffer * req_buf,struct test_spec * test_spec)17 static rpc_status_t deserialize_test_spec(const struct rpc_buffer *req_buf,
18 struct test_spec *test_spec)
19 {
20 struct tlv_const_iterator req_iter;
21 struct tlv_record decoded_record;
22
23 test_spec->name[0] = 0;
24 test_spec->group[0] = 0;
25
26 tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
27
28 if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_NAME, &decoded_record)) {
29 if ((decoded_record.length > 0) && (decoded_record.length < TEST_NAME_MAX_LEN)) {
30 memcpy(test_spec->name, decoded_record.value, decoded_record.length);
31 test_spec->name[decoded_record.length] = 0;
32 }
33 }
34
35 if (tlv_find_decode(&req_iter, TS_TEST_RUNNER_TEST_SPEC_TAG_GROUP, &decoded_record)) {
36 if ((decoded_record.length > 0) && (decoded_record.length < TEST_GROUP_MAX_LEN)) {
37 memcpy(test_spec->group, decoded_record.value, decoded_record.length);
38 test_spec->group[decoded_record.length] = 0;
39 }
40 }
41
42 return TS_RPC_CALL_ACCEPTED;
43 }
44
serialize_test_result(const struct test_result * result,size_t * serialized_len)45 static uint8_t *serialize_test_result(const struct test_result *result, size_t *serialized_len)
46 {
47 uint8_t *out_buf;
48 size_t fixed_len = sizeof(struct ts_test_runner_test_result);
49 size_t required_space = fixed_len;
50 size_t name_len = strlen(result->name);
51 size_t group_len = strlen(result->group);
52
53 if (name_len)
54 required_space += tlv_required_space(name_len);
55 if (group_len)
56 required_space += tlv_required_space(group_len);
57 if (result->run_state == TEST_RUN_STATE_FAILED)
58 required_space += tlv_required_space(sizeof(struct ts_test_runner_test_failure));
59
60 *serialized_len = required_space;
61
62 out_buf = malloc(required_space);
63
64 if (out_buf) {
65 struct ts_test_runner_test_result result_msg;
66 struct tlv_iterator tlv_iter;
67
68 result_msg.run_state = result->run_state;
69
70 memcpy(out_buf, &result_msg, fixed_len);
71
72 tlv_iterator_begin(&tlv_iter, (uint8_t *)out_buf + fixed_len,
73 required_space - fixed_len);
74
75 if (name_len) {
76 struct tlv_record record;
77
78 record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_NAME;
79 record.length = name_len;
80 record.value = (const uint8_t *)result->name;
81 tlv_encode(&tlv_iter, &record);
82 }
83
84 if (group_len) {
85 struct tlv_record record;
86
87 record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_GROUP;
88 record.length = group_len;
89 record.value = (const uint8_t *)result->group;
90 tlv_encode(&tlv_iter, &record);
91 }
92
93 if (result->run_state == TEST_RUN_STATE_FAILED) {
94 struct ts_test_runner_test_failure serialized_failure;
95 struct tlv_record record;
96
97 serialized_failure.line_num = result->failure.line_num;
98 serialized_failure.info = result->failure.info;
99
100 record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG_FAILURE;
101 record.length = sizeof(serialized_failure);
102 record.value = (const uint8_t *)&serialized_failure;
103 tlv_encode(&tlv_iter, &record);
104 }
105 }
106
107 return out_buf;
108 }
109
serialize_test_results(struct rpc_buffer * resp_buf,const struct test_summary * summary,const struct test_result * results)110 static rpc_status_t serialize_test_results(struct rpc_buffer *resp_buf,
111 const struct test_summary *summary,
112 const struct test_result *results)
113 {
114 size_t space_used = 0;
115 rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
116
117 /* Serialize fixed size summary */
118 struct ts_test_runner_result_summary summary_msg;
119 size_t fixed_len = sizeof(struct ts_test_runner_result_summary);
120
121 summary_msg.num_tests = summary->num_tests;
122 summary_msg.num_passed = summary->num_passed;
123 summary_msg.num_failed = summary->num_failed;
124
125 if (fixed_len + space_used <= resp_buf->size) {
126 memcpy((uint8_t *)resp_buf->data + space_used, &summary_msg, fixed_len);
127 space_used += fixed_len;
128
129 /* Serialize test result objects */
130 struct tlv_iterator resp_iter;
131
132 tlv_iterator_begin(&resp_iter, (uint8_t *)resp_buf->data + space_used,
133 resp_buf->size - space_used);
134
135 for (size_t i = 0;
136 (i < summary->num_results) && (rpc_status == TS_RPC_CALL_ACCEPTED); ++i) {
137 size_t serialised_len;
138 uint8_t *serialize_buf =
139 serialize_test_result(&results[i], &serialised_len);
140
141 if (serialize_buf) {
142 struct tlv_record result_record;
143
144 result_record.tag = TS_TEST_RUNNER_TEST_RESULT_TAG;
145 result_record.length = serialised_len;
146 result_record.value = serialize_buf;
147
148 if (tlv_encode(&resp_iter, &result_record)) {
149 space_used += tlv_required_space(serialised_len);
150 } else {
151 /* Insufficient buffer space */
152 rpc_status = RPC_ERROR_RESOURCE_FAILURE;
153 }
154
155 free(serialize_buf);
156 }
157 }
158 }
159
160 resp_buf->data_length = space_used;
161
162 return rpc_status;
163 }
164
165 /* Operation: run_tests */
deserialize_run_tests_req(const struct rpc_buffer * req_buf,struct test_spec * test_spec)166 static rpc_status_t deserialize_run_tests_req(const struct rpc_buffer *req_buf,
167 struct test_spec *test_spec)
168 {
169 return deserialize_test_spec(req_buf, test_spec);
170 }
171
serialize_run_tests_resp(struct rpc_buffer * resp_buf,const struct test_summary * summary,const struct test_result * results)172 static rpc_status_t serialize_run_tests_resp(struct rpc_buffer *resp_buf,
173 const struct test_summary *summary,
174 const struct test_result *results)
175 {
176 return serialize_test_results(resp_buf, summary, results);
177 }
178
179 /* Operation: list_tests */
deserialize_list_tests_req(const struct rpc_buffer * req_buf,struct test_spec * test_spec)180 static rpc_status_t deserialize_list_tests_req(const struct rpc_buffer *req_buf,
181 struct test_spec *test_spec)
182 {
183 return deserialize_test_spec(req_buf, test_spec);
184 }
185
serialize_list_tests_resp(struct rpc_buffer * resp_buf,const struct test_summary * summary,const struct test_result * results)186 static rpc_status_t serialize_list_tests_resp(struct rpc_buffer *resp_buf,
187 const struct test_summary *summary,
188 const struct test_result *results)
189 {
190 return serialize_test_results(resp_buf, summary, results);
191 }
192
193 /* Singleton method to provide access to the serializer instance */
packedc_test_runner_provider_serializer_instance(void)194 const struct test_runner_provider_serializer *packedc_test_runner_provider_serializer_instance(void)
195 {
196 static const struct test_runner_provider_serializer instance = {
197 deserialize_run_tests_req, serialize_run_tests_resp, deserialize_list_tests_req,
198 serialize_list_tests_resp
199 };
200
201 return &instance;
202 }
203