Skip to content

Commit 313b6ff

Browse files
committed
Merge tag 'linux-kselftest-kunit-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull KUnit updates from Shuah Khan: "Several enhancements and fixes: - ability to run each test suite and test separately - support for timing test run - several fixes and improvements" * tag 'linux-kselftest-kunit-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: tool: fix typecheck errors about loading qemu configs kunit: tool: continue past invalid utf-8 output kunit: Reset suite count after running tests kunit: tool: improve compatibility of kunit_parser with KTAP specification kunit: tool: yield output from run_kernel in real time kunit: tool: support running each suite/test separately kunit: tool: actually track how long it took to run tests kunit: tool: factor exec + parse steps into a function kunit: add 'kunit.action' param to allow listing out tests kunit: tool: show list of valid --arch options when invalid kunit: tool: misc fixes (unused vars, imports, leaked files) kunit: fix too small allocation when using suite-only kunit.filter_glob kunit: tool: allow filtering test cases via glob kunit: drop assumption in kunit-log-test about current suite
2 parents 84924e2 + 52a5d80 commit 313b6ff

14 files changed

+1413
-518
lines changed

Documentation/dev-tools/kunit/running_tips.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ It can be handy to create a bash function like:
2525
Running a subset of tests
2626
-------------------------
2727

28-
``kunit.py run`` accepts an optional glob argument to filter tests. Currently
29-
this only matches against suite names, but this may change in the future.
28+
``kunit.py run`` accepts an optional glob argument to filter tests. The format
29+
is ``"<suite_glob>[.test_glob]"``.
3030

3131
Say that we wanted to run the sysctl tests, we could do so via:
3232

@@ -35,6 +35,13 @@ Say that we wanted to run the sysctl tests, we could do so via:
3535
$ echo -e 'CONFIG_KUNIT=y\nCONFIG_KUNIT_ALL_TESTS=y' > .kunit/.kunitconfig
3636
$ ./tools/testing/kunit/kunit.py run 'sysctl*'
3737
38+
We can filter down to just the "write" tests via:
39+
40+
.. code-block:: bash
41+
42+
$ echo -e 'CONFIG_KUNIT=y\nCONFIG_KUNIT_ALL_TESTS=y' > .kunit/.kunitconfig
43+
$ ./tools/testing/kunit/kunit.py run 'sysctl*.*write*'
44+
3845
We're paying the cost of building more tests than we need this way, but it's
3946
easier than fiddling with ``.kunitconfig`` files or commenting out
4047
``kunit_suite``'s.

lib/kunit/executor.c

Lines changed: 136 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,89 @@ extern struct kunit_suite * const * const __kunit_suites_end[];
1515
#if IS_BUILTIN(CONFIG_KUNIT)
1616

1717
static char *filter_glob_param;
18+
static char *action_param;
19+
1820
module_param_named(filter_glob, filter_glob_param, charp, 0);
1921
MODULE_PARM_DESC(filter_glob,
20-
"Filter which KUnit test suites run at boot-time, e.g. list*");
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(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+
/* Use memcpy to workaround copy->name being const. */
73+
copy = kmalloc(sizeof(*copy), GFP_KERNEL);
74+
memcpy(copy, suite, sizeof(*copy));
75+
76+
filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
77+
78+
n = 0;
79+
kunit_suite_for_each_test_case(suite, test_case) {
80+
if (!test_glob || glob_match(test_glob, test_case->name))
81+
filtered[n++] = *test_case;
82+
}
83+
84+
copy->test_cases = filtered;
85+
return copy;
86+
}
2187

2288
static char *kunit_shutdown;
2389
core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
2490

