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; 181d71307aSDaniel Latypov module_param_named(filter_glob, filter_glob_param, charp, 0); 195d31f71eSDaniel Latypov MODULE_PARM_DESC(filter_glob, 20a127b154SDaniel Latypov "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 21a127b154SDaniel Latypov 22a127b154SDaniel Latypov /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */ 23a127b154SDaniel Latypov struct kunit_test_filter { 24a127b154SDaniel Latypov char *suite_glob; 25a127b154SDaniel Latypov char *test_glob; 26a127b154SDaniel Latypov }; 27a127b154SDaniel Latypov 28a127b154SDaniel Latypov /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */ 29a127b154SDaniel Latypov static void kunit_parse_filter_glob(struct kunit_test_filter *parsed, 30a127b154SDaniel Latypov const char *filter_glob) 31a127b154SDaniel Latypov { 32a127b154SDaniel Latypov const int len = strlen(filter_glob); 33a127b154SDaniel Latypov const char *period = strchr(filter_glob, '.'); 34a127b154SDaniel Latypov 35a127b154SDaniel Latypov if (!period) { 36*cd94fbc2SDaniel Latypov parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL); 37a127b154SDaniel Latypov parsed->test_glob = NULL; 38a127b154SDaniel Latypov strcpy(parsed->suite_glob, filter_glob); 39a127b154SDaniel Latypov return; 40a127b154SDaniel Latypov } 41a127b154SDaniel Latypov 42a127b154SDaniel Latypov parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL); 43a127b154SDaniel Latypov parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL); 44a127b154SDaniel Latypov 45a127b154SDaniel Latypov strncpy(parsed->suite_glob, filter_glob, period - filter_glob); 46a127b154SDaniel Latypov strncpy(parsed->test_glob, period + 1, len - (period - filter_glob)); 47a127b154SDaniel Latypov } 48a127b154SDaniel Latypov 49a127b154SDaniel Latypov /* Create a copy of suite with only tests that match test_glob. */ 50a127b154SDaniel Latypov static struct kunit_suite * 51a127b154SDaniel Latypov kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob) 52a127b154SDaniel Latypov { 53a127b154SDaniel Latypov int n = 0; 54a127b154SDaniel Latypov struct kunit_case *filtered, *test_case; 55a127b154SDaniel Latypov struct kunit_suite *copy; 56a127b154SDaniel Latypov 57a127b154SDaniel Latypov kunit_suite_for_each_test_case(suite, test_case) { 58a127b154SDaniel Latypov if (!test_glob || glob_match(test_glob, test_case->name)) 59a127b154SDaniel Latypov ++n; 60a127b154SDaniel Latypov } 61a127b154SDaniel Latypov 62a127b154SDaniel Latypov if (n == 0) 63a127b154SDaniel Latypov return NULL; 64a127b154SDaniel Latypov 65a127b154SDaniel Latypov /* Use memcpy to workaround copy->name being const. */ 66a127b154SDaniel Latypov copy = kmalloc(sizeof(*copy), GFP_KERNEL); 67a127b154SDaniel Latypov memcpy(copy, suite, sizeof(*copy)); 68a127b154SDaniel Latypov 69a127b154SDaniel Latypov filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 70a127b154SDaniel Latypov 71a127b154SDaniel Latypov n = 0; 72a127b154SDaniel Latypov kunit_suite_for_each_test_case(suite, test_case) { 73a127b154SDaniel Latypov if (!test_glob || glob_match(test_glob, test_case->name)) 74a127b154SDaniel Latypov filtered[n++] = *test_case; 75a127b154SDaniel Latypov } 76a127b154SDaniel Latypov 77a127b154SDaniel Latypov copy->test_cases = filtered; 78a127b154SDaniel Latypov return copy; 79a127b154SDaniel Latypov } 805d31f71eSDaniel Latypov 81b6d5799bSDavid Gow static char *kunit_shutdown; 82b6d5799bSDavid Gow core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 83b6d5799bSDavid Gow 845d31f71eSDaniel Latypov static struct kunit_suite * const * 851d71307aSDaniel Latypov kunit_filter_subsuite(struct kunit_suite * const * const subsuite, 86a127b154SDaniel Latypov struct kunit_test_filter *filter) 875d31f71eSDaniel Latypov { 885d31f71eSDaniel Latypov int i, n = 0; 89a127b154SDaniel Latypov struct kunit_suite **filtered, *filtered_suite; 905d31f71eSDaniel Latypov 915d31f71eSDaniel Latypov n = 0; 92a127b154SDaniel Latypov for (i = 0; subsuite[i]; ++i) { 93a127b154SDaniel Latypov if (glob_match(filter->suite_glob, subsuite[i]->name)) 945d31f71eSDaniel Latypov ++n; 955d31f71eSDaniel Latypov } 965d31f71eSDaniel Latypov 975d31f71eSDaniel Latypov if (n == 0) 985d31f71eSDaniel Latypov return NULL; 995d31f71eSDaniel Latypov 1005d31f71eSDaniel Latypov filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL); 1015d31f71eSDaniel Latypov if (!filtered) 1025d31f71eSDaniel Latypov return NULL; 1035d31f71eSDaniel Latypov 1045d31f71eSDaniel Latypov n = 0; 1055d31f71eSDaniel Latypov for (i = 0; subsuite[i] != NULL; ++i) { 106a127b154SDaniel Latypov if (!glob_match(filter->suite_glob, subsuite[i]->name)) 107a127b154SDaniel Latypov continue; 108a127b154SDaniel Latypov filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob); 109a127b154SDaniel Latypov if (filtered_suite) 110a127b154SDaniel Latypov filtered[n++] = filtered_suite; 1115d31f71eSDaniel Latypov } 1125d31f71eSDaniel Latypov filtered[n] = NULL; 1135d31f71eSDaniel Latypov 1145d31f71eSDaniel Latypov return filtered; 1155d31f71eSDaniel Latypov } 1165d31f71eSDaniel Latypov 1175d31f71eSDaniel Latypov struct suite_set { 1185d31f71eSDaniel Latypov struct kunit_suite * const * const *start; 1195d31f71eSDaniel Latypov struct kunit_suite * const * const *end; 1205d31f71eSDaniel Latypov }; 1215d31f71eSDaniel Latypov 122a127b154SDaniel Latypov static void kunit_free_subsuite(struct kunit_suite * const *subsuite) 123a127b154SDaniel Latypov { 124a127b154SDaniel Latypov unsigned int i; 125a127b154SDaniel Latypov 126a127b154SDaniel Latypov for (i = 0; subsuite[i]; i++) 127a127b154SDaniel Latypov kfree(subsuite[i]); 128a127b154SDaniel Latypov 129a127b154SDaniel Latypov kfree(subsuite); 130a127b154SDaniel Latypov } 131a127b154SDaniel Latypov 132a127b154SDaniel Latypov static void kunit_free_suite_set(struct suite_set suite_set) 133a127b154SDaniel Latypov { 134a127b154SDaniel Latypov struct kunit_suite * const * const *suites; 135a127b154SDaniel Latypov 136a127b154SDaniel Latypov for (suites = suite_set.start; suites < suite_set.end; suites++) 137a127b154SDaniel Latypov kunit_free_subsuite(*suites); 138a127b154SDaniel Latypov kfree(suite_set.start); 139a127b154SDaniel Latypov } 140a127b154SDaniel Latypov 1411d71307aSDaniel Latypov static struct suite_set kunit_filter_suites(const struct suite_set *suite_set, 1421d71307aSDaniel Latypov const char *filter_glob) 1435d31f71eSDaniel Latypov { 1445d31f71eSDaniel Latypov int i; 1455d31f71eSDaniel Latypov struct kunit_suite * const **copy, * const *filtered_subsuite; 1465d31f71eSDaniel Latypov struct suite_set filtered; 147a127b154SDaniel Latypov struct kunit_test_filter filter; 1485d31f71eSDaniel Latypov 1491d71307aSDaniel Latypov const size_t max = suite_set->end - suite_set->start; 1505d31f71eSDaniel Latypov 1515d31f71eSDaniel Latypov copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 1525d31f71eSDaniel Latypov filtered.start = copy; 1535d31f71eSDaniel Latypov if (!copy) { /* won't be able to run anything, return an empty set */ 1545d31f71eSDaniel Latypov filtered.end = copy; 1555d31f71eSDaniel Latypov return filtered; 1565d31f71eSDaniel Latypov } 1575d31f71eSDaniel Latypov 158a127b154SDaniel Latypov kunit_parse_filter_glob(&filter, filter_glob); 159a127b154SDaniel Latypov 1605d31f71eSDaniel Latypov for (i = 0; i < max; ++i) { 161a127b154SDaniel Latypov filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter); 1625d31f71eSDaniel Latypov if (filtered_subsuite) 1635d31f71eSDaniel Latypov *copy++ = filtered_subsuite; 1645d31f71eSDaniel Latypov } 1655d31f71eSDaniel Latypov filtered.end = copy; 166a127b154SDaniel Latypov 167a127b154SDaniel Latypov kfree(filter.suite_glob); 168a127b154SDaniel Latypov kfree(filter.test_glob); 1695d31f71eSDaniel Latypov return filtered; 1705d31f71eSDaniel Latypov } 1715d31f71eSDaniel Latypov 172b6d5799bSDavid Gow static void kunit_handle_shutdown(void) 173b6d5799bSDavid Gow { 174b6d5799bSDavid Gow if (!kunit_shutdown) 175b6d5799bSDavid Gow return; 176b6d5799bSDavid Gow 177b6d5799bSDavid Gow if (!strcmp(kunit_shutdown, "poweroff")) 178b6d5799bSDavid Gow kernel_power_off(); 179b6d5799bSDavid Gow else if (!strcmp(kunit_shutdown, "halt")) 180b6d5799bSDavid Gow kernel_halt(); 181b6d5799bSDavid Gow else if (!strcmp(kunit_shutdown, "reboot")) 182b6d5799bSDavid Gow kernel_restart(NULL); 183b6d5799bSDavid Gow 184b6d5799bSDavid Gow } 185b6d5799bSDavid Gow 1865d31f71eSDaniel Latypov static void kunit_print_tap_header(struct suite_set *suite_set) 18745dcbb6fSBrendan Higgins { 18845dcbb6fSBrendan Higgins struct kunit_suite * const * const *suites, * const *subsuite; 18945dcbb6fSBrendan Higgins int num_of_suites = 0; 19045dcbb6fSBrendan Higgins 1915d31f71eSDaniel Latypov for (suites = suite_set->start; suites < suite_set->end; suites++) 19245dcbb6fSBrendan Higgins for (subsuite = *suites; *subsuite != NULL; subsuite++) 19345dcbb6fSBrendan Higgins num_of_suites++; 19445dcbb6fSBrendan Higgins 19545dcbb6fSBrendan Higgins pr_info("TAP version 14\n"); 19645dcbb6fSBrendan Higgins pr_info("1..%d\n", num_of_suites); 19745dcbb6fSBrendan Higgins } 19845dcbb6fSBrendan Higgins 1998c0d8849SBrendan Higgins int kunit_run_all_tests(void) 200aac35468SAlan Maguire { 201aac35468SAlan Maguire struct kunit_suite * const * const *suites; 2021d71307aSDaniel Latypov struct suite_set suite_set = { 2031d71307aSDaniel Latypov .start = __kunit_suites_start, 2041d71307aSDaniel Latypov .end = __kunit_suites_end, 2051d71307aSDaniel Latypov }; 206aac35468SAlan Maguire 2071d71307aSDaniel Latypov if (filter_glob_param) 2081d71307aSDaniel Latypov suite_set = kunit_filter_suites(&suite_set, filter_glob_param); 20945dcbb6fSBrendan Higgins 2105d31f71eSDaniel Latypov kunit_print_tap_header(&suite_set); 2115d31f71eSDaniel Latypov 2125d31f71eSDaniel Latypov for (suites = suite_set.start; suites < suite_set.end; suites++) 213aac35468SAlan Maguire __kunit_test_suites_init(*suites); 214aac35468SAlan Maguire 2151d71307aSDaniel Latypov if (filter_glob_param) { /* a copy was made of each array */ 216a127b154SDaniel Latypov kunit_free_suite_set(suite_set); 2175d31f71eSDaniel Latypov } 2185d31f71eSDaniel Latypov 219b6d5799bSDavid Gow kunit_handle_shutdown(); 220b6d5799bSDavid Gow 221aac35468SAlan Maguire return 0; 222aac35468SAlan Maguire } 223aac35468SAlan Maguire 2241d71307aSDaniel Latypov #if IS_BUILTIN(CONFIG_KUNIT_TEST) 2251d71307aSDaniel Latypov #include "executor_test.c" 2261d71307aSDaniel Latypov #endif 2271d71307aSDaniel Latypov 228aac35468SAlan Maguire #endif /* IS_BUILTIN(CONFIG_KUNIT) */ 229