1aac35468SAlan Maguire // SPDX-License-Identifier: GPL-2.0 2aac35468SAlan Maguire 3b6d5799bSDavid Gow #include <linux/reboot.h> 4aac35468SAlan Maguire #include <kunit/test.h> 55d31f71eSDaniel Latypov #include <linux/glob.h> 65d31f71eSDaniel Latypov #include <linux/moduleparam.h> 7aac35468SAlan Maguire 8aac35468SAlan Maguire /* 9aac35468SAlan Maguire * These symbols point to the .kunit_test_suites section and are defined in 10aac35468SAlan Maguire * include/asm-generic/vmlinux.lds.h, and consequently must be extern. 11aac35468SAlan Maguire */ 12aac35468SAlan Maguire extern struct kunit_suite * const * const __kunit_suites_start[]; 13aac35468SAlan Maguire extern struct kunit_suite * const * const __kunit_suites_end[]; 14aac35468SAlan Maguire 15aac35468SAlan Maguire #if IS_BUILTIN(CONFIG_KUNIT) 16aac35468SAlan Maguire 171d71307aSDaniel Latypov static char *filter_glob_param; 189c6b0e1dSDaniel Latypov static char *action_param; 199c6b0e1dSDaniel Latypov 201d71307aSDaniel Latypov module_param_named(filter_glob, filter_glob_param, charp, 0); 215d31f71eSDaniel Latypov MODULE_PARM_DESC(filter_glob, 22a127b154SDaniel Latypov "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 239c6b0e1dSDaniel Latypov module_param_named(action, action_param, charp, 0); 249c6b0e1dSDaniel Latypov MODULE_PARM_DESC(action, 259c6b0e1dSDaniel Latypov "Changes KUnit executor behavior, valid values are:\n" 269c6b0e1dSDaniel Latypov "<none>: run the tests like normal\n" 279c6b0e1dSDaniel Latypov "'list' to list test names instead of running them.\n"); 28a127b154SDaniel Latypov 29a127b154SDaniel Latypov /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */ 30a127b154SDaniel Latypov struct kunit_test_filter { 31a127b154SDaniel Latypov char *suite_glob; 32a127b154SDaniel Latypov char *test_glob; 33a127b154SDaniel Latypov }; 34a127b154SDaniel Latypov 35a127b154SDaniel Latypov /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */ 36a127b154SDaniel Latypov static void kunit_parse_filter_glob(struct kunit_test_filter *parsed, 37a127b154SDaniel Latypov const char *filter_glob) 38a127b154SDaniel Latypov { 39a127b154SDaniel Latypov const int len = strlen(filter_glob); 40a127b154SDaniel Latypov const char *period = strchr(filter_glob, '.'); 41a127b154SDaniel Latypov 42a127b154SDaniel Latypov if (!period) { 43cd94fbc2SDaniel Latypov parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL); 44a127b154SDaniel Latypov parsed->test_glob = NULL; 45a127b154SDaniel Latypov strcpy(parsed->suite_glob, filter_glob); 46a127b154SDaniel Latypov return; 47a127b154SDaniel Latypov } 48a127b154SDaniel Latypov 49a127b154SDaniel Latypov parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL); 50a127b154SDaniel Latypov parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL); 51a127b154SDaniel Latypov 52a127b154SDaniel Latypov strncpy(parsed->suite_glob, filter_glob, period - filter_glob); 53a127b154SDaniel Latypov strncpy(parsed->test_glob, period + 1, len - (period - filter_glob)); 54a127b154SDaniel Latypov } 55a127b154SDaniel Latypov 56a127b154SDaniel Latypov /* Create a copy of suite with only tests that match test_glob. */ 57a127b154SDaniel Latypov static struct kunit_suite * 58*d2fbdde8SDaniel Latypov kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob) 59a127b154SDaniel Latypov { 60a127b154SDaniel Latypov int n = 0; 61a127b154SDaniel Latypov struct kunit_case *filtered, *test_case; 62a127b154SDaniel Latypov struct kunit_suite *copy; 63a127b154SDaniel Latypov 64a127b154SDaniel Latypov kunit_suite_for_each_test_case(suite, test_case) { 65a127b154SDaniel Latypov if (!test_glob || glob_match(test_glob, test_case->name)) 66a127b154SDaniel Latypov ++n; 67a127b154SDaniel Latypov } 68a127b154SDaniel Latypov 69a127b154SDaniel Latypov if (n == 0) 70a127b154SDaniel Latypov return NULL; 71a127b154SDaniel Latypov 72*d2fbdde8SDaniel Latypov copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL); 73a02353f4SDaniel Latypov if (!copy) 74a02353f4SDaniel Latypov return ERR_PTR(-ENOMEM); 75a127b154SDaniel Latypov 76a127b154SDaniel Latypov filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 77a02353f4SDaniel Latypov if (!filtered) 78a02353f4SDaniel Latypov return ERR_PTR(-ENOMEM); 79a127b154SDaniel Latypov 80a127b154SDaniel Latypov n = 0; 81a127b154SDaniel Latypov kunit_suite_for_each_test_case(suite, test_case) { 82a127b154SDaniel Latypov if (!test_glob || glob_match(test_glob, test_case->name)) 83a127b154SDaniel Latypov filtered[n++] = *test_case; 84a127b154SDaniel Latypov } 85a127b154SDaniel Latypov 86a127b154SDaniel Latypov copy->test_cases = filtered; 87a127b154SDaniel Latypov return copy; 88a127b154SDaniel Latypov } 895d31f71eSDaniel Latypov 90b6d5799bSDavid Gow static char *kunit_shutdown; 91b6d5799bSDavid Gow core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 92b6d5799bSDavid Gow 935d31f71eSDaniel Latypov static struct kunit_suite * const * 941d71307aSDaniel Latypov kunit_filter_subsuite(struct kunit_suite * const * const subsuite, 95a127b154SDaniel Latypov struct kunit_test_filter *filter) 965d31f71eSDaniel Latypov { 975d31f71eSDaniel Latypov int i, n = 0; 98a127b154SDaniel Latypov struct kunit_suite **filtered, *filtered_suite; 995d31f71eSDaniel Latypov 1005d31f71eSDaniel Latypov n = 0; 101a127b154SDaniel Latypov for (i = 0; subsuite[i]; ++i) { 102a127b154SDaniel Latypov if (glob_match(filter->suite_glob, subsuite[i]->name)) 1035d31f71eSDaniel Latypov ++n; 1045d31f71eSDaniel Latypov } 1055d31f71eSDaniel Latypov 1065d31f71eSDaniel Latypov if (n == 0) 1075d31f71eSDaniel Latypov return NULL; 1085d31f71eSDaniel Latypov 1095d31f71eSDaniel Latypov filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL); 1105d31f71eSDaniel Latypov if (!filtered) 111a02353f4SDaniel Latypov return ERR_PTR(-ENOMEM); 1125d31f71eSDaniel Latypov 1135d31f71eSDaniel Latypov n = 0; 1145d31f71eSDaniel Latypov for (i = 0; subsuite[i] != NULL; ++i) { 115a127b154SDaniel Latypov if (!glob_match(filter->suite_glob, subsuite[i]->name)) 116a127b154SDaniel Latypov continue; 117a127b154SDaniel Latypov filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob); 118a02353f4SDaniel Latypov if (IS_ERR(filtered_suite)) 119a02353f4SDaniel Latypov return ERR_CAST(filtered_suite); 120a02353f4SDaniel Latypov else if (filtered_suite) 121a127b154SDaniel Latypov filtered[n++] = filtered_suite; 1225d31f71eSDaniel Latypov } 1235d31f71eSDaniel Latypov filtered[n] = NULL; 1245d31f71eSDaniel Latypov 1255d31f71eSDaniel Latypov return filtered; 1265d31f71eSDaniel Latypov } 1275d31f71eSDaniel Latypov 1285d31f71eSDaniel Latypov struct suite_set { 1295d31f71eSDaniel Latypov struct kunit_suite * const * const *start; 1305d31f71eSDaniel Latypov struct kunit_suite * const * const *end; 1315d31f71eSDaniel Latypov }; 1325d31f71eSDaniel Latypov 133a127b154SDaniel Latypov static void kunit_free_subsuite(struct kunit_suite * const *subsuite) 134a127b154SDaniel Latypov { 135a127b154SDaniel Latypov unsigned int i; 136a127b154SDaniel Latypov 137a127b154SDaniel Latypov for (i = 0; subsuite[i]; i++) 138a127b154SDaniel Latypov kfree(subsuite[i]); 139a127b154SDaniel Latypov 140a127b154SDaniel Latypov kfree(subsuite); 141a127b154SDaniel Latypov } 142a127b154SDaniel Latypov 143a127b154SDaniel Latypov static void kunit_free_suite_set(struct suite_set suite_set) 144a127b154SDaniel Latypov { 145a127b154SDaniel Latypov struct kunit_suite * const * const *suites; 146a127b154SDaniel Latypov 147a127b154SDaniel Latypov for (suites = suite_set.start; suites < suite_set.end; suites++) 148a127b154SDaniel Latypov kunit_free_subsuite(*suites); 149a127b154SDaniel Latypov kfree(suite_set.start); 150a127b154SDaniel Latypov } 151a127b154SDaniel Latypov 1521d71307aSDaniel Latypov static struct suite_set kunit_filter_suites(const struct suite_set *suite_set, 153a02353f4SDaniel Latypov const char *filter_glob, 154a02353f4SDaniel Latypov int *err) 1555d31f71eSDaniel Latypov { 1565d31f71eSDaniel Latypov int i; 1575d31f71eSDaniel Latypov struct kunit_suite * const **copy, * const *filtered_subsuite; 1585d31f71eSDaniel Latypov struct suite_set filtered; 159a127b154SDaniel Latypov struct kunit_test_filter filter; 1605d31f71eSDaniel Latypov 1611d71307aSDaniel Latypov const size_t max = suite_set->end - suite_set->start; 1625d31f71eSDaniel Latypov 1635d31f71eSDaniel Latypov copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 1645d31f71eSDaniel Latypov filtered.start = copy; 1655d31f71eSDaniel Latypov if (!copy) { /* won't be able to run anything, return an empty set */ 1665d31f71eSDaniel Latypov filtered.end = copy; 1675d31f71eSDaniel Latypov return filtered; 1685d31f71eSDaniel Latypov } 1695d31f71eSDaniel Latypov 170a127b154SDaniel Latypov kunit_parse_filter_glob(&filter, filter_glob); 171a127b154SDaniel Latypov 1725d31f71eSDaniel Latypov for (i = 0; i < max; ++i) { 173a127b154SDaniel Latypov filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter); 174a02353f4SDaniel Latypov if (IS_ERR(filtered_subsuite)) { 175a02353f4SDaniel Latypov *err = PTR_ERR(filtered_subsuite); 176a02353f4SDaniel Latypov return filtered; 177a02353f4SDaniel Latypov } 1785d31f71eSDaniel Latypov if (filtered_subsuite) 1795d31f71eSDaniel Latypov *copy++ = filtered_subsuite; 1805d31f71eSDaniel Latypov } 1815d31f71eSDaniel Latypov filtered.end = copy; 182a127b154SDaniel Latypov 183a127b154SDaniel Latypov kfree(filter.suite_glob); 184a127b154SDaniel Latypov kfree(filter.test_glob); 1855d31f71eSDaniel Latypov return filtered; 1865d31f71eSDaniel Latypov } 1875d31f71eSDaniel Latypov 188b6d5799bSDavid Gow static void kunit_handle_shutdown(void) 189b6d5799bSDavid Gow { 190b6d5799bSDavid Gow if (!kunit_shutdown) 191b6d5799bSDavid Gow return; 192b6d5799bSDavid Gow 193b6d5799bSDavid Gow if (!strcmp(kunit_shutdown, "poweroff")) 194b6d5799bSDavid Gow kernel_power_off(); 195b6d5799bSDavid Gow else if (!strcmp(kunit_shutdown, "halt")) 196b6d5799bSDavid Gow kernel_halt(); 197b6d5799bSDavid Gow else if (!strcmp(kunit_shutdown, "reboot")) 198b6d5799bSDavid Gow kernel_restart(NULL); 199b6d5799bSDavid Gow 200b6d5799bSDavid Gow } 201b6d5799bSDavid Gow 2025d31f71eSDaniel Latypov static void kunit_print_tap_header(struct suite_set *suite_set) 20345dcbb6fSBrendan Higgins { 20445dcbb6fSBrendan Higgins struct kunit_suite * const * const *suites, * const *subsuite; 20545dcbb6fSBrendan Higgins int num_of_suites = 0; 20645dcbb6fSBrendan Higgins 2075d31f71eSDaniel Latypov for (suites = suite_set->start; suites < suite_set->end; suites++) 20845dcbb6fSBrendan Higgins for (subsuite = *suites; *subsuite != NULL; subsuite++) 20945dcbb6fSBrendan Higgins num_of_suites++; 21045dcbb6fSBrendan Higgins 21145dcbb6fSBrendan Higgins pr_info("TAP version 14\n"); 21245dcbb6fSBrendan Higgins pr_info("1..%d\n", num_of_suites); 21345dcbb6fSBrendan Higgins } 21445dcbb6fSBrendan Higgins 2159c6b0e1dSDaniel Latypov static void kunit_exec_run_tests(struct suite_set *suite_set) 216aac35468SAlan Maguire { 217aac35468SAlan Maguire struct kunit_suite * const * const *suites; 2189c6b0e1dSDaniel Latypov 2199c6b0e1dSDaniel Latypov kunit_print_tap_header(suite_set); 2209c6b0e1dSDaniel Latypov 2219c6b0e1dSDaniel Latypov for (suites = suite_set->start; suites < suite_set->end; suites++) 2229c6b0e1dSDaniel Latypov __kunit_test_suites_init(*suites); 2239c6b0e1dSDaniel Latypov } 2249c6b0e1dSDaniel Latypov 2259c6b0e1dSDaniel Latypov static void kunit_exec_list_tests(struct suite_set *suite_set) 2269c6b0e1dSDaniel Latypov { 2279c6b0e1dSDaniel Latypov unsigned int i; 2289c6b0e1dSDaniel Latypov struct kunit_suite * const * const *suites; 2299c6b0e1dSDaniel Latypov struct kunit_case *test_case; 2309c6b0e1dSDaniel Latypov 2319c6b0e1dSDaniel Latypov /* Hack: print a tap header so kunit.py can find the start of KUnit output. */ 2329c6b0e1dSDaniel Latypov pr_info("TAP version 14\n"); 2339c6b0e1dSDaniel Latypov 2349c6b0e1dSDaniel Latypov for (suites = suite_set->start; suites < suite_set->end; suites++) 2359c6b0e1dSDaniel Latypov for (i = 0; (*suites)[i] != NULL; i++) { 2369c6b0e1dSDaniel Latypov kunit_suite_for_each_test_case((*suites)[i], test_case) { 2379c6b0e1dSDaniel Latypov pr_info("%s.%s\n", (*suites)[i]->name, test_case->name); 2389c6b0e1dSDaniel Latypov } 2399c6b0e1dSDaniel Latypov } 2409c6b0e1dSDaniel Latypov } 2419c6b0e1dSDaniel Latypov 2429c6b0e1dSDaniel Latypov int kunit_run_all_tests(void) 2439c6b0e1dSDaniel Latypov { 2441d71307aSDaniel Latypov struct suite_set suite_set = { 2451d71307aSDaniel Latypov .start = __kunit_suites_start, 2461d71307aSDaniel Latypov .end = __kunit_suites_end, 2471d71307aSDaniel Latypov }; 2481b11063dSDaniel Latypov int err = 0; 249aac35468SAlan Maguire 250a02353f4SDaniel Latypov if (filter_glob_param) { 251a02353f4SDaniel Latypov suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err); 252a02353f4SDaniel Latypov if (err) { 253a02353f4SDaniel Latypov pr_err("kunit executor: error filtering suites: %d\n", err); 2541b11063dSDaniel Latypov goto out; 255a02353f4SDaniel Latypov } 256a02353f4SDaniel Latypov } 25745dcbb6fSBrendan Higgins 2589c6b0e1dSDaniel Latypov if (!action_param) 2599c6b0e1dSDaniel Latypov kunit_exec_run_tests(&suite_set); 2609c6b0e1dSDaniel Latypov else if (strcmp(action_param, "list") == 0) 2619c6b0e1dSDaniel Latypov kunit_exec_list_tests(&suite_set); 2629c6b0e1dSDaniel Latypov else 2639c6b0e1dSDaniel Latypov pr_err("kunit executor: unknown action '%s'\n", action_param); 264aac35468SAlan Maguire 2651d71307aSDaniel Latypov if (filter_glob_param) { /* a copy was made of each array */ 266a127b154SDaniel Latypov kunit_free_suite_set(suite_set); 2675d31f71eSDaniel Latypov } 2685d31f71eSDaniel Latypov 269b6d5799bSDavid Gow 2701b11063dSDaniel Latypov out: 2711b11063dSDaniel Latypov kunit_handle_shutdown(); 2721b11063dSDaniel Latypov return err; 273aac35468SAlan Maguire } 274aac35468SAlan Maguire 2751d71307aSDaniel Latypov #if IS_BUILTIN(CONFIG_KUNIT_TEST) 2761d71307aSDaniel Latypov #include "executor_test.c" 2771d71307aSDaniel Latypov #endif 2781d71307aSDaniel Latypov 279aac35468SAlan Maguire #endif /* IS_BUILTIN(CONFIG_KUNIT) */ 280