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 */ 12 extern struct kunit_suite * const __kunit_suites_start[]; 13 extern struct kunit_suite * const __kunit_suites_end[]; 14 15 #if IS_BUILTIN(CONFIG_KUNIT) 16 17 static char *filter_glob_param; 18 static char *action_param; 19 20 module_param_named(filter_glob, filter_glob_param, charp, 0); 21 MODULE_PARM_DESC(filter_glob, 22 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 23 module_param_named(action, action_param, charp, 0); 24 MODULE_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. */ 30 struct 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. */ 36 static 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. */ 57 static struct kunit_suite * 58 kunit_filter_tests(const 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 copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL); 73 if (!copy) 74 return ERR_PTR(-ENOMEM); 75 76 filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 77 if (!filtered) 78 return ERR_PTR(-ENOMEM); 79 80 n = 0; 81 kunit_suite_for_each_test_case(suite, test_case) { 82 if (!test_glob || glob_match(test_glob, test_case->name)) 83 filtered[n++] = *test_case; 84 } 85 86 copy->test_cases = filtered; 87 return copy; 88 } 89 90 static char *kunit_shutdown; 91 core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 92 93 /* Stores an array of suites, end points one past the end */ 94 struct suite_set { 95 struct kunit_suite * const *start; 96 struct kunit_suite * const *end; 97 }; 98 99 static void kunit_free_suite_set(struct suite_set suite_set) 100 { 101 struct kunit_suite * const *suites; 102 103 for (suites = suite_set.start; suites < suite_set.end; suites++) 104 kfree(*suites); 105 kfree(suite_set.start); 106 } 107 108 static struct suite_set kunit_filter_suites(const struct suite_set *suite_set, 109 const char *filter_glob, 110 int *err) 111 { 112 int i; 113 struct kunit_suite **copy, *filtered_suite; 114 struct suite_set filtered; 115 struct kunit_test_filter filter; 116 117 const size_t max = suite_set->end - suite_set->start; 118 119 copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 120 filtered.start = copy; 121 if (!copy) { /* won't be able to run anything, return an empty set */ 122 filtered.end = copy; 123 return filtered; 124 } 125 126 kunit_parse_filter_glob(&filter, filter_glob); 127 128 for (i = 0; &suite_set->start[i] != suite_set->end; i++) { 129 if (!glob_match(filter.suite_glob, suite_set->start[i]->name)) 130 continue; 131 132 filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob); 133 if (IS_ERR(filtered_suite)) { 134 *err = PTR_ERR(filtered_suite); 135 return filtered; 136 } 137 if (!filtered_suite) 138 continue; 139 140 *copy++ = filtered_suite; 141 } 142 filtered.end = copy; 143 144 kfree(filter.suite_glob); 145 kfree(filter.test_glob); 146 return filtered; 147 } 148 149 static void kunit_handle_shutdown(void) 150 { 151 if (!kunit_shutdown) 152 return; 153 154 if (!strcmp(kunit_shutdown, "poweroff")) 155 kernel_power_off(); 156 else if (!strcmp(kunit_shutdown, "halt")) 157 kernel_halt(); 158 else if (!strcmp(kunit_shutdown, "reboot")) 159 kernel_restart(NULL); 160 161 } 162 163 static void kunit_exec_run_tests(struct suite_set *suite_set) 164 { 165 size_t num_suites = suite_set->end - suite_set->start; 166 167 pr_info("TAP version 14\n"); 168 pr_info("1..%zu\n", num_suites); 169 170 __kunit_test_suites_init(suite_set->start, num_suites); 171 } 172 173 static void kunit_exec_list_tests(struct suite_set *suite_set) 174 { 175 struct kunit_suite * const *suites; 176 struct kunit_case *test_case; 177 178 /* Hack: print a tap header so kunit.py can find the start of KUnit output. */ 179 pr_info("TAP version 14\n"); 180 181 for (suites = suite_set->start; suites < suite_set->end; suites++) 182 kunit_suite_for_each_test_case((*suites), test_case) { 183 pr_info("%s.%s\n", (*suites)->name, test_case->name); 184 } 185 } 186 187 int kunit_run_all_tests(void) 188 { 189 struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end}; 190 int err = 0; 191 192 if (filter_glob_param) { 193 suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err); 194 if (err) { 195 pr_err("kunit executor: error filtering suites: %d\n", err); 196 goto out; 197 } 198 } 199 200 if (!action_param) 201 kunit_exec_run_tests(&suite_set); 202 else if (strcmp(action_param, "list") == 0) 203 kunit_exec_list_tests(&suite_set); 204 else 205 pr_err("kunit executor: unknown action '%s'\n", action_param); 206 207 if (filter_glob_param) { /* a copy was made of each suite */ 208 kunit_free_suite_set(suite_set); 209 } 210 211 out: 212 kunit_handle_shutdown(); 213 return err; 214 } 215 216 #if IS_BUILTIN(CONFIG_KUNIT_TEST) 217 #include "executor_test.c" 218 #endif 219 220 #endif /* IS_BUILTIN(CONFIG_KUNIT) */ 221