2591
static struct kunit_suite * const *
2692
kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
27-
const char *filter_glob)
93+
struct kunit_test_filter *filter)
2894
{
2995
int i, n = 0;
30-
struct kunit_suite **filtered;
96+
struct kunit_suite **filtered, *filtered_suite;
3197

3298
n = 0;
33-
for (i = 0; subsuite[i] != NULL; ++i) {
34-
if (glob_match(filter_glob, subsuite[i]->name))
99+
for (i = 0; subsuite[i]; ++i) {
100+
if (glob_match(filter->suite_glob, subsuite[i]->name))
35101
++n;
36102
}
37103

@@ -44,8 +110,11 @@ kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
44110

45111
n = 0;
46112
for (i = 0; subsuite[i] != NULL; ++i) {
47-
if (glob_match(filter_glob, subsuite[i]->name))
48-
filtered[n++] = subsuite[i];
113+
if (!glob_match(filter->suite_glob, subsuite[i]->name))
114+
continue;
115+
filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
116+
if (filtered_suite)
117+
filtered[n++] = filtered_suite;
49118
}
50119
filtered[n] = NULL;
51120

@@ -57,12 +126,32 @@ struct suite_set {
57126
struct kunit_suite * const * const *end;
58127
};
59128

129+
static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
130+
{
131+
unsigned int i;
132+
133+
for (i = 0; subsuite[i]; i++)
134+
kfree(subsuite[i]);
135+
136+
kfree(subsuite);
137+
}
138+
139+
static void kunit_free_suite_set(struct suite_set suite_set)
140+
{
141+
struct kunit_suite * const * const *suites;
142+
143+
for (suites = suite_set.start; suites < suite_set.end; suites++)
144+
kunit_free_subsuite(*suites);
145+
kfree(suite_set.start);
146+
}
147+
60148
static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
61149
const char *filter_glob)
62150
{
63151
int i;
64152
struct kunit_suite * const **copy, * const *filtered_subsuite;
65153
struct suite_set filtered;
154+
struct kunit_test_filter filter;
66155

67156
const size_t max = suite_set->end - suite_set->start;
68157

@@ -73,12 +162,17 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
73162
return filtered;
74163
}
75164

165+
kunit_parse_filter_glob(&filter, filter_glob);
166+
76167
for (i = 0; i < max; ++i) {
77-
filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], filter_glob);
168+
filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
78169
if (filtered_subsuite)
79170
*copy++ = filtered_subsuite;
80171
}
81172
filtered.end = copy;
173+
174+
kfree(filter.suite_glob);
175+
kfree(filter.test_glob);
82176
return filtered;
83177
}
84178

@@ -109,9 +203,35 @@ static void kunit_print_tap_header(struct suite_set *suite_set)
109203
pr_info("1..%d\n", num_of_suites);
110204
}
111205

112-
int kunit_run_all_tests(void)
206+
static void kunit_exec_run_tests(struct suite_set *suite_set)
207+
{
208+
struct kunit_suite * const * const *suites;
209+
210+
kunit_print_tap_header(suite_set);
211+
212+
for (suites = suite_set->start; suites < suite_set->end; suites++)
213+
__kunit_test_suites_init(*suites);
214+
}
215+
216+
static void kunit_exec_list_tests(struct suite_set *suite_set)
113217
{
218+
unsigned int i;
114219
struct kunit_suite * const * const *suites;
220+
struct kunit_case *test_case;
221+
222+
/* Hack: print a tap header so kunit.py can find the start of KUnit output. */
223+
pr_info("TAP version 14\n");
224+
225+
for (suites = suite_set->start; suites < suite_set->end; suites++)
226+
for (i = 0; (*suites)[i] != NULL; i++) {
227+
kunit_suite_for_each_test_case((*suites)[i], test_case) {
228+
pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
229+
}
230+
}
231+
}
232+
233+
int kunit_run_all_tests(void)
234+
{
115235
struct suite_set suite_set = {
116236
.start = __kunit_suites_start,
117237
.end = __kunit_suites_end,
@@ -120,15 +240,15 @@ int kunit_run_all_tests(void)
120240
if (filter_glob_param)
121241
suite_set = kunit_filter_suites(&suite_set, filter_glob_param);
122242

123-
kunit_print_tap_header(&suite_set);
124-
125-
for (suites = suite_set.start; suites < suite_set.end; suites++)
126-
__kunit_test_suites_init(*suites);
243+
if (!action_param)
244+
kunit_exec_run_tests(&suite_set);
245+
else if (strcmp(action_param, "list") == 0)
246+
kunit_exec_list_tests(&suite_set);
247+
else
248+
pr_err("kunit executor: unknown action '%s'\n", action_param);
127249

128250
if (filter_glob_param) { /* a copy was made of each array */
129-
for (suites = suite_set.start; suites < suite_set.end; suites++)
130-
kfree(*suites);
131-
kfree(suite_set.start);
251+
kunit_free_suite_set(suite_set);
132252
}
133253

134254
kunit_handle_shutdown();

0 commit comments

Comments
 (0)