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