2020-08-04 23:47:42 +03:00
// SPDX-License-Identifier: GPL-2.0
2021-05-27 00:24:04 +03:00
# include <linux/reboot.h>
2020-08-04 23:47:42 +03:00
# include <kunit/test.h>
2021-02-06 03:08:52 +03:00
# include <linux/glob.h>
# include <linux/moduleparam.h>
2020-08-04 23:47:42 +03:00
/*
* These symbols point to the . kunit_test_suites section and are defined in
* include / asm - generic / vmlinux . lds . h , and consequently must be extern .
*/
2022-07-09 06:19:58 +03:00
extern struct kunit_suite * const __kunit_suites_start [ ] ;
extern struct kunit_suite * const __kunit_suites_end [ ] ;
2020-08-04 23:47:42 +03:00
# if IS_BUILTIN(CONFIG_KUNIT)
2021-04-21 05:04:27 +03:00
static char * filter_glob_param ;
2021-10-01 01:20:45 +03:00
static char * action_param ;
2021-04-21 05:04:27 +03:00
module_param_named ( filter_glob , filter_glob_param , charp , 0 ) ;
2021-02-06 03:08:52 +03:00
MODULE_PARM_DESC ( filter_glob ,
2021-09-15 00:03:48 +03:00
" Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test " ) ;
2021-10-01 01:20:45 +03:00
module_param_named ( action , action_param , charp , 0 ) ;
MODULE_PARM_DESC ( action ,
" Changes KUnit executor behavior, valid values are: \n "
" <none>: run the tests like normal \n "
" 'list' to list test names instead of running them. \n " ) ;
2021-09-15 00:03:48 +03:00
/* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
struct kunit_test_filter {
char * suite_glob ;
char * test_glob ;
} ;
/* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
static void kunit_parse_filter_glob ( struct kunit_test_filter * parsed ,
const char * filter_glob )
{
const int len = strlen ( filter_glob ) ;
const char * period = strchr ( filter_glob , ' . ' ) ;
if ( ! period ) {
2021-10-02 04:36:35 +03:00
parsed - > suite_glob = kzalloc ( len + 1 , GFP_KERNEL ) ;
2021-09-15 00:03:48 +03:00
parsed - > test_glob = NULL ;
strcpy ( parsed - > suite_glob , filter_glob ) ;
return ;
}
parsed - > suite_glob = kzalloc ( period - filter_glob + 1 , GFP_KERNEL ) ;
parsed - > test_glob = kzalloc ( len - ( period - filter_glob ) + 1 , GFP_KERNEL ) ;
strncpy ( parsed - > suite_glob , filter_glob , period - filter_glob ) ;
strncpy ( parsed - > test_glob , period + 1 , len - ( period - filter_glob ) ) ;
}
/* Create a copy of suite with only tests that match test_glob. */
static struct kunit_suite *
2022-05-16 19:54:46 +03:00
kunit_filter_tests ( const struct kunit_suite * const suite , const char * test_glob )
2021-09-15 00:03:48 +03:00
{
int n = 0 ;
struct kunit_case * filtered , * test_case ;
struct kunit_suite * copy ;
kunit_suite_for_each_test_case ( suite , test_case ) {
if ( ! test_glob | | glob_match ( test_glob , test_case - > name ) )
+ + n ;
}
if ( n = = 0 )
return NULL ;
2022-05-16 19:54:46 +03:00
copy = kmemdup ( suite , sizeof ( * copy ) , GFP_KERNEL ) ;
2022-05-12 00:16:26 +03:00
if ( ! copy )
return ERR_PTR ( - ENOMEM ) ;
2021-09-15 00:03:48 +03:00
filtered = kcalloc ( n + 1 , sizeof ( * filtered ) , GFP_KERNEL ) ;
2022-07-13 02:25:27 +03:00
if ( ! filtered ) {
kfree ( copy ) ;
2022-05-12 00:16:26 +03:00
return ERR_PTR ( - ENOMEM ) ;
2022-07-13 02:25:27 +03:00
}
2021-09-15 00:03:48 +03:00
n = 0 ;
kunit_suite_for_each_test_case ( suite , test_case ) {
if ( ! test_glob | | glob_match ( test_glob , test_case - > name ) )
filtered [ n + + ] = * test_case ;
}
copy - > test_cases = filtered ;
return copy ;
}
2021-02-06 03:08:52 +03:00
2021-05-27 00:24:04 +03:00
static char * kunit_shutdown ;
core_param ( kunit_shutdown , kunit_shutdown , charp , 0644 ) ;
2022-07-09 06:19:58 +03:00
/* Stores an array of suites, end points one past the end */
2021-02-06 03:08:52 +03:00
struct suite_set {
2022-07-09 06:19:58 +03:00
struct kunit_suite * const * start ;
struct kunit_suite * const * end ;
2021-02-06 03:08:52 +03:00
} ;
2021-09-15 00:03:48 +03:00
static void kunit_free_suite_set ( struct suite_set suite_set )
{
2022-07-09 06:19:58 +03:00
struct kunit_suite * const * suites ;
2021-09-15 00:03:48 +03:00
for ( suites = suite_set . start ; suites < suite_set . end ; suites + + )
2022-07-09 06:19:58 +03:00
kfree ( * suites ) ;
2021-09-15 00:03:48 +03:00
kfree ( suite_set . start ) ;
}
2021-04-21 05:04:27 +03:00
static struct suite_set kunit_filter_suites ( const struct suite_set * suite_set ,
2022-05-12 00:16:26 +03:00
const char * filter_glob ,
int * err )
2021-02-06 03:08:52 +03:00
{
int i ;
2022-07-09 06:19:58 +03:00
struct kunit_suite * * copy , * filtered_suite ;
2021-02-06 03:08:52 +03:00
struct suite_set filtered ;
2021-09-15 00:03:48 +03:00
struct kunit_test_filter filter ;
2021-02-06 03:08:52 +03:00
2021-04-21 05:04:27 +03:00
const size_t max = suite_set - > end - suite_set - > start ;
2021-02-06 03:08:52 +03:00
copy = kmalloc_array ( max , sizeof ( * filtered . start ) , GFP_KERNEL ) ;
filtered . start = copy ;
if ( ! copy ) { /* won't be able to run anything, return an empty set */
filtered . end = copy ;
return filtered ;
}
2021-09-15 00:03:48 +03:00
kunit_parse_filter_glob ( & filter , filter_glob ) ;
2022-07-09 06:19:58 +03:00
for ( i = 0 ; & suite_set - > start [ i ] ! = suite_set - > end ; i + + ) {
if ( ! glob_match ( filter . suite_glob , suite_set - > start [ i ] - > name ) )
continue ;
filtered_suite = kunit_filter_tests ( suite_set - > start [ i ] , filter . test_glob ) ;
if ( IS_ERR ( filtered_suite ) ) {
* err = PTR_ERR ( filtered_suite ) ;
2022-05-12 00:16:26 +03:00
return filtered ;
}
2022-07-09 06:19:58 +03:00
if ( ! filtered_suite )
continue ;
* copy + + = filtered_suite ;
2021-02-06 03:08:52 +03:00
}
filtered . end = copy ;
2021-09-15 00:03:48 +03:00
kfree ( filter . suite_glob ) ;
kfree ( filter . test_glob ) ;
2021-02-06 03:08:52 +03:00
return filtered ;
}
2021-05-27 00:24:04 +03:00
static void kunit_handle_shutdown ( void )
{
if ( ! kunit_shutdown )
return ;
if ( ! strcmp ( kunit_shutdown , " poweroff " ) )
kernel_power_off ( ) ;
else if ( ! strcmp ( kunit_shutdown , " halt " ) )
kernel_halt ( ) ;
else if ( ! strcmp ( kunit_shutdown , " reboot " ) )
kernel_restart ( NULL ) ;
}
2021-10-01 01:20:45 +03:00
static void kunit_exec_run_tests ( struct suite_set * suite_set )
2020-08-04 23:47:42 +03:00
{
2022-07-09 06:19:58 +03:00
size_t num_suites = suite_set - > end - suite_set - > start ;
2021-10-01 01:20:45 +03:00
2022-11-23 21:25:58 +03:00
pr_info ( " KTAP version 1 \n " ) ;
2022-07-09 06:19:58 +03:00
pr_info ( " 1..%zu \n " , num_suites ) ;
2021-10-01 01:20:45 +03:00
2022-07-09 06:19:58 +03:00
__kunit_test_suites_init ( suite_set - > start , num_suites ) ;
2021-10-01 01:20:45 +03:00
}
static void kunit_exec_list_tests ( struct suite_set * suite_set )
{
2022-07-09 06:19:58 +03:00
struct kunit_suite * const * suites ;
2021-10-01 01:20:45 +03:00
struct kunit_case * test_case ;
2022-11-23 21:25:58 +03:00
/* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
pr_info ( " KTAP version 1 \n " ) ;
2021-10-01 01:20:45 +03:00
for ( suites = suite_set - > start ; suites < suite_set - > end ; suites + + )
2022-07-09 06:19:58 +03:00
kunit_suite_for_each_test_case ( ( * suites ) , test_case ) {
pr_info ( " %s.%s \n " , ( * suites ) - > name , test_case - > name ) ;
2021-10-01 01:20:45 +03:00
}
}
int kunit_run_all_tests ( void )
{
2022-07-09 06:19:58 +03:00
struct suite_set suite_set = { __kunit_suites_start , __kunit_suites_end } ;
2022-05-13 21:37:07 +03:00
int err = 0 ;
2022-08-23 17:24:54 +03:00
if ( ! kunit_enabled ( ) ) {
pr_info ( " kunit: disabled \n " ) ;
goto out ;
}
2020-08-04 23:47:42 +03:00
2022-05-12 00:16:26 +03:00
if ( filter_glob_param ) {
suite_set = kunit_filter_suites ( & suite_set , filter_glob_param , & err ) ;
if ( err ) {
pr_err ( " kunit executor: error filtering suites: %d \n " , err ) ;
2022-05-13 21:37:07 +03:00
goto out ;
2022-05-12 00:16:26 +03:00
}
}
2021-02-06 03:08:52 +03:00
2021-10-01 01:20:45 +03:00
if ( ! action_param )
kunit_exec_run_tests ( & suite_set ) ;
else if ( strcmp ( action_param , " list " ) = = 0 )
kunit_exec_list_tests ( & suite_set ) ;
else
pr_err ( " kunit executor: unknown action '%s' \n " , action_param ) ;
2020-08-04 23:47:44 +03:00
2022-07-09 06:19:58 +03:00
if ( filter_glob_param ) { /* a copy was made of each suite */
2021-09-15 00:03:48 +03:00
kunit_free_suite_set ( suite_set ) ;
2021-02-06 03:08:52 +03:00
}
2020-08-04 23:47:42 +03:00
2022-05-13 21:37:07 +03:00
out :
kunit_handle_shutdown ( ) ;
return err ;
2020-08-04 23:47:42 +03:00
}
2021-04-21 05:04:27 +03:00
# if IS_BUILTIN(CONFIG_KUNIT_TEST)
# include "executor_test.c"
# endif
2020-08-04 23:47:42 +03:00
# endif /* IS_BUILTIN(CONFIG_KUNIT) */