Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: Allow kunit test modules to use test filtering

External tools, e.g., Intel GPU tools (IGT), support execution of
individual selftests provided by kernel modules. That could be also
applicable to kunit test modules if they provided test filtering. But
test filtering is now possible only when kunit code is built into the
kernel. Moreover, a filter can be specified only at boot time, then
reboot is required each time a different filter is needed.

Build the test filtering code also when kunit is configured as a module,
expose test filtering functions to other kunit source files, and use them
in kunit module notifier callback functions. Userspace can then reload
the kunit module with a value of the filter_glob parameter tuned to a
specific kunit test module every time it wants to limit the scope of tests
executed on that module load. Make the kunit.filter* parameters visible
in sysfs for user convenience.

v5: Refresh on tpp of attributes filtering fix
v4: Refresh on top of newly applied attributes patches and changes
introdced by new versions of other patches submitted in series with
this one.
v3: Fix CONFIG_GLOB, required by filtering functions, not selected when
building as a module (lkp@intel.com).
v2: Fix new name of a structure moved to kunit namespace not updated
across all uses (lkp@intel.com).

Signed-off-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Janusz Krzysztofik and committed by
Shuah Khan
b67abaad 18258c60

+66 -27
+11
include/kunit/test.h
··· 310 310 311 311 bool kunit_enabled(void); 312 312 const char *kunit_action(void); 313 + const char *kunit_filter_glob(void); 314 + char *kunit_filter(void); 315 + char *kunit_filter_action(void); 313 316 314 317 void kunit_init_test(struct kunit *test, const char *name, char *log); 315 318 ··· 322 319 323 320 unsigned int kunit_test_case_num(struct kunit_suite *suite, 324 321 struct kunit_case *test_case); 322 + 323 + struct kunit_suite_set 324 + kunit_filter_suites(const struct kunit_suite_set *suite_set, 325 + const char *filter_glob, 326 + char *filters, 327 + char *filter_action, 328 + int *err); 329 + void kunit_free_suite_set(struct kunit_suite_set suite_set); 325 330 326 331 int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites); 327 332
+1 -1
lib/kunit/Kconfig
··· 4 4 5 5 menuconfig KUNIT 6 6 tristate "KUnit - Enable support for unit tests" 7 - select GLOB if KUNIT=y 7 + select GLOB 8 8 help 9 9 Enables support for kernel unit tests (KUnit), a lightweight unit 10 10 testing and mocking framework for the Linux kernel. These tests are
+37 -26
lib/kunit/executor.c
··· 27 27 return action_param; 28 28 } 29 29 30 - #if IS_BUILTIN(CONFIG_KUNIT) 31 - 32 30 static char *filter_glob_param; 33 31 static char *filter_param; 34 32 static char *filter_action_param; 35 33 36 - module_param_named(filter_glob, filter_glob_param, charp, 0); 34 + module_param_named(filter_glob, filter_glob_param, charp, 0400); 37 35 MODULE_PARM_DESC(filter_glob, 38 36 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 39 - module_param_named(filter, filter_param, charp, 0); 37 + module_param_named(filter, filter_param, charp, 0400); 40 38 MODULE_PARM_DESC(filter, 41 39 "Filter which KUnit test suites/tests run at boot-time using attributes, e.g. speed>slow"); 42 - module_param_named(filter_action, filter_action_param, charp, 0); 40 + module_param_named(filter_action, filter_action_param, charp, 0400); 43 41 MODULE_PARM_DESC(filter_action, 44 42 "Changes behavior of filtered tests using attributes, valid values are:\n" 45 43 "<none>: do not run filtered tests as normal\n" 46 44 "'skip': skip all filtered tests instead so tests will appear in output\n"); 45 + 46 + const char *kunit_filter_glob(void) 47 + { 48 + return filter_glob_param; 49 + } 50 + 51 + char *kunit_filter(void) 52 + { 53 + return filter_param; 54 + } 55 + 56 + char *kunit_filter_action(void) 57 + { 58 + return filter_action_param; 59 + } 47 60 48 61 /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */ 49 62 struct kunit_glob_filter { ··· 121 108 return copy; 122 109 } 123 110 124 - static char *kunit_shutdown; 125 - core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 126 - 127 - static void kunit_free_suite_set(struct kunit_suite_set suite_set) 111 + void kunit_free_suite_set(struct kunit_suite_set suite_set) 128 112 { 129 113 struct kunit_suite * const *suites; 130 114 ··· 130 120 kfree(suite_set.start); 131 121 } 132 122 133 - static struct kunit_suite_set 123 + struct kunit_suite_set 134 124 kunit_filter_suites(const struct kunit_suite_set *suite_set, 135 125 const char *filter_glob, 136 126 char *filters, ··· 228 218 return filtered; 229 219 } 230 220 231 - static void kunit_handle_shutdown(void) 232 - { 233 - if (!kunit_shutdown) 234 - return; 235 - 236 - if (!strcmp(kunit_shutdown, "poweroff")) 237 - kernel_power_off(); 238 - else if (!strcmp(kunit_shutdown, "halt")) 239 - kernel_halt(); 240 - else if (!strcmp(kunit_shutdown, "reboot")) 241 - kernel_restart(NULL); 242 - 243 - } 244 - 245 - #endif 246 - 247 221 void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin) 248 222 { 249 223 size_t num_suites = suite_set->end - suite_set->start; ··· 264 270 } 265 271 266 272 #if IS_BUILTIN(CONFIG_KUNIT) 273 + 274 + static char *kunit_shutdown; 275 + core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 276 + 277 + static void kunit_handle_shutdown(void) 278 + { 279 + if (!kunit_shutdown) 280 + return; 281 + 282 + if (!strcmp(kunit_shutdown, "poweroff")) 283 + kernel_power_off(); 284 + else if (!strcmp(kunit_shutdown, "halt")) 285 + kernel_halt(); 286 + else if (!strcmp(kunit_shutdown, "reboot")) 287 + kernel_restart(NULL); 288 + 289 + } 267 290 268 291 int kunit_run_all_tests(void) 269 292 {
+17
lib/kunit/test.c
··· 740 740 mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites, 741 741 }; 742 742 const char *action = kunit_action(); 743 + int err = 0; 744 + 745 + suite_set = kunit_filter_suites(&suite_set, 746 + kunit_filter_glob() ?: "*.*", 747 + kunit_filter(), kunit_filter_action(), 748 + &err); 749 + if (err) 750 + pr_err("kunit module: error filtering suites: %d\n", err); 751 + 752 + mod->kunit_suites = (struct kunit_suite **)suite_set.start; 753 + mod->num_kunit_suites = suite_set.end - suite_set.start; 743 754 744 755 if (!action) 745 756 kunit_exec_run_tests(&suite_set, false); ··· 764 753 765 754 static void kunit_module_exit(struct module *mod) 766 755 { 756 + struct kunit_suite_set suite_set = { 757 + mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites, 758 + }; 767 759 const char *action = kunit_action(); 768 760 769 761 if (!action) 770 762 __kunit_test_suites_exit(mod->kunit_suites, 771 763 mod->num_kunit_suites); 764 + 765 + if (suite_set.start) 766 + kunit_free_suite_set(suite_set); 772 767 } 773 768 774 769 static int kunit_module_notify(struct notifier_block *nb, unsigned long val,