diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index 1c83e7d60a8a973dc1f679cce1f280e7f969aba1..d62a04255c2e0f9be700c574dc3385fc33a78c72 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -125,8 +125,8 @@ We need many test cases covering all the unit's behaviors. It is common to have many similar tests. In order to reduce duplication in these closely related tests, most unit testing frameworks (including KUnit) provide the concept of a *test suite*. A test suite is a collection of test cases for a unit of code -with a setup function that gets invoked before every test case and then a tear -down function that gets invoked after every test case completes. For example: +with optional setup and teardown functions that run before/after the whole +suite and/or every test case. For example: .. code-block:: c @@ -141,16 +141,19 @@ down function that gets invoked after every test case completes. For example: .name = "example", .init = example_test_init, .exit = example_test_exit, + .suite_init = example_suite_init, + .suite_exit = example_suite_exit, .test_cases = example_test_cases, }; kunit_test_suite(example_test_suite); -In the above example, the test suite ``example_test_suite`` would run the test -cases ``example_test_foo``, ``example_test_bar``, and ``example_test_baz``. Each -would have ``example_test_init`` called immediately before it and -``example_test_exit`` called immediately after it. -``kunit_test_suite(example_test_suite)`` registers the test suite with the -KUnit test framework. +In the above example, the test suite ``example_test_suite`` would first run +``example_suite_init``, then run the test cases ``example_test_foo``, +``example_test_bar``, and ``example_test_baz``. Each would have +``example_test_init`` called immediately before it and ``example_test_exit`` +called immediately after it. Finally, ``example_suite_exit`` would be called +after everything else. ``kunit_test_suite(example_test_suite)`` registers the +test suite with the KUnit test framework. .. note:: A test case will only run if it is associated with a test suite. diff --git a/include/kunit/test.h b/include/kunit/test.h index d04f9e2fd5e78a1bfa75b8049a3f6bd430306672..719269d4442c22fdb55fb65b32bce28abfc10c37 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -153,6 +153,8 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) * struct kunit_suite - describes a related collection of &struct kunit_case * * @name: the name of the test. Purely informational. + * @suite_init: called once per test suite before the test cases. + * @suite_exit: called once per test suite after all test cases. * @init: called before every test case. * @exit: called after every test case. * @test_cases: a null terminated array of test cases. @@ -167,6 +169,8 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) */ struct kunit_suite { const char name[256]; + int (*suite_init)(struct kunit_suite *suite); + void (*suite_exit)(struct kunit_suite *suite); int (*init)(struct kunit *test); void (*exit)(struct kunit *test); struct kunit_case *test_cases; @@ -175,6 +179,7 @@ struct kunit_suite { char status_comment[KUNIT_STATUS_COMMENT_SIZE]; struct dentry *debugfs; char *log; + int suite_init_err; }; /** diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c index 4bbf37c04ebaf0c50bc19693f4a37c1637976bee..23d37b7029975c720a4e33a5adc0ad7ad2e3933d 100644 --- a/lib/kunit/kunit-example-test.c +++ b/lib/kunit/kunit-example-test.c @@ -40,6 +40,17 @@ static int example_test_init(struct kunit *test) return 0; } +/* + * This is run once before all test cases in the suite. + * See the comment on example_test_suite for more information. + */ +static int example_test_init_suite(struct kunit_suite *suite) +{ + kunit_info(suite, "initializing suite\n"); + + return 0; +} + /* * This test should always be skipped. */ @@ -140,17 +151,20 @@ static struct kunit_case example_test_cases[] = { * may be specified which runs after every test case and can be used to for * cleanup. For clarity, running tests in a test suite would behave as follows: * + * suite.suite_init(suite); * suite.init(test); * suite.test_case[0](test); * suite.exit(test); * suite.init(test); * suite.test_case[1](test); * suite.exit(test); + * suite.suite_exit(suite); * ...; */ static struct kunit_suite example_test_suite = { .name = "example", .init = example_test_init, + .suite_init = example_test_init_suite, .test_cases = example_test_cases, }; diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 64ee6a9d8003eec2f1b617d22631caeaa8fa3ca1..65c56bd0545d6c9bbcfa3f84cabd2b1a0526e611 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -179,6 +179,9 @@ enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite) const struct kunit_case *test_case; enum kunit_status status = KUNIT_SKIPPED; + if (suite->suite_init_err) + return KUNIT_FAILURE; + kunit_suite_for_each_test_case(suite, test_case) { if (test_case->status == KUNIT_FAILURE) return KUNIT_FAILURE; @@ -498,6 +501,15 @@ int kunit_run_tests(struct kunit_suite *suite) struct kunit_result_stats suite_stats = { 0 }; struct kunit_result_stats total_stats = { 0 }; + if (suite->suite_init) { + suite->suite_init_err = suite->suite_init(suite); + if (suite->suite_init_err) { + kunit_err(suite, KUNIT_SUBTEST_INDENT + "# failed to initialize (%d)", suite->suite_init_err); + goto suite_end; + } + } + kunit_print_suite_start(suite); kunit_suite_for_each_test_case(suite, test_case) { @@ -551,7 +563,11 @@ int kunit_run_tests(struct kunit_suite *suite) kunit_accumulate_stats(&total_stats, param_stats); } + if (suite->suite_exit) + suite->suite_exit(suite); + kunit_print_suite_stats(suite, suite_stats, total_stats); +suite_end: kunit_print_suite_end(suite); return 0; @@ -562,6 +578,7 @@ static void kunit_init_suite(struct kunit_suite *suite) { kunit_debugfs_create_suite(suite); suite->status_comment[0] = '\0'; + suite->suite_init_err = 0; } int __kunit_test_suites_init(struct kunit_suite * const * const suites)