Linux 6.9-rc1
[linux-2.6-microblaze.git] / lib / kunit / executor.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/reboot.h>
4 #include <kunit/test.h>
5 #include <kunit/attributes.h>
6 #include <linux/glob.h>
7 #include <linux/moduleparam.h>
8
9 /*
10  * These symbols point to the .kunit_test_suites section and are defined in
11  * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
12  */
13 extern struct kunit_suite * const __kunit_suites_start[];
14 extern struct kunit_suite * const __kunit_suites_end[];
15 extern struct kunit_suite * const __kunit_init_suites_start[];
16 extern struct kunit_suite * const __kunit_init_suites_end[];
17
18 static char *action_param;
19
20 module_param_named(action, action_param, charp, 0400);
21 MODULE_PARM_DESC(action,
22                  "Changes KUnit executor behavior, valid values are:\n"
23                  "<none>: run the tests like normal\n"
24                  "'list' to list test names instead of running them.\n"
25                  "'list_attr' to list test names and attributes instead of running them.\n");
26
27 const char *kunit_action(void)
28 {
29         return action_param;
30 }
31
32 static char *filter_glob_param;
33 static char *filter_param;
34 static char *filter_action_param;
35
36 module_param_named(filter_glob, filter_glob_param, charp, 0600);
37 MODULE_PARM_DESC(filter_glob,
38                 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
39 module_param_named(filter, filter_param, charp, 0600);
40 MODULE_PARM_DESC(filter,
41                 "Filter which KUnit test suites/tests run at boot-time using attributes, e.g. speed>slow");
42 module_param_named(filter_action, filter_action_param, charp, 0600);
43 MODULE_PARM_DESC(filter_action,
44                 "Changes behavior of filtered tests using attributes, valid values are:\n"
45                 "<none>: do not run filtered tests as normal\n"
46                 "'skip': skip all filtered tests instead so tests will appear in output\n");
47
48 const char *kunit_filter_glob(void)
49 {
50         return filter_glob_param;
51 }
52
53 char *kunit_filter(void)
54 {
55         return filter_param;
56 }
57
58 char *kunit_filter_action(void)
59 {
60         return filter_action_param;
61 }
62
63 /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
64 struct kunit_glob_filter {
65         char *suite_glob;
66         char *test_glob;
67 };
68
69 /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
70 static int kunit_parse_glob_filter(struct kunit_glob_filter *parsed,
71                                     const char *filter_glob)
72 {
73         const int len = strlen(filter_glob);
74         const char *period = strchr(filter_glob, '.');
75
76         if (!period) {
77                 parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL);
78                 if (!parsed->suite_glob)
79                         return -ENOMEM;
80
81                 parsed->test_glob = NULL;
82                 strcpy(parsed->suite_glob, filter_glob);
83                 return 0;
84         }
85
86         parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL);
87         if (!parsed->suite_glob)
88                 return -ENOMEM;
89
90         parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL);
91         if (!parsed->test_glob) {
92                 kfree(parsed->suite_glob);
93                 return -ENOMEM;
94         }
95
96         strncpy(parsed->suite_glob, filter_glob, period - filter_glob);
97         strncpy(parsed->test_glob, period + 1, len - (period - filter_glob));
98
99         return 0;
100 }
101
102 /* Create a copy of suite with only tests that match test_glob. */
103 static struct kunit_suite *
104 kunit_filter_glob_tests(const struct kunit_suite *const suite, const char *test_glob)
105 {
106         int n = 0;
107         struct kunit_case *filtered, *test_case;
108         struct kunit_suite *copy;
109
110         kunit_suite_for_each_test_case(suite, test_case) {
111                 if (!test_glob || glob_match(test_glob, test_case->name))
112                         ++n;
113         }
114
115         if (n == 0)
116                 return NULL;
117
118         copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL);
119         if (!copy)
120                 return ERR_PTR(-ENOMEM);
121
122         filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
123         if (!filtered) {
124                 kfree(copy);
125                 return ERR_PTR(-ENOMEM);
126         }
127
128         n = 0;
129         kunit_suite_for_each_test_case(suite, test_case) {
130                 if (!test_glob || glob_match(test_glob, test_case->name))
131                         filtered[n++] = *test_case;
132         }
133
134         copy->test_cases = filtered;
135         return copy;
136 }
137
138 void kunit_free_suite_set(struct kunit_suite_set suite_set)
139 {
140         struct kunit_suite * const *suites;
141
142         for (suites = suite_set.start; suites < suite_set.end; suites++) {
143                 kfree((*suites)->test_cases);
144                 kfree(*suites);
145         }
146         kfree(suite_set.start);
147 }
148
149 /*
150  * Filter and reallocate test suites. Must return the filtered test suites set
151  * allocated at a valid virtual address or NULL in case of error.
152  */
153 struct kunit_suite_set
154 kunit_filter_suites(const struct kunit_suite_set *suite_set,
155                     const char *filter_glob,
156                     char *filters,
157                     char *filter_action,
158                     int *err)
159 {
160         int i, j, k;
161         int filter_count = 0;
162         struct kunit_suite **copy, **copy_start, *filtered_suite, *new_filtered_suite;
163         struct kunit_suite_set filtered = {NULL, NULL};
164         struct kunit_glob_filter parsed_glob;
165         struct kunit_attr_filter *parsed_filters = NULL;
166         struct kunit_suite * const *suites;
167
168         const size_t max = suite_set->end - suite_set->start;
169
170         copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL);
171         if (!copy) { /* won't be able to run anything, return an empty set */
172                 return filtered;
173         }
174         copy_start = copy;
175
176         if (filter_glob) {
177                 *err = kunit_parse_glob_filter(&parsed_glob, filter_glob);
178                 if (*err)
179                         goto free_copy;
180         }
181
182         /* Parse attribute filters */
183         if (filters) {
184                 filter_count = kunit_get_filter_count(filters);
185                 parsed_filters = kcalloc(filter_count, sizeof(*parsed_filters), GFP_KERNEL);
186                 if (!parsed_filters) {
187                         *err = -ENOMEM;
188                         goto free_parsed_glob;
189                 }
190                 for (j = 0; j < filter_count; j++)
191                         parsed_filters[j] = kunit_next_attr_filter(&filters, err);
192                 if (*err)
193                         goto free_parsed_filters;
194         }
195
196         for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
197                 filtered_suite = suite_set->start[i];
198                 if (filter_glob) {
199                         if (!glob_match(parsed_glob.suite_glob, filtered_suite->name))
200                                 continue;
201                         filtered_suite = kunit_filter_glob_tests(filtered_suite,
202                                         parsed_glob.test_glob);
203                         if (IS_ERR(filtered_suite)) {
204                                 *err = PTR_ERR(filtered_suite);
205                                 goto free_filtered_suite;
206                         }
207                 }
208                 if (filter_count > 0 && parsed_filters != NULL) {
209                         for (k = 0; k < filter_count; k++) {
210                                 new_filtered_suite = kunit_filter_attr_tests(filtered_suite,
211                                                 parsed_filters[k], filter_action, err);
212
213                                 /* Free previous copy of suite */
214                                 if (k > 0 || filter_glob) {
215                                         kfree(filtered_suite->test_cases);
216                                         kfree(filtered_suite);
217                                 }
218
219                                 filtered_suite = new_filtered_suite;
220
221                                 if (*err)
222                                         goto free_filtered_suite;
223
224                                 if (IS_ERR(filtered_suite)) {
225                                         *err = PTR_ERR(filtered_suite);
226                                         goto free_filtered_suite;
227                                 }
228                                 if (!filtered_suite)
229                                         break;
230                         }
231                 }
232
233                 if (!filtered_suite)
234                         continue;
235
236                 *copy++ = filtered_suite;
237         }
238         filtered.start = copy_start;
239         filtered.end = copy;
240
241 free_filtered_suite:
242         if (*err) {
243                 for (suites = copy_start; suites < copy; suites++) {
244                         kfree((*suites)->test_cases);
245                         kfree(*suites);
246                 }
247         }
248
249 free_parsed_filters:
250         if (filter_count)
251                 kfree(parsed_filters);
252
253 free_parsed_glob:
254         if (filter_glob) {
255                 kfree(parsed_glob.suite_glob);
256                 kfree(parsed_glob.test_glob);
257         }
258
259 free_copy:
260         if (*err)
261                 kfree(copy_start);
262
263         return filtered;
264 }
265
266 void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin)
267 {
268         size_t num_suites = suite_set->end - suite_set->start;
269
270         if (builtin || num_suites) {
271                 pr_info("KTAP version 1\n");
272                 pr_info("1..%zu\n", num_suites);
273         }
274
275         __kunit_test_suites_init(suite_set->start, num_suites);
276 }
277
278 void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr)
279 {
280         struct kunit_suite * const *suites;
281         struct kunit_case *test_case;
282
283         /* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
284         pr_info("KTAP version 1\n");
285
286         for (suites = suite_set->start; suites < suite_set->end; suites++) {
287                 /* Print suite name and suite attributes */
288                 pr_info("%s\n", (*suites)->name);
289                 if (include_attr)
290                         kunit_print_attr((void *)(*suites), false, 0);
291
292                 /* Print test case name and attributes in suite */
293                 kunit_suite_for_each_test_case((*suites), test_case) {
294                         pr_info("%s.%s\n", (*suites)->name, test_case->name);
295                         if (include_attr)
296                                 kunit_print_attr((void *)test_case, true, 0);
297                 }
298         }
299 }
300
301 struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set,
302                 struct kunit_suite_set suite_set)
303 {
304         struct kunit_suite_set total_suite_set = {NULL, NULL};
305         struct kunit_suite **total_suite_start = NULL;
306         size_t init_num_suites, num_suites, suite_size;
307         int i = 0;
308
309         init_num_suites = init_suite_set.end - init_suite_set.start;
310         num_suites = suite_set.end - suite_set.start;
311         suite_size = sizeof(suite_set.start);
312
313         /* Allocate memory for array of all kunit suites */
314         total_suite_start = kmalloc_array(init_num_suites + num_suites, suite_size, GFP_KERNEL);
315         if (!total_suite_start)
316                 return total_suite_set;
317
318         /* Append and mark init suites and then append all other kunit suites */
319         memcpy(total_suite_start, init_suite_set.start, init_num_suites * suite_size);
320         for (i = 0; i < init_num_suites; i++)
321                 total_suite_start[i]->is_init = true;
322
323         memcpy(total_suite_start + init_num_suites, suite_set.start, num_suites * suite_size);
324
325         /* Set kunit suite set start and end */
326         total_suite_set.start = total_suite_start;
327         total_suite_set.end = total_suite_start + (init_num_suites + num_suites);
328
329         return total_suite_set;
330 }
331
332 #if IS_BUILTIN(CONFIG_KUNIT)
333
334 static char *kunit_shutdown;
335 core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
336
337 static void kunit_handle_shutdown(void)
338 {
339         if (!kunit_shutdown)
340                 return;
341
342         if (!strcmp(kunit_shutdown, "poweroff"))
343                 kernel_power_off();
344         else if (!strcmp(kunit_shutdown, "halt"))
345                 kernel_halt();
346         else if (!strcmp(kunit_shutdown, "reboot"))
347                 kernel_restart(NULL);
348
349 }
350
351 int kunit_run_all_tests(void)
352 {
353         struct kunit_suite_set suite_set = {NULL, NULL};
354         struct kunit_suite_set filtered_suite_set = {NULL, NULL};
355         struct kunit_suite_set init_suite_set = {
356                 __kunit_init_suites_start, __kunit_init_suites_end,
357         };
358         struct kunit_suite_set normal_suite_set = {
359                 __kunit_suites_start, __kunit_suites_end,
360         };
361         size_t init_num_suites = init_suite_set.end - init_suite_set.start;
362         int err = 0;
363
364         if (init_num_suites > 0) {
365                 suite_set = kunit_merge_suite_sets(init_suite_set, normal_suite_set);
366                 if (!suite_set.start)
367                         goto out;
368         } else
369                 suite_set = normal_suite_set;
370
371         if (!kunit_enabled()) {
372                 pr_info("kunit: disabled\n");
373                 goto free_out;
374         }
375
376         if (filter_glob_param || filter_param) {
377                 filtered_suite_set = kunit_filter_suites(&suite_set, filter_glob_param,
378                                 filter_param, filter_action_param, &err);
379
380                 /* Free original suite set before using filtered suite set */
381                 if (init_num_suites > 0)
382                         kfree(suite_set.start);
383                 suite_set = filtered_suite_set;
384
385                 if (err) {
386                         pr_err("kunit executor: error filtering suites: %d\n", err);
387                         goto free_out;
388                 }
389         }
390
391         if (!action_param)
392                 kunit_exec_run_tests(&suite_set, true);
393         else if (strcmp(action_param, "list") == 0)
394                 kunit_exec_list_tests(&suite_set, false);
395         else if (strcmp(action_param, "list_attr") == 0)
396                 kunit_exec_list_tests(&suite_set, true);
397         else
398                 pr_err("kunit executor: unknown action '%s'\n", action_param);
399
400 free_out:
401         if (filter_glob_param || filter_param)
402                 kunit_free_suite_set(suite_set);
403         else if (init_num_suites > 0)
404                 /* Don't use kunit_free_suite_set because suites aren't individually allocated */
405                 kfree(suite_set.start);
406
407 out:
408         kunit_handle_shutdown();
409         return err;
410 }
411
412 #if IS_BUILTIN(CONFIG_KUNIT_TEST)
413 #include "executor_test.c"
414 #endif
415
416 #endif /* IS_BUILTIN(CONFIG_KUNIT) */