Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <linux/reboot.h>
0004 #include <kunit/test.h>
0005 #include <linux/glob.h>
0006 #include <linux/moduleparam.h>
0007 
0008 /*
0009  * These symbols point to the .kunit_test_suites section and are defined in
0010  * include/asm-generic/vmlinux.lds.h, and consequently must be extern.
0011  */
0012 extern struct kunit_suite * const __kunit_suites_start[];
0013 extern struct kunit_suite * const __kunit_suites_end[];
0014 
0015 #if IS_BUILTIN(CONFIG_KUNIT)
0016 
0017 static char *filter_glob_param;
0018 static char *action_param;
0019 
0020 module_param_named(filter_glob, filter_glob_param, charp, 0);
0021 MODULE_PARM_DESC(filter_glob,
0022         "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test");
0023 module_param_named(action, action_param, charp, 0);
0024 MODULE_PARM_DESC(action,
0025          "Changes KUnit executor behavior, valid values are:\n"
0026          "<none>: run the tests like normal\n"
0027          "'list' to list test names instead of running them.\n");
0028 
0029 /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
0030 struct kunit_test_filter {
0031     char *suite_glob;
0032     char *test_glob;
0033 };
0034 
0035 /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
0036 static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
0037                     const char *filter_glob)
0038 {
0039     const int len = strlen(filter_glob);
0040     const char *period = strchr(filter_glob, '.');
0041 
0042     if (!period) {
0043         parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL);
0044         parsed->test_glob = NULL;
0045         strcpy(parsed->suite_glob, filter_glob);
0046         return;
0047     }
0048 
0049     parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL);
0050     parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL);
0051 
0052     strncpy(parsed->suite_glob, filter_glob, period - filter_glob);
0053     strncpy(parsed->test_glob, period + 1, len - (period - filter_glob));
0054 }
0055 
0056 /* Create a copy of suite with only tests that match test_glob. */
0057 static struct kunit_suite *
0058 kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
0059 {
0060     int n = 0;
0061     struct kunit_case *filtered, *test_case;
0062     struct kunit_suite *copy;
0063 
0064     kunit_suite_for_each_test_case(suite, test_case) {
0065         if (!test_glob || glob_match(test_glob, test_case->name))
0066             ++n;
0067     }
0068 
0069     if (n == 0)
0070         return NULL;
0071 
0072     copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL);
0073     if (!copy)
0074         return ERR_PTR(-ENOMEM);
0075 
0076     filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
0077     if (!filtered) {
0078         kfree(copy);
0079         return ERR_PTR(-ENOMEM);
0080     }
0081 
0082     n = 0;
0083     kunit_suite_for_each_test_case(suite, test_case) {
0084         if (!test_glob || glob_match(test_glob, test_case->name))
0085             filtered[n++] = *test_case;
0086     }
0087 
0088     copy->test_cases = filtered;
0089     return copy;
0090 }
0091 
0092 static char *kunit_shutdown;
0093 core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
0094 
0095 /* Stores an array of suites, end points one past the end */
0096 struct suite_set {
0097     struct kunit_suite * const *start;
0098     struct kunit_suite * const *end;
0099 };
0100 
0101 static void kunit_free_suite_set(struct suite_set suite_set)
0102 {
0103     struct kunit_suite * const *suites;
0104 
0105     for (suites = suite_set.start; suites < suite_set.end; suites++)
0106         kfree(*suites);
0107     kfree(suite_set.start);
0108 }
0109 
0110 static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
0111                         const char *filter_glob,
0112                         int *err)
0113 {
0114     int i;
0115     struct kunit_suite **copy, *filtered_suite;
0116     struct suite_set filtered;
0117     struct kunit_test_filter filter;
0118 
0119     const size_t max = suite_set->end - suite_set->start;
0120 
0121     copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
0122     filtered.start = copy;
0123     if (!copy) { /* won't be able to run anything, return an empty set */
0124         filtered.end = copy;
0125         return filtered;
0126     }
0127 
0128     kunit_parse_filter_glob(&filter, filter_glob);
0129 
0130     for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
0131         if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
0132             continue;
0133 
0134         filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
0135         if (IS_ERR(filtered_suite)) {
0136             *err = PTR_ERR(filtered_suite);
0137             return filtered;
0138         }
0139         if (!filtered_suite)
0140             continue;
0141 
0142         *copy++ = filtered_suite;
0143     }
0144     filtered.end = copy;
0145 
0146     kfree(filter.suite_glob);
0147     kfree(filter.test_glob);
0148     return filtered;
0149 }
0150 
0151 static void kunit_handle_shutdown(void)
0152 {
0153     if (!kunit_shutdown)
0154         return;
0155 
0156     if (!strcmp(kunit_shutdown, "poweroff"))
0157         kernel_power_off();
0158     else if (!strcmp(kunit_shutdown, "halt"))
0159         kernel_halt();
0160     else if (!strcmp(kunit_shutdown, "reboot"))
0161         kernel_restart(NULL);
0162 
0163 }
0164 
0165 static void kunit_exec_run_tests(struct suite_set *suite_set)
0166 {
0167     size_t num_suites = suite_set->end - suite_set->start;
0168 
0169     pr_info("TAP version 14\n");
0170     pr_info("1..%zu\n", num_suites);
0171 
0172     __kunit_test_suites_init(suite_set->start, num_suites);
0173 }
0174 
0175 static void kunit_exec_list_tests(struct suite_set *suite_set)
0176 {
0177     struct kunit_suite * const *suites;
0178     struct kunit_case *test_case;
0179 
0180     /* Hack: print a tap header so kunit.py can find the start of KUnit output. */
0181     pr_info("TAP version 14\n");
0182 
0183     for (suites = suite_set->start; suites < suite_set->end; suites++)
0184         kunit_suite_for_each_test_case((*suites), test_case) {
0185             pr_info("%s.%s\n", (*suites)->name, test_case->name);
0186         }
0187 }
0188 
0189 int kunit_run_all_tests(void)
0190 {
0191     struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
0192     int err = 0;
0193 
0194     if (filter_glob_param) {
0195         suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
0196         if (err) {
0197             pr_err("kunit executor: error filtering suites: %d\n", err);
0198             goto out;
0199         }
0200     }
0201 
0202     if (!action_param)
0203         kunit_exec_run_tests(&suite_set);
0204     else if (strcmp(action_param, "list") == 0)
0205         kunit_exec_list_tests(&suite_set);
0206     else
0207         pr_err("kunit executor: unknown action '%s'\n", action_param);
0208 
0209     if (filter_glob_param) { /* a copy was made of each suite */
0210         kunit_free_suite_set(suite_set);
0211     }
0212 
0213 out:
0214     kunit_handle_shutdown();
0215     return err;
0216 }
0217 
0218 #if IS_BUILTIN(CONFIG_KUNIT_TEST)
0219 #include "executor_test.c"
0220 #endif
0221 
0222 #endif /* IS_BUILTIN(CONFIG_KUNIT) */