kunit: tool: update riscv QEMU config with new serial dependency
[linux-block.git] / lib / kunit / executor.c
CommitLineData
aac35468
AM
1// SPDX-License-Identifier: GPL-2.0
2
b6d5799b 3#include <linux/reboot.h>
aac35468 4#include <kunit/test.h>
5d31f71e
DL
5#include <linux/glob.h>
6#include <linux/moduleparam.h>
aac35468
AM
7
8/*
9 * These symbols point to the .kunit_test_suites section and are defined in
10 * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
11 */
12extern struct kunit_suite * const * const __kunit_suites_start[];
13extern struct kunit_suite * const * const __kunit_suites_end[];
14
15#if IS_BUILTIN(CONFIG_KUNIT)
16
1d71307a 17static char *filter_glob_param;
9c6b0e1d
DL
18static char *action_param;
19
1d71307a 20module_param_named(filter_glob, filter_glob_param, charp, 0);
5d31f71e 21MODULE_PARM_DESC(filter_glob,
a127b154 22 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
9c6b0e1d
DL
23module_param_named(action, action_param, charp, 0);
24MODULE_PARM_DESC(action,
25 "Changes KUnit executor behavior, valid values are:\n"
26 "<none>: run the tests like normal\n"
27 "'list' to list test names instead of running them.\n");
a127b154
DL
28
29/* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
30struct kunit_test_filter {
31 char *suite_glob;
32 char *test_glob;
33};
34
35/* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
36static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
37 const char *filter_glob)
38{
39 const int len = strlen(filter_glob);
40 const char *period = strchr(filter_glob, '.');
41
42 if (!period) {
cd94fbc2 43 parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL);
a127b154
DL
44 parsed->test_glob = NULL;
45 strcpy(parsed->suite_glob, filter_glob);
46 return;
47 }
48
49 parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL);
50 parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL);
51
52 strncpy(parsed->suite_glob, filter_glob, period - filter_glob);
53 strncpy(parsed->test_glob, period + 1, len - (period - filter_glob));
54}
55
56/* Create a copy of suite with only tests that match test_glob. */
57static struct kunit_suite *
58kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
59{
60 int n = 0;
61 struct kunit_case *filtered, *test_case;
62 struct kunit_suite *copy;
63
64 kunit_suite_for_each_test_case(suite, test_case) {
65 if (!test_glob || glob_match(test_glob, test_case->name))
66 ++n;
67 }
68
69 if (n == 0)
70 return NULL;
71
72 /* Use memcpy to workaround copy->name being const. */
73 copy = kmalloc(sizeof(*copy), GFP_KERNEL);
a02353f4
DL
74 if (!copy)
75 return ERR_PTR(-ENOMEM);
a127b154
DL
76 memcpy(copy, suite, sizeof(*copy));
77
78 filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
a02353f4
DL
79 if (!filtered)
80 return ERR_PTR(-ENOMEM);
a127b154
DL
81
82 n = 0;
83 kunit_suite_for_each_test_case(suite, test_case) {
84 if (!test_glob || glob_match(test_glob, test_case->name))
85 filtered[n++] = *test_case;
86 }
87
88 copy->test_cases = filtered;
89 return copy;
90}
5d31f71e 91
b6d5799b
DG
92static char *kunit_shutdown;
93core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
94
5d31f71e 95static struct kunit_suite * const *
1d71307a 96kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
a127b154 97 struct kunit_test_filter *filter)
5d31f71e
DL
98{
99 int i, n = 0;
a127b154 100 struct kunit_suite **filtered, *filtered_suite;
5d31f71e
DL
101
102 n = 0;
a127b154
DL
103 for (i = 0; subsuite[i]; ++i) {
104 if (glob_match(filter->suite_glob, subsuite[i]->name))
5d31f71e
DL
105 ++n;
106 }
107
108 if (n == 0)
109 return NULL;
110
111 filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL);
112 if (!filtered)
a02353f4 113 return ERR_PTR(-ENOMEM);
5d31f71e
DL
114
115 n = 0;
116 for (i = 0; subsuite[i] != NULL; ++i) {
a127b154
DL
117 if (!glob_match(filter->suite_glob, subsuite[i]->name))
118 continue;
119 filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
a02353f4
DL
120 if (IS_ERR(filtered_suite))
121 return ERR_CAST(filtered_suite);
122 else if (filtered_suite)
a127b154 123 filtered[n++] = filtered_suite;
5d31f71e
DL
124 }
125 filtered[n] = NULL;
126
127 return filtered;
128}
129
130struct suite_set {
131 struct kunit_suite * const * const *start;
132 struct kunit_suite * const * const *end;
133};
134
a127b154
DL
135static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
136{
137 unsigned int i;
138
139 for (i = 0; subsuite[i]; i++)
140 kfree(subsuite[i]);
141
142 kfree(subsuite);
143}
144
145static void kunit_free_suite_set(struct suite_set suite_set)
146{
147 struct kunit_suite * const * const *suites;
148
149 for (suites = suite_set.start; suites < suite_set.end; suites++)
150 kunit_free_subsuite(*suites);
151 kfree(suite_set.start);
152}
153
1d71307a 154static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
a02353f4
DL
155 const char *filter_glob,
156 int *err)
5d31f71e
DL
157{
158 int i;
159 struct kunit_suite * const **copy, * const *filtered_subsuite;
160 struct suite_set filtered;
a127b154 161 struct kunit_test_filter filter;
5d31f71e 162
1d71307a 163 const size_t max = suite_set->end - suite_set->start;
5d31f71e
DL
164
165 copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
166 filtered.start = copy;
167 if (!copy) { /* won't be able to run anything, return an empty set */
168 filtered.end = copy;
169 return filtered;
170 }
171
a127b154
DL
172 kunit_parse_filter_glob(&filter, filter_glob);
173
5d31f71e 174 for (i = 0; i < max; ++i) {
a127b154 175 filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
a02353f4
DL
176 if (IS_ERR(filtered_subsuite)) {
177 *err = PTR_ERR(filtered_subsuite);
178 return filtered;
179 }
5d31f71e
DL
180 if (filtered_subsuite)
181 *copy++ = filtered_subsuite;
182 }
183 filtered.end = copy;
a127b154
DL
184
185 kfree(filter.suite_glob);
186 kfree(filter.test_glob);
5d31f71e
DL
187 return filtered;
188}
189
b6d5799b
DG
190static void kunit_handle_shutdown(void)
191{
192 if (!kunit_shutdown)
193 return;
194
195 if (!strcmp(kunit_shutdown, "poweroff"))
196 kernel_power_off();
197 else if (!strcmp(kunit_shutdown, "halt"))
198 kernel_halt();
199 else if (!strcmp(kunit_shutdown, "reboot"))
200 kernel_restart(NULL);
201
202}
203
5d31f71e 204static void kunit_print_tap_header(struct suite_set *suite_set)
45dcbb6f
BH
205{
206 struct kunit_suite * const * const *suites, * const *subsuite;
207 int num_of_suites = 0;
208
5d31f71e 209 for (suites = suite_set->start; suites < suite_set->end; suites++)
45dcbb6f
BH
210 for (subsuite = *suites; *subsuite != NULL; subsuite++)
211 num_of_suites++;
212
213 pr_info("TAP version 14\n");
214 pr_info("1..%d\n", num_of_suites);
215}
216
9c6b0e1d 217static void kunit_exec_run_tests(struct suite_set *suite_set)
aac35468
AM
218{
219 struct kunit_suite * const * const *suites;
9c6b0e1d
DL
220
221 kunit_print_tap_header(suite_set);
222
223 for (suites = suite_set->start; suites < suite_set->end; suites++)
224 __kunit_test_suites_init(*suites);
225}
226
227static void kunit_exec_list_tests(struct suite_set *suite_set)
228{
229 unsigned int i;
230 struct kunit_suite * const * const *suites;
231 struct kunit_case *test_case;
232
233 /* Hack: print a tap header so kunit.py can find the start of KUnit output. */
234 pr_info("TAP version 14\n");
235
236 for (suites = suite_set->start; suites < suite_set->end; suites++)
237 for (i = 0; (*suites)[i] != NULL; i++) {
238 kunit_suite_for_each_test_case((*suites)[i], test_case) {
239 pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
240 }
241 }
242}
243
244int kunit_run_all_tests(void)
245{
1d71307a
DL
246 struct suite_set suite_set = {
247 .start = __kunit_suites_start,
248 .end = __kunit_suites_end,
249 };
a02353f4 250 int err;
aac35468 251
a02353f4
DL
252 if (filter_glob_param) {
253 suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
254 if (err) {
255 pr_err("kunit executor: error filtering suites: %d\n", err);
256 return err;
257 }
258 }
5d31f71e 259
9c6b0e1d
DL
260 if (!action_param)
261 kunit_exec_run_tests(&suite_set);
262 else if (strcmp(action_param, "list") == 0)
263 kunit_exec_list_tests(&suite_set);
264 else
265 pr_err("kunit executor: unknown action '%s'\n", action_param);
45dcbb6f 266
1d71307a 267 if (filter_glob_param) { /* a copy was made of each array */
a127b154 268 kunit_free_suite_set(suite_set);
5d31f71e 269 }
aac35468 270
b6d5799b
DG
271 kunit_handle_shutdown();
272
aac35468
AM
273 return 0;
274}
275
1d71307a
DL
276#if IS_BUILTIN(CONFIG_KUNIT_TEST)
277#include "executor_test.c"
278#endif
279
aac35468 280#endif /* IS_BUILTIN(CONFIG_KUNIT) */