Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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 __kunit_suites_start[];
 13extern struct kunit_suite * 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(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		kfree(copy);
 79		return ERR_PTR(-ENOMEM);
 80	}
 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
 95/* Stores an array of suites, end points one past the end */
 96struct suite_set {
 97	struct kunit_suite * const *start;
 98	struct kunit_suite * const *end;
 99};
100
101static void kunit_free_suite_set(struct suite_set suite_set)
102{
103	struct kunit_suite * const *suites;
104
105	for (suites = suite_set.start; suites < suite_set.end; suites++)
106		kfree(*suites);
107	kfree(suite_set.start);
108}
109
110static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
111					    const char *filter_glob,
112					    int *err)
113{
114	int i;
115	struct kunit_suite **copy, *filtered_suite;
116	struct suite_set filtered;
117	struct kunit_test_filter filter;
118
119	const size_t max = suite_set->end - suite_set->start;
120
121	copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
122	filtered.start = copy;
123	if (!copy) { /* won't be able to run anything, return an empty set */
124		filtered.end = copy;
125		return filtered;
126	}
127
128	kunit_parse_filter_glob(&filter, filter_glob);
129
130	for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
131		if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
132			continue;
133
134		filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
135		if (IS_ERR(filtered_suite)) {
136			*err = PTR_ERR(filtered_suite);
137			return filtered;
138		}
139		if (!filtered_suite)
140			continue;
141
142		*copy++ = filtered_suite;
143	}
144	filtered.end = copy;
145
146	kfree(filter.suite_glob);
147	kfree(filter.test_glob);
148	return filtered;
149}
150
151static void kunit_handle_shutdown(void)
152{
153	if (!kunit_shutdown)
154		return;
155
156	if (!strcmp(kunit_shutdown, "poweroff"))
157		kernel_power_off();
158	else if (!strcmp(kunit_shutdown, "halt"))
159		kernel_halt();
160	else if (!strcmp(kunit_shutdown, "reboot"))
161		kernel_restart(NULL);
162
163}
164
165static void kunit_exec_run_tests(struct suite_set *suite_set)
166{
167	size_t num_suites = suite_set->end - suite_set->start;
168
169	pr_info("KTAP version 1\n");
170	pr_info("1..%zu\n", num_suites);
171
172	__kunit_test_suites_init(suite_set->start, num_suites);
173}
174
175static void kunit_exec_list_tests(struct suite_set *suite_set)
176{
177	struct kunit_suite * const *suites;
178	struct kunit_case *test_case;
179
180	/* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
181	pr_info("KTAP version 1\n");
182
183	for (suites = suite_set->start; suites < suite_set->end; suites++)
184		kunit_suite_for_each_test_case((*suites), test_case) {
185			pr_info("%s.%s\n", (*suites)->name, test_case->name);
186		}
187}
188
189int kunit_run_all_tests(void)
190{
191	struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
192	int err = 0;
193	if (!kunit_enabled()) {
194		pr_info("kunit: disabled\n");
195		goto out;
196	}
197
198	if (filter_glob_param) {
199		suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
200		if (err) {
201			pr_err("kunit executor: error filtering suites: %d\n", err);
202			goto out;
203		}
204	}
205
206	if (!action_param)
207		kunit_exec_run_tests(&suite_set);
208	else if (strcmp(action_param, "list") == 0)
209		kunit_exec_list_tests(&suite_set);
210	else
211		pr_err("kunit executor: unknown action '%s'\n", action_param);
212
213	if (filter_glob_param) { /* a copy was made of each suite */
214		kunit_free_suite_set(suite_set);
215	}
216
217out:
218	kunit_handle_shutdown();
219	return err;
220}
221
222#if IS_BUILTIN(CONFIG_KUNIT_TEST)
223#include "executor_test.c"
224#endif
225
226#endif /* IS_BUILTIN(CONFIG_KUNIT) */