2019-09-23 12:02:40 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test for core test infrastructure .
*
* Copyright ( C ) 2019 , Google LLC .
* Author : Brendan Higgins < brendanhiggins @ google . com >
*/
# include <kunit/test.h>
2020-01-07 01:28:19 +03:00
# include "try-catch-impl.h"
2019-09-23 12:02:40 +03:00
struct kunit_try_catch_test_context {
struct kunit_try_catch * try_catch ;
bool function_called ;
} ;
static void kunit_test_successful_try ( void * data )
{
struct kunit * test = data ;
struct kunit_try_catch_test_context * ctx = test - > priv ;
ctx - > function_called = true ;
}
static void kunit_test_no_catch ( void * data )
{
struct kunit * test = data ;
KUNIT_FAIL ( test , " Catch should not be called \n " ) ;
}
static void kunit_test_try_catch_successful_try_no_catch ( struct kunit * test )
{
struct kunit_try_catch_test_context * ctx = test - > priv ;
struct kunit_try_catch * try_catch = ctx - > try_catch ;
kunit_try_catch_init ( try_catch ,
test ,
kunit_test_successful_try ,
kunit_test_no_catch ) ;
kunit_try_catch_run ( try_catch , test ) ;
KUNIT_EXPECT_TRUE ( test , ctx - > function_called ) ;
}
static void kunit_test_unsuccessful_try ( void * data )
{
struct kunit * test = data ;
struct kunit_try_catch_test_context * ctx = test - > priv ;
struct kunit_try_catch * try_catch = ctx - > try_catch ;
kunit_try_catch_throw ( try_catch ) ;
KUNIT_FAIL ( test , " This line should never be reached \n " ) ;
}
static void kunit_test_catch ( void * data )
{
struct kunit * test = data ;
struct kunit_try_catch_test_context * ctx = test - > priv ;
ctx - > function_called = true ;
}
static void kunit_test_try_catch_unsuccessful_try_does_catch ( struct kunit * test )
{
struct kunit_try_catch_test_context * ctx = test - > priv ;
struct kunit_try_catch * try_catch = ctx - > try_catch ;
kunit_try_catch_init ( try_catch ,
test ,
kunit_test_unsuccessful_try ,
kunit_test_catch ) ;
kunit_try_catch_run ( try_catch , test ) ;
KUNIT_EXPECT_TRUE ( test , ctx - > function_called ) ;
}
static int kunit_try_catch_test_init ( struct kunit * test )
{
struct kunit_try_catch_test_context * ctx ;
ctx = kunit_kzalloc ( test , sizeof ( * ctx ) , GFP_KERNEL ) ;
2019-09-23 12:02:41 +03:00
KUNIT_ASSERT_NOT_ERR_OR_NULL ( test , ctx ) ;
2019-09-23 12:02:40 +03:00
test - > priv = ctx ;
ctx - > try_catch = kunit_kmalloc ( test ,
sizeof ( * ctx - > try_catch ) ,
GFP_KERNEL ) ;
2019-09-23 12:02:41 +03:00
KUNIT_ASSERT_NOT_ERR_OR_NULL ( test , ctx - > try_catch ) ;
2019-09-23 12:02:40 +03:00
return 0 ;
}
static struct kunit_case kunit_try_catch_test_cases [ ] = {
KUNIT_CASE ( kunit_test_try_catch_successful_try_no_catch ) ,
KUNIT_CASE ( kunit_test_try_catch_unsuccessful_try_does_catch ) ,
{ }
} ;
static struct kunit_suite kunit_try_catch_test_suite = {
. name = " kunit-try-catch-test " ,
. init = kunit_try_catch_test_init ,
. test_cases = kunit_try_catch_test_cases ,
} ;
2019-09-23 12:02:42 +03:00
/*
* Context for testing test managed resources
* is_resource_initialized is used to test arbitrary resources
*/
struct kunit_test_resource_context {
struct kunit test ;
bool is_resource_initialized ;
int allocate_order [ 2 ] ;
int free_order [ 2 ] ;
} ;
static int fake_resource_init ( struct kunit_resource * res , void * context )
{
struct kunit_test_resource_context * ctx = context ;
2020-05-30 00:46:20 +03:00
res - > data = & ctx - > is_resource_initialized ;
2019-09-23 12:02:42 +03:00
ctx - > is_resource_initialized = true ;
return 0 ;
}
static void fake_resource_free ( struct kunit_resource * res )
{
2020-05-30 00:46:20 +03:00
bool * is_resource_initialized = res - > data ;
2019-09-23 12:02:42 +03:00
* is_resource_initialized = false ;
}
static void kunit_resource_test_init_resources ( struct kunit * test )
{
struct kunit_test_resource_context * ctx = test - > priv ;
2020-03-26 17:25:07 +03:00
kunit_init_test ( & ctx - > test , " testing_test_init_test " , NULL ) ;
2019-09-23 12:02:42 +03:00
KUNIT_EXPECT_TRUE ( test , list_empty ( & ctx - > test . resources ) ) ;
}
static void kunit_resource_test_alloc_resource ( struct kunit * test )
{
struct kunit_test_resource_context * ctx = test - > priv ;
struct kunit_resource * res ;
kunit_resource_free_t free = fake_resource_free ;
res = kunit_alloc_and_get_resource ( & ctx - > test ,
fake_resource_init ,
fake_resource_free ,
GFP_KERNEL ,
ctx ) ;
KUNIT_ASSERT_NOT_ERR_OR_NULL ( test , res ) ;
KUNIT_EXPECT_PTR_EQ ( test ,
& ctx - > is_resource_initialized ,
2020-05-30 00:46:20 +03:00
( bool * ) res - > data ) ;
2019-09-23 12:02:42 +03:00
KUNIT_EXPECT_TRUE ( test , list_is_last ( & res - > node , & ctx - > test . resources ) ) ;
KUNIT_EXPECT_PTR_EQ ( test , free , res - > free ) ;
2020-05-30 00:46:20 +03:00
kunit_put_resource ( res ) ;
2019-09-23 12:02:42 +03:00
}
2020-05-30 00:46:20 +03:00
/*
* Note : tests below use kunit_alloc_and_get_resource ( ) , so as a consequence
* they have a reference to the associated resource that they must release
* via kunit_put_resource ( ) . In normal operation , users will only
* have to do this for cases where they use kunit_find_resource ( ) , and the
* kunit_alloc_resource ( ) function will be used ( which does not take a
* resource reference ) .
*/
2019-09-23 12:02:42 +03:00
static void kunit_resource_test_destroy_resource ( struct kunit * test )
{
struct kunit_test_resource_context * ctx = test - > priv ;
struct kunit_resource * res = kunit_alloc_and_get_resource (
& ctx - > test ,
fake_resource_init ,
fake_resource_free ,
GFP_KERNEL ,
ctx ) ;
2020-05-30 00:46:20 +03:00
kunit_put_resource ( res ) ;
2019-09-23 12:02:42 +03:00
KUNIT_ASSERT_FALSE ( test ,
2020-05-30 00:46:20 +03:00
kunit_destroy_resource ( & ctx - > test ,
2019-09-23 12:02:42 +03:00
kunit_resource_instance_match ,
2020-05-30 00:46:20 +03:00
res - > data ) ) ;
2019-09-23 12:02:42 +03:00
KUNIT_EXPECT_FALSE ( test , ctx - > is_resource_initialized ) ;
KUNIT_EXPECT_TRUE ( test , list_empty ( & ctx - > test . resources ) ) ;
}
static void kunit_resource_test_cleanup_resources ( struct kunit * test )
{
int i ;
struct kunit_test_resource_context * ctx = test - > priv ;
struct kunit_resource * resources [ 5 ] ;
for ( i = 0 ; i < ARRAY_SIZE ( resources ) ; i + + ) {
resources [ i ] = kunit_alloc_and_get_resource ( & ctx - > test ,
fake_resource_init ,
fake_resource_free ,
GFP_KERNEL ,
ctx ) ;
2020-05-30 00:46:20 +03:00
kunit_put_resource ( resources [ i ] ) ;
2019-09-23 12:02:42 +03:00
}
kunit_cleanup ( & ctx - > test ) ;
KUNIT_EXPECT_TRUE ( test , list_empty ( & ctx - > test . resources ) ) ;
}
static void kunit_resource_test_mark_order ( int order_array [ ] ,
size_t order_size ,
int key )
{
int i ;
for ( i = 0 ; i < order_size & & order_array [ i ] ; i + + )
;
order_array [ i ] = key ;
}
# define KUNIT_RESOURCE_TEST_MARK_ORDER(ctx, order_field, key) \
kunit_resource_test_mark_order ( ctx - > order_field , \
ARRAY_SIZE ( ctx - > order_field ) , \
key )
static int fake_resource_2_init ( struct kunit_resource * res , void * context )
{
struct kunit_test_resource_context * ctx = context ;
KUNIT_RESOURCE_TEST_MARK_ORDER ( ctx , allocate_order , 2 ) ;
2020-05-30 00:46:20 +03:00
res - > data = ctx ;
2019-09-23 12:02:42 +03:00
return 0 ;
}
static void fake_resource_2_free ( struct kunit_resource * res )
{
2020-05-30 00:46:20 +03:00
struct kunit_test_resource_context * ctx = res - > data ;
2019-09-23 12:02:42 +03:00
KUNIT_RESOURCE_TEST_MARK_ORDER ( ctx , free_order , 2 ) ;
}
static int fake_resource_1_init ( struct kunit_resource * res , void * context )
{
struct kunit_test_resource_context * ctx = context ;
2020-05-30 00:46:20 +03:00
struct kunit_resource * res2 ;
2019-09-23 12:02:42 +03:00
2020-05-30 00:46:20 +03:00
res2 = kunit_alloc_and_get_resource ( & ctx - > test ,
fake_resource_2_init ,
fake_resource_2_free ,
GFP_KERNEL ,
ctx ) ;
2019-09-23 12:02:42 +03:00
KUNIT_RESOURCE_TEST_MARK_ORDER ( ctx , allocate_order , 1 ) ;
2020-05-30 00:46:20 +03:00
res - > data = ctx ;
kunit_put_resource ( res2 ) ;
2019-09-23 12:02:42 +03:00
return 0 ;
}
static void fake_resource_1_free ( struct kunit_resource * res )
{
2020-05-30 00:46:20 +03:00
struct kunit_test_resource_context * ctx = res - > data ;
2019-09-23 12:02:42 +03:00
KUNIT_RESOURCE_TEST_MARK_ORDER ( ctx , free_order , 1 ) ;
}
/*
* TODO ( brendanhiggins @ google . com ) : replace the arrays that keep track of the
* order of allocation and freeing with strict mocks using the IN_SEQUENCE macro
* to assert allocation and freeing order when the feature becomes available .
*/
static void kunit_resource_test_proper_free_ordering ( struct kunit * test )
{
struct kunit_test_resource_context * ctx = test - > priv ;
2020-05-30 00:46:20 +03:00
struct kunit_resource * res ;
2019-09-23 12:02:42 +03:00
/* fake_resource_1 allocates a fake_resource_2 in its init. */
2020-05-30 00:46:20 +03:00
res = kunit_alloc_and_get_resource ( & ctx - > test ,
fake_resource_1_init ,
fake_resource_1_free ,
GFP_KERNEL ,
ctx ) ;
2019-09-23 12:02:42 +03:00
/*
* Since fake_resource_2_init calls KUNIT_RESOURCE_TEST_MARK_ORDER
* before returning to fake_resource_1_init , it should be the first to
* put its key in the allocate_order array .
*/
KUNIT_EXPECT_EQ ( test , ctx - > allocate_order [ 0 ] , 2 ) ;
KUNIT_EXPECT_EQ ( test , ctx - > allocate_order [ 1 ] , 1 ) ;
2020-05-30 00:46:20 +03:00
kunit_put_resource ( res ) ;
2019-09-23 12:02:42 +03:00
kunit_cleanup ( & ctx - > test ) ;
/*
* Because fake_resource_2 finishes allocation before fake_resource_1 ,
* fake_resource_1 should be freed first since it could depend on
* fake_resource_2 .
*/
KUNIT_EXPECT_EQ ( test , ctx - > free_order [ 0 ] , 1 ) ;
KUNIT_EXPECT_EQ ( test , ctx - > free_order [ 1 ] , 2 ) ;
}
2020-05-30 00:46:20 +03:00
static void kunit_resource_test_static ( struct kunit * test )
{
struct kunit_test_resource_context ctx ;
struct kunit_resource res ;
KUNIT_EXPECT_EQ ( test , kunit_add_resource ( test , NULL , NULL , & res , & ctx ) ,
0 ) ;
KUNIT_EXPECT_PTR_EQ ( test , res . data , ( void * ) & ctx ) ;
kunit_cleanup ( test ) ;
KUNIT_EXPECT_TRUE ( test , list_empty ( & test - > resources ) ) ;
}
2020-05-30 00:46:21 +03:00
static void kunit_resource_test_named ( struct kunit * test )
{
struct kunit_resource res1 , res2 , * found = NULL ;
struct kunit_test_resource_context ctx ;
KUNIT_EXPECT_EQ ( test ,
kunit_add_named_resource ( test , NULL , NULL , & res1 ,
" resource_1 " , & ctx ) ,
0 ) ;
KUNIT_EXPECT_PTR_EQ ( test , res1 . data , ( void * ) & ctx ) ;
KUNIT_EXPECT_EQ ( test ,
kunit_add_named_resource ( test , NULL , NULL , & res1 ,
" resource_1 " , & ctx ) ,
- EEXIST ) ;
KUNIT_EXPECT_EQ ( test ,
kunit_add_named_resource ( test , NULL , NULL , & res2 ,
" resource_2 " , & ctx ) ,
0 ) ;
found = kunit_find_named_resource ( test , " resource_1 " ) ;
KUNIT_EXPECT_PTR_EQ ( test , found , & res1 ) ;
if ( found )
kunit_put_resource ( & res1 ) ;
KUNIT_EXPECT_EQ ( test , kunit_destroy_named_resource ( test , " resource_2 " ) ,
0 ) ;
kunit_cleanup ( test ) ;
KUNIT_EXPECT_TRUE ( test , list_empty ( & test - > resources ) ) ;
}
2019-09-23 12:02:42 +03:00
static int kunit_resource_test_init ( struct kunit * test )
{
struct kunit_test_resource_context * ctx =
kzalloc ( sizeof ( * ctx ) , GFP_KERNEL ) ;
KUNIT_ASSERT_NOT_ERR_OR_NULL ( test , ctx ) ;
test - > priv = ctx ;
2020-03-26 17:25:07 +03:00
kunit_init_test ( & ctx - > test , " test_test_context " , NULL ) ;
2019-09-23 12:02:42 +03:00
return 0 ;
}
static void kunit_resource_test_exit ( struct kunit * test )
{
struct kunit_test_resource_context * ctx = test - > priv ;
kunit_cleanup ( & ctx - > test ) ;
kfree ( ctx ) ;
}
static struct kunit_case kunit_resource_test_cases [ ] = {
KUNIT_CASE ( kunit_resource_test_init_resources ) ,
KUNIT_CASE ( kunit_resource_test_alloc_resource ) ,
KUNIT_CASE ( kunit_resource_test_destroy_resource ) ,
KUNIT_CASE ( kunit_resource_test_cleanup_resources ) ,
KUNIT_CASE ( kunit_resource_test_proper_free_ordering ) ,
2020-05-30 00:46:20 +03:00
KUNIT_CASE ( kunit_resource_test_static ) ,
2020-05-30 00:46:21 +03:00
KUNIT_CASE ( kunit_resource_test_named ) ,
2019-09-23 12:02:42 +03:00
{ }
} ;
static struct kunit_suite kunit_resource_test_suite = {
. name = " kunit-resource-test " ,
. init = kunit_resource_test_init ,
. exit = kunit_resource_test_exit ,
. test_cases = kunit_resource_test_cases ,
} ;
2020-03-26 17:25:08 +03:00
static void kunit_log_test ( struct kunit * test ) ;
static struct kunit_case kunit_log_test_cases [ ] = {
KUNIT_CASE ( kunit_log_test ) ,
{ }
} ;
static struct kunit_suite kunit_log_test_suite = {
. name = " kunit-log-test " ,
. test_cases = kunit_log_test_cases ,
} ;
static void kunit_log_test ( struct kunit * test )
{
struct kunit_suite * suite = & kunit_log_test_suite ;
kunit_log ( KERN_INFO , test , " put this in log. " ) ;
kunit_log ( KERN_INFO , test , " this too. " ) ;
kunit_log ( KERN_INFO , suite , " add to suite log. " ) ;
kunit_log ( KERN_INFO , suite , " along with this. " ) ;
# ifdef CONFIG_KUNIT_DEBUGFS
KUNIT_EXPECT_NOT_ERR_OR_NULL ( test ,
strstr ( test - > log , " put this in log. " ) ) ;
KUNIT_EXPECT_NOT_ERR_OR_NULL ( test ,
strstr ( test - > log , " this too. " ) ) ;
KUNIT_EXPECT_NOT_ERR_OR_NULL ( test ,
strstr ( suite - > log , " add to suite log. " ) ) ;
KUNIT_EXPECT_NOT_ERR_OR_NULL ( test ,
strstr ( suite - > log , " along with this. " ) ) ;
# else
KUNIT_EXPECT_PTR_EQ ( test , test - > log , ( char * ) NULL ) ;
KUNIT_EXPECT_PTR_EQ ( test , suite - > log , ( char * ) NULL ) ;
# endif
}
kunit_test_suites ( & kunit_try_catch_test_suite , & kunit_resource_test_suite ,
& kunit_log_test_suite ) ;
2020-01-07 01:28:20 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;