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