1 /*
2  * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include "test_runner_provider.h"
7 
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 <stdbool.h>
12 #include <stdlib.h>
13 
14 #include "test_runner_backend.h"
15 #include "test_runner_uuid.h"
16 
17 /* Service request handlers */
18 static rpc_status_t run_tests_handler(void *context, struct rpc_request *req);
19 static rpc_status_t list_tests_handler(void *context, struct rpc_request *req);
20 
21 /* Handler mapping table for service */
22 static const struct service_handler handler_table[] = {
23 	{ TS_TEST_RUNNER_OPCODE_RUN_TESTS, run_tests_handler },
24 	{ TS_TEST_RUNNER_OPCODE_LIST_TESTS, list_tests_handler }
25 };
26 
test_runner_provider_init(struct test_runner_provider * context)27 struct rpc_service_interface *test_runner_provider_init(struct test_runner_provider *context)
28 {
29 	struct rpc_service_interface *rpc_interface = NULL;
30 	const struct rpc_uuid service_uuid = { .uuid = TS_TEST_RUNNER_SERVICE_UUID };
31 
32 	if (context) {
33 		for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
34 			context->serializers[encoding] = NULL;
35 
36 		context->backend_list = NULL;
37 
38 		service_provider_init(&context->base_provider, context, &service_uuid,
39 				      handler_table,
40 				      sizeof(handler_table) / sizeof(struct service_handler));
41 
42 		rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
43 
44 		/* Allow a deployment specific test_runner backend to be registrered */
45 		test_runner_register_default_backend(context);
46 	}
47 
48 	return rpc_interface;
49 }
50 
test_runner_provider_deinit(struct test_runner_provider * context)51 void test_runner_provider_deinit(struct test_runner_provider *context)
52 {
53 	(void)context;
54 }
55 
test_runner_provider_register_serializer(struct test_runner_provider * context,unsigned int encoding,const struct test_runner_provider_serializer * serializer)56 void test_runner_provider_register_serializer(
57 	struct test_runner_provider *context, unsigned int encoding,
58 	const struct test_runner_provider_serializer *serializer)
59 {
60 	if (encoding < TS_RPC_ENCODING_LIMIT)
61 		context->serializers[encoding] = serializer;
62 }
63 
test_runner_provider_register_backend(struct test_runner_provider * context,struct test_runner_backend * backend)64 void test_runner_provider_register_backend(struct test_runner_provider *context,
65 					   struct test_runner_backend *backend)
66 {
67 	/* Insert into list of backend test runners */
68 	backend->next = context->backend_list;
69 	context->backend_list = backend;
70 }
71 
72 static const struct test_runner_provider_serializer *
get_test_runner_serializer(struct test_runner_provider * context,const struct rpc_request * req)73 get_test_runner_serializer(struct test_runner_provider *context, const struct rpc_request *req)
74 {
75 	const struct test_runner_provider_serializer *serializer = NULL;
76 	unsigned int encoding = 0; /* Only one encoding is supported now */
77 
78 	if (encoding < TS_RPC_ENCODING_LIMIT)
79 		serializer = context->serializers[encoding];
80 
81 	return serializer;
82 }
83 
alloc_result_buf(struct test_runner_provider * context,const struct test_spec * test_spec,size_t * result_limit)84 static struct test_result *alloc_result_buf(struct test_runner_provider *context,
85 					    const struct test_spec *test_spec, size_t *result_limit)
86 {
87 	struct test_result *space = NULL;
88 	size_t total_tests = 0;
89 	struct test_runner_backend *backend = context->backend_list;
90 
91 	while (backend) {
92 		total_tests += backend->count_tests(test_spec);
93 		backend = backend->next;
94 	}
95 
96 	space = malloc(total_tests * sizeof(struct test_result));
97 
98 	*result_limit = total_tests;
99 	return space;
100 }
101 
run_qualifying_tests(struct test_runner_provider * context,bool list_only,const struct test_spec * spec,struct test_summary * summary,struct test_result * results,size_t result_limit)102 static int run_qualifying_tests(struct test_runner_provider *context, bool list_only,
103 				const struct test_spec *spec, struct test_summary *summary,
104 				struct test_result *results, size_t result_limit)
105 {
106 	int test_status = TS_TEST_RUNNER_STATUS_SUCCESS;
107 	struct test_runner_backend *backend = context->backend_list;
108 
109 	summary->num_tests = 0;
110 	summary->num_results = 0;
111 	summary->num_passed = 0;
112 	summary->num_failed = 0;
113 
114 	while (backend && (test_status == TS_TEST_RUNNER_STATUS_SUCCESS)) {
115 		struct test_summary interim_summary;
116 
117 		if (list_only) {
118 			backend->list_tests(spec, &interim_summary, &results[summary->num_results],
119 					    result_limit - summary->num_results);
120 		} else {
121 			test_status = backend->run_tests(spec, &interim_summary,
122 							 &results[summary->num_results],
123 							 result_limit - summary->num_results);
124 		}
125 
126 		summary->num_tests += interim_summary.num_tests;
127 		summary->num_results += interim_summary.num_results;
128 		summary->num_passed += interim_summary.num_passed;
129 		summary->num_failed += interim_summary.num_failed;
130 
131 		backend = backend->next;
132 	}
133 
134 	return test_status;
135 }
136 
run_tests_handler(void * context,struct rpc_request * req)137 static rpc_status_t run_tests_handler(void *context, struct rpc_request *req)
138 {
139 	struct test_runner_provider *this_instance = (struct test_runner_provider *)context;
140 	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
141 	struct test_spec test_spec;
142 
143 	struct rpc_buffer *req_buf = &req->request;
144 	const struct test_runner_provider_serializer *serializer =
145 		get_test_runner_serializer(this_instance, req);
146 
147 	if (serializer)
148 		rpc_status = serializer->deserialize_run_tests_req(req_buf, &test_spec);
149 
150 	if (rpc_status == RPC_SUCCESS) {
151 		struct test_summary summary;
152 		size_t result_limit = 0;
153 		struct test_result *result_buf =
154 			alloc_result_buf(this_instance, &test_spec, &result_limit);
155 
156 		req->service_status = run_qualifying_tests(this_instance, false, &test_spec,
157 							   &summary, result_buf, result_limit);
158 
159 		if (req->service_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
160 			struct rpc_buffer *resp_buf = &req->response;
161 
162 			rpc_status = serializer->serialize_run_tests_resp(resp_buf, &summary,
163 									  result_buf);
164 
165 			free(result_buf);
166 		}
167 	}
168 
169 	return rpc_status;
170 }
171 
list_tests_handler(void * context,struct rpc_request * req)172 static rpc_status_t list_tests_handler(void *context, struct rpc_request *req)
173 {
174 	struct test_runner_provider *this_instance = (struct test_runner_provider *)context;
175 	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
176 	struct test_spec test_spec;
177 
178 	struct rpc_buffer *req_buf = &req->request;
179 	const struct test_runner_provider_serializer *serializer =
180 		get_test_runner_serializer(this_instance, req);
181 
182 	if (serializer)
183 		rpc_status = serializer->deserialize_list_tests_req(req_buf, &test_spec);
184 
185 	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
186 		struct test_summary summary;
187 		size_t result_limit = 0;
188 		struct test_result *result_buf =
189 			alloc_result_buf(this_instance, &test_spec, &result_limit);
190 
191 		req->service_status = run_qualifying_tests(this_instance, true, &test_spec,
192 							   &summary, result_buf, result_limit);
193 
194 		if (req->service_status == TS_TEST_RUNNER_STATUS_SUCCESS) {
195 			struct rpc_buffer *resp_buf = &req->response;
196 
197 			rpc_status = serializer->serialize_list_tests_resp(resp_buf, &summary,
198 									   result_buf);
199 
200 			free(result_buf);
201 		}
202 	}
203 
204 	return rpc_status;
205 }
206