executor.c (7274B)
1// SPDX-License-Identifier: GPL-2.0 2 3#include <linux/reboot.h> 4#include <kunit/test.h> 5#include <linux/glob.h> 6#include <linux/moduleparam.h> 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 17static char *filter_glob_param; 18static char *action_param; 19 20module_param_named(filter_glob, filter_glob_param, charp, 0); 21MODULE_PARM_DESC(filter_glob, 22 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 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"); 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) { 43 parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL); 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); 74 if (!copy) 75 return ERR_PTR(-ENOMEM); 76 memcpy(copy, suite, sizeof(*copy)); 77 78 filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 79 if (!filtered) 80 return ERR_PTR(-ENOMEM); 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} 91 92static char *kunit_shutdown; 93core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 94 95static struct kunit_suite * const * 96kunit_filter_subsuite(struct kunit_suite * const * const subsuite, 97 struct kunit_test_filter *filter) 98{ 99 int i, n = 0; 100 struct kunit_suite **filtered, *filtered_suite; 101 102 n = 0; 103 for (i = 0; subsuite[i]; ++i) { 104 if (glob_match(filter->suite_glob, subsuite[i]->name)) 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) 113 return ERR_PTR(-ENOMEM); 114 115 n = 0; 116 for (i = 0; subsuite[i] != NULL; ++i) { 117 if (!glob_match(filter->suite_glob, subsuite[i]->name)) 118 continue; 119 filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob); 120 if (IS_ERR(filtered_suite)) 121 return ERR_CAST(filtered_suite); 122 else if (filtered_suite) 123 filtered[n++] = filtered_suite; 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 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 154static struct suite_set kunit_filter_suites(const struct suite_set *suite_set, 155 const char *filter_glob, 156 int *err) 157{ 158 int i; 159 struct kunit_suite * const **copy, * const *filtered_subsuite; 160 struct suite_set filtered; 161 struct kunit_test_filter filter; 162 163 const size_t max = suite_set->end - suite_set->start; 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 172 kunit_parse_filter_glob(&filter, filter_glob); 173 174 for (i = 0; i < max; ++i) { 175 filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter); 176 if (IS_ERR(filtered_subsuite)) { 177 *err = PTR_ERR(filtered_subsuite); 178 return filtered; 179 } 180 if (filtered_subsuite) 181 *copy++ = filtered_subsuite; 182 } 183 filtered.end = copy; 184 185 kfree(filter.suite_glob); 186 kfree(filter.test_glob); 187 return filtered; 188} 189 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 204static void kunit_print_tap_header(struct suite_set *suite_set) 205{ 206 struct kunit_suite * const * const *suites, * const *subsuite; 207 int num_of_suites = 0; 208 209 for (suites = suite_set->start; suites < suite_set->end; suites++) 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 217static void kunit_exec_run_tests(struct suite_set *suite_set) 218{ 219 struct kunit_suite * const * const *suites; 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{ 246 struct suite_set suite_set = { 247 .start = __kunit_suites_start, 248 .end = __kunit_suites_end, 249 }; 250 int err = 0; 251 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 goto out; 257 } 258 } 259 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); 266 267 if (filter_glob_param) { /* a copy was made of each array */ 268 kunit_free_suite_set(suite_set); 269 } 270 271 272out: 273 kunit_handle_shutdown(); 274 return err; 275} 276 277#if IS_BUILTIN(CONFIG_KUNIT_TEST) 278#include "executor_test.c" 279#endif 280 281#endif /* IS_BUILTIN(CONFIG_KUNIT) */