Commit | Line | Data |
---|---|---|
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 | */ | |
12 | extern struct kunit_suite * const * const __kunit_suites_start[]; | |
13 | extern struct kunit_suite * const * const __kunit_suites_end[]; | |
14 | ||
15 | #if IS_BUILTIN(CONFIG_KUNIT) | |
16 | ||
5d31f71e DL |
17 | static char *filter_glob; |
18 | module_param(filter_glob, charp, 0); | |
19 | MODULE_PARM_DESC(filter_glob, | |
20 | "Filter which KUnit test suites run at boot-time, e.g. list*"); | |
21 | ||
b6d5799b DG |
22 | static char *kunit_shutdown; |
23 | core_param(kunit_shutdown, kunit_shutdown, charp, 0644); | |
24 | ||
5d31f71e DL |
25 | static struct kunit_suite * const * |
26 | kunit_filter_subsuite(struct kunit_suite * const * const subsuite) | |
27 | { | |
28 | int i, n = 0; | |
29 | struct kunit_suite **filtered; | |
30 | ||
31 | n = 0; | |
32 | for (i = 0; subsuite[i] != NULL; ++i) { | |
33 | if (glob_match(filter_glob, subsuite[i]->name)) | |
34 | ++n; | |
35 | } | |
36 | ||
37 | if (n == 0) | |
38 | return NULL; | |
39 | ||
40 | filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL); | |
41 | if (!filtered) | |
42 | return NULL; | |
43 | ||
44 | n = 0; | |
45 | for (i = 0; subsuite[i] != NULL; ++i) { | |
46 | if (glob_match(filter_glob, subsuite[i]->name)) | |
47 | filtered[n++] = subsuite[i]; | |
48 | } | |
49 | filtered[n] = NULL; | |
50 | ||
51 | return filtered; | |
52 | } | |
53 | ||
54 | struct suite_set { | |
55 | struct kunit_suite * const * const *start; | |
56 | struct kunit_suite * const * const *end; | |
57 | }; | |
58 | ||
59 | static struct suite_set kunit_filter_suites(void) | |
60 | { | |
61 | int i; | |
62 | struct kunit_suite * const **copy, * const *filtered_subsuite; | |
63 | struct suite_set filtered; | |
64 | ||
65 | const size_t max = __kunit_suites_end - __kunit_suites_start; | |
66 | ||
67 | if (!filter_glob) { | |
68 | filtered.start = __kunit_suites_start; | |
69 | filtered.end = __kunit_suites_end; | |
70 | return filtered; | |
71 | } | |
72 | ||
73 | copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); | |
74 | filtered.start = copy; | |
75 | if (!copy) { /* won't be able to run anything, return an empty set */ | |
76 | filtered.end = copy; | |
77 | return filtered; | |
78 | } | |
79 | ||
80 | for (i = 0; i < max; ++i) { | |
81 | filtered_subsuite = kunit_filter_subsuite(__kunit_suites_start[i]); | |
82 | if (filtered_subsuite) | |
83 | *copy++ = filtered_subsuite; | |
84 | } | |
85 | filtered.end = copy; | |
86 | return filtered; | |
87 | } | |
88 | ||
b6d5799b DG |
89 | static void kunit_handle_shutdown(void) |
90 | { | |
91 | if (!kunit_shutdown) | |
92 | return; | |
93 | ||
94 | if (!strcmp(kunit_shutdown, "poweroff")) | |
95 | kernel_power_off(); | |
96 | else if (!strcmp(kunit_shutdown, "halt")) | |
97 | kernel_halt(); | |
98 | else if (!strcmp(kunit_shutdown, "reboot")) | |
99 | kernel_restart(NULL); | |
100 | ||
101 | } | |
102 | ||
5d31f71e | 103 | static void kunit_print_tap_header(struct suite_set *suite_set) |
45dcbb6f BH |
104 | { |
105 | struct kunit_suite * const * const *suites, * const *subsuite; | |
106 | int num_of_suites = 0; | |
107 | ||
5d31f71e | 108 | for (suites = suite_set->start; suites < suite_set->end; suites++) |
45dcbb6f BH |
109 | for (subsuite = *suites; *subsuite != NULL; subsuite++) |
110 | num_of_suites++; | |
111 | ||
112 | pr_info("TAP version 14\n"); | |
113 | pr_info("1..%d\n", num_of_suites); | |
114 | } | |
115 | ||
8c0d8849 | 116 | int kunit_run_all_tests(void) |
aac35468 AM |
117 | { |
118 | struct kunit_suite * const * const *suites; | |
119 | ||
5d31f71e DL |
120 | struct suite_set suite_set = kunit_filter_suites(); |
121 | ||
122 | kunit_print_tap_header(&suite_set); | |
123 | ||
124 | for (suites = suite_set.start; suites < suite_set.end; suites++) | |
125 | __kunit_test_suites_init(*suites); | |
45dcbb6f | 126 | |
5d31f71e DL |
127 | if (filter_glob) { /* a copy was made of each array */ |
128 | for (suites = suite_set.start; suites < suite_set.end; suites++) | |
129 | kfree(*suites); | |
130 | kfree(suite_set.start); | |
131 | } | |
aac35468 | 132 | |
b6d5799b DG |
133 | kunit_handle_shutdown(); |
134 | ||
aac35468 AM |
135 | return 0; |
136 | } | |
137 | ||
aac35468 | 138 | #endif /* IS_BUILTIN(CONFIG_KUNIT) */ |