The current kunit execution model is to provide base kunit functionality and tests built-in to the kernel. The aim of this series is to allow building kunit itself and tests as modules. This in turn allows a simple form of selective execution; load the module you wish to test. In doing so, kunit itself (if also built as a module) will be loaded as an implicit dependency.
Because this requires a core API modification - if a module delivers multiple suites, they must be declared with the kunit_test_suites() macro - we're proposing this patch set as a candidate to be applied to the test tree before too many kunit consumers appear. We attempt to deal with existing consumers in patch 3.
Changes since v5: - fixed fs/ext4/Makefile to remove unneeded conditional compilation (Iurii, patch 3) - added Reviewed-by, Acked-by to patches 3, 4, 5 and 6
Changes since v4: - fixed signoff chain to use Co-developed-by: prior to Knut's signoff (Stephen, all patches) - added Reviewed-by, Tested-by for patches 1, 2, 4 and 6 - updated comment describing try-catch-impl.h (Stephen, patch 2) - fixed MODULE_LICENSEs to be GPL v2 (Stephen, patches 3, 5) - added __init to kunit_init() (Stephen, patch 5)
Changes since v3: - removed symbol lookup patch for separate submission later - removed use of sysctl_hung_task_timeout_seconds (patch 4, as discussed with Brendan and Stephen) - disabled build of string-stream-test when CONFIG_KUNIT_TEST=m; this is to avoid having to deal with symbol lookup issues - changed string-stream-impl.h back to string-stream.h (Brendan) - added module build support to new list, ext4 tests
Changes since v2: - moved string-stream.h header to lib/kunit/string-stream-impl.h (Brendan) (patch 1) - split out non-exported interfaces in try-catch-impl.h (Brendan) (patch 2) - added kunit_find_symbol() and KUNIT_INIT_SYMBOL to lookup non-exported symbols (patches 3, 4) - removed #ifdef MODULE around module licenses (Randy, Brendan, Andy) (patch 4) - replaced kunit_test_suite() with kunit_test_suites() rather than supporting both (Brendan) (patch 4) - lookup sysctl_hung_task_timeout_secs as kunit may be built as a module and the symbol may not be available (patch 5)
Alan Maguire (6): kunit: move string-stream.h to lib/kunit kunit: hide unexported try-catch interface in try-catch-impl.h kunit: allow kunit tests to be loaded as a module kunit: remove timeout dependence on sysctl_hung_task_timeout_seconds kunit: allow kunit to be loaded as a module kunit: update documentation to describe module-based build
Documentation/dev-tools/kunit/faq.rst | 3 +- Documentation/dev-tools/kunit/index.rst | 3 ++ Documentation/dev-tools/kunit/usage.rst | 16 ++++++++++ fs/ext4/Kconfig | 2 +- fs/ext4/Makefile | 3 +- fs/ext4/inode-test.c | 4 ++- include/kunit/assert.h | 3 +- include/kunit/test.h | 35 ++++++++++++++------ include/kunit/try-catch.h | 10 ------ kernel/sysctl-test.c | 4 ++- lib/Kconfig.debug | 4 +-- lib/kunit/Kconfig | 6 ++-- lib/kunit/Makefile | 14 +++++--- lib/kunit/assert.c | 10 ++++++ lib/kunit/{example-test.c => kunit-example-test.c} | 4 ++- lib/kunit/{test-test.c => kunit-test.c} | 7 ++-- lib/kunit/string-stream-test.c | 5 +-- lib/kunit/string-stream.c | 3 +- {include => lib}/kunit/string-stream.h | 0 lib/kunit/test.c | 25 ++++++++++++++- lib/kunit/try-catch-impl.h | 27 ++++++++++++++++ lib/kunit/try-catch.c | 37 +++++----------------- lib/list-test.c | 4 ++- 23 files changed, 157 insertions(+), 72 deletions(-) rename lib/kunit/{example-test.c => kunit-example-test.c} (97%) rename lib/kunit/{test-test.c => kunit-test.c} (98%) rename {include => lib}/kunit/string-stream.h (100%) create mode 100644 lib/kunit/try-catch-impl.h
string-stream interfaces are not intended for external use; move them from include/kunit to lib/kunit accordingly.
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Brendan Higgins brendanhiggins@google.com Tested-by: Brendan Higgins brendanhiggins@google.com --- include/kunit/assert.h | 3 ++- lib/kunit/assert.c | 2 ++ lib/kunit/string-stream-test.c | 3 ++- lib/kunit/string-stream.c | 3 ++- {include => lib}/kunit/string-stream.h | 0 lib/kunit/test.c | 2 ++ 6 files changed, 10 insertions(+), 3 deletions(-) rename {include => lib}/kunit/string-stream.h (100%)
diff --git a/include/kunit/assert.h b/include/kunit/assert.h index db6a0fc..ad889b5 100644 --- a/include/kunit/assert.h +++ b/include/kunit/assert.h @@ -9,10 +9,11 @@ #ifndef _KUNIT_ASSERT_H #define _KUNIT_ASSERT_H
-#include <kunit/string-stream.h> #include <linux/err.h> +#include <linux/kernel.h>
struct kunit; +struct string_stream;
/** * enum kunit_assert_type - Type of expectation/assertion. diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c index 86013d4..9aca71c 100644 --- a/lib/kunit/assert.c +++ b/lib/kunit/assert.c @@ -7,6 +7,8 @@ */ #include <kunit/assert.h>
+#include "string-stream.h" + void kunit_base_assert_format(const struct kunit_assert *assert, struct string_stream *stream) { diff --git a/lib/kunit/string-stream-test.c b/lib/kunit/string-stream-test.c index 76cc05e..6c70dc8 100644 --- a/lib/kunit/string-stream-test.c +++ b/lib/kunit/string-stream-test.c @@ -6,10 +6,11 @@ * Author: Brendan Higgins brendanhiggins@google.com */
-#include <kunit/string-stream.h> #include <kunit/test.h> #include <linux/slab.h>
+#include "string-stream.h" + static void string_stream_test_empty_on_creation(struct kunit *test) { struct string_stream *stream = alloc_string_stream(test, GFP_KERNEL); diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c index e6d17aa..3503920 100644 --- a/lib/kunit/string-stream.c +++ b/lib/kunit/string-stream.c @@ -6,11 +6,12 @@ * Author: Brendan Higgins brendanhiggins@google.com */
-#include <kunit/string-stream.h> #include <kunit/test.h> #include <linux/list.h> #include <linux/slab.h>
+#include "string-stream.h" + struct string_stream_fragment_alloc_context { struct kunit *test; int len; diff --git a/include/kunit/string-stream.h b/lib/kunit/string-stream.h similarity index 100% rename from include/kunit/string-stream.h rename to lib/kunit/string-stream.h diff --git a/lib/kunit/test.c b/lib/kunit/test.c index c83c0fa..36ebf47 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -11,6 +11,8 @@ #include <linux/kernel.h> #include <linux/sched/debug.h>
+#include "string-stream.h" + static void kunit_set_failure(struct kunit *test) { WRITE_ONCE(test->success, false);
Define function as static inline in try-catch-impl.h to allow it to be used in kunit itself and tests. Also remove unused kunit_generic_try_catch
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Brendan Higgins brendanhiggins@google.com Tested-by: Brendan Higgins brendanhiggins@google.com --- include/kunit/try-catch.h | 10 ---------- lib/kunit/test-test.c | 2 ++ lib/kunit/test.c | 2 +- lib/kunit/try-catch-impl.h | 27 +++++++++++++++++++++++++++ lib/kunit/try-catch.c | 13 ++----------- 5 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 lib/kunit/try-catch-impl.h
diff --git a/include/kunit/try-catch.h b/include/kunit/try-catch.h index 404f336..c507dd4 100644 --- a/include/kunit/try-catch.h +++ b/include/kunit/try-catch.h @@ -53,11 +53,6 @@ struct kunit_try_catch { void *context; };
-void kunit_try_catch_init(struct kunit_try_catch *try_catch, - struct kunit *test, - kunit_try_catch_func_t try, - kunit_try_catch_func_t catch); - void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context);
void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch); @@ -67,9 +62,4 @@ static inline int kunit_try_catch_get_result(struct kunit_try_catch *try_catch) return try_catch->try_result; }
-/* - * Exposed for testing only. - */ -void kunit_generic_try_catch_init(struct kunit_try_catch *try_catch); - #endif /* _KUNIT_TRY_CATCH_H */ diff --git a/lib/kunit/test-test.c b/lib/kunit/test-test.c index 5ebe059..5a6cc04 100644 --- a/lib/kunit/test-test.c +++ b/lib/kunit/test-test.c @@ -7,6 +7,8 @@ */ #include <kunit/test.h>
+#include "try-catch-impl.h" + struct kunit_try_catch_test_context { struct kunit_try_catch *try_catch; bool function_called; diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 36ebf47..58a6227 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -7,11 +7,11 @@ */
#include <kunit/test.h> -#include <kunit/try-catch.h> #include <linux/kernel.h> #include <linux/sched/debug.h>
#include "string-stream.h" +#include "try-catch-impl.h"
static void kunit_set_failure(struct kunit *test) { diff --git a/lib/kunit/try-catch-impl.h b/lib/kunit/try-catch-impl.h new file mode 100644 index 0000000..203ba6a --- /dev/null +++ b/lib/kunit/try-catch-impl.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Internal kunit try catch implementation to be shared with tests. + * + * Copyright (C) 2019, Google LLC. + * Author: Brendan Higgins brendanhiggins@google.com + */ + +#ifndef _KUNIT_TRY_CATCH_IMPL_H +#define _KUNIT_TRY_CATCH_IMPL_H + +#include <kunit/try-catch.h> +#include <linux/types.h> + +struct kunit; + +static inline void kunit_try_catch_init(struct kunit_try_catch *try_catch, + struct kunit *test, + kunit_try_catch_func_t try, + kunit_try_catch_func_t catch) +{ + try_catch->test = test; + try_catch->try = try; + try_catch->catch = catch; +} + +#endif /* _KUNIT_TRY_CATCH_IMPL_H */ diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 55686839..4a66d16 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -8,12 +8,13 @@ */
#include <kunit/test.h> -#include <kunit/try-catch.h> #include <linux/completion.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/sched/sysctl.h>
+#include "try-catch-impl.h" + void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch) { try_catch->try_result = -EFAULT; @@ -106,13 +107,3 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
try_catch->catch(try_catch->context); } - -void kunit_try_catch_init(struct kunit_try_catch *try_catch, - struct kunit *test, - kunit_try_catch_func_t try, - kunit_try_catch_func_t catch) -{ - try_catch->test = test; - try_catch->try = try; - try_catch->catch = catch; -}
As tests are added to kunit, it will become less feasible to execute all built tests together. By supporting modular tests we provide a simple way to do selective execution on a running system; specifying
CONFIG_KUNIT=y CONFIG_KUNIT_EXAMPLE_TEST=m
...means we can simply "insmod example-test.ko" to run the tests.
To achieve this we need to do the following:
o export the required symbols in kunit o string-stream tests utilize non-exported symbols so for now we skip building them when CONFIG_KUNIT_TEST=m. o support a new way of declaring test suites. Because a module cannot do multiple late_initcall()s, we provide a kunit_test_suites() macro to declare multiple suites within the same module at once. o some test module names would have been too general ("test-test" and "example-test" for kunit tests, "inode-test" for ext4 tests); rename these as appropriate ("kunit-test", "kunit-example-test" and "ext4-inode-test" respectively).
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Brendan Higgins brendanhiggins@google.com Acked-by: Theodore Ts'o tytso@mit.edu # for ext4 bits Acked-by: David Gow davidgow@google.com # For list-test --- fs/ext4/Kconfig | 2 +- fs/ext4/Makefile | 3 +- fs/ext4/inode-test.c | 4 ++- include/kunit/test.h | 35 +++++++++++++++------- kernel/sysctl-test.c | 4 ++- lib/Kconfig.debug | 4 +-- lib/kunit/Kconfig | 4 +-- lib/kunit/Makefile | 10 +++++-- lib/kunit/assert.c | 8 +++++ lib/kunit/{example-test.c => kunit-example-test.c} | 4 ++- lib/kunit/{test-test.c => kunit-test.c} | 5 ++-- lib/kunit/string-stream-test.c | 2 +- lib/kunit/test.c | 8 +++++ lib/kunit/try-catch.c | 2 ++ lib/list-test.c | 4 ++- 15 files changed, 73 insertions(+), 26 deletions(-) rename lib/kunit/{example-test.c => kunit-example-test.c} (97%) rename lib/kunit/{test-test.c => kunit-test.c} (98%)
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index ef42ab0..435510f 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -108,7 +108,7 @@ config EXT4_DEBUG echo 1 > /sys/module/ext4/parameters/mballoc_debug
config EXT4_KUNIT_TESTS - bool "KUnit tests for ext4" + tristate "KUnit tests for ext4" select EXT4_FS depends on KUNIT help diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 840b91d..4ccb3c9 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -13,5 +13,6 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o -ext4-$(CONFIG_EXT4_KUNIT_TESTS) += inode-test.o +ext4-inode-test-objs += inode-test.o +obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o ext4-$(CONFIG_FS_VERITY) += verity.o diff --git a/fs/ext4/inode-test.c b/fs/ext4/inode-test.c index 92a9da1..95620bf 100644 --- a/fs/ext4/inode-test.c +++ b/fs/ext4/inode-test.c @@ -269,4 +269,6 @@ static void inode_test_xtimestamp_decoding(struct kunit *test) .test_cases = ext4_inode_test_cases, };
-kunit_test_suite(ext4_inode_test_suite); +kunit_test_suites(&ext4_inode_test_suite); + +MODULE_LICENSE("GPL v2"); diff --git a/include/kunit/test.h b/include/kunit/test.h index dba4830..4e21a36 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -12,6 +12,7 @@ #include <kunit/assert.h> #include <kunit/try-catch.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/types.h>
@@ -197,31 +198,45 @@ struct kunit { int kunit_run_tests(struct kunit_suite *suite);
/** - * kunit_test_suite() - used to register a &struct kunit_suite with KUnit. + * kunit_test_suites() - used to register one or more &struct kunit_suite + * with KUnit. * - * @suite: a statically allocated &struct kunit_suite. + * @suites: a statically allocated list of &struct kunit_suite. * - * Registers @suite with the test framework. See &struct kunit_suite for + * Registers @suites with the test framework. See &struct kunit_suite for * more information. * - * NOTE: Currently KUnit tests are all run as late_initcalls; this means + * When builtin, KUnit tests are all run as late_initcalls; this means * that they cannot test anything where tests must run at a different init * phase. One significant restriction resulting from this is that KUnit * cannot reliably test anything that is initialize in the late_init phase; * another is that KUnit is useless to test things that need to be run in * an earlier init phase. * + * An alternative is to build the tests as a module. Because modules + * do not support multiple late_initcall()s, we need to initialize an + * array of suites for a module. + * * TODO(brendanhiggins@google.com): Don't run all KUnit tests as * late_initcalls. I have some future work planned to dispatch all KUnit * tests from the same place, and at the very least to do so after * everything else is definitely initialized. */ -#define kunit_test_suite(suite) \ - static int kunit_suite_init##suite(void) \ - { \ - return kunit_run_tests(&suite); \ - } \ - late_initcall(kunit_suite_init##suite) +#define kunit_test_suites(...) \ + static struct kunit_suite *suites[] = { __VA_ARGS__, NULL}; \ + static int kunit_test_suites_init(void) \ + { \ + unsigned int i; \ + for (i = 0; suites[i] != NULL; i++) \ + kunit_run_tests(suites[i]); \ + return 0; \ + } \ + late_initcall(kunit_test_suites_init); \ + static void __exit kunit_test_suites_exit(void) \ + { \ + return; \ + } \ + module_exit(kunit_test_suites_exit)
/* * Like kunit_alloc_resource() below, but returns the struct kunit_resource diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 2a63241..ccb7850 100644 --- a/kernel/sysctl-test.c +++ b/kernel/sysctl-test.c @@ -389,4 +389,6 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max( .test_cases = sysctl_test_cases, };
-kunit_test_suite(sysctl_test_suite); +kunit_test_suites(&sysctl_test_suite); + +MODULE_LICENSE("GPL v2"); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6c1be61..4b25bef 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1951,7 +1951,7 @@ config TEST_SYSCTL If unsure, say N.
config SYSCTL_KUNIT_TEST - bool "KUnit test for sysctl" + tristate "KUnit test for sysctl" depends on KUNIT help This builds the proc sysctl unit test, which runs on boot. @@ -1962,7 +1962,7 @@ config SYSCTL_KUNIT_TEST If unsure, say N.
config LIST_KUNIT_TEST - bool "KUnit Test for Kernel Linked-list structures" + tristate "KUnit Test for Kernel Linked-list structures" depends on KUNIT help This builds the linked list KUnit test suite. diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig index af37016..9ebd5e6 100644 --- a/lib/kunit/Kconfig +++ b/lib/kunit/Kconfig @@ -15,7 +15,7 @@ menuconfig KUNIT if KUNIT
config KUNIT_TEST - bool "KUnit test for KUnit" + tristate "KUnit test for KUnit" help Enables the unit tests for the KUnit test framework. These tests test the KUnit test framework itself; the tests are both written using @@ -24,7 +24,7 @@ config KUNIT_TEST expected.
config KUNIT_EXAMPLE_TEST - bool "Example test for KUnit" + tristate "Example test for KUnit" help Enables an example unit test that illustrates some of the basic features of KUnit. This test only exists to help new users understand diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index 769d940..bc6e5e54 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -3,7 +3,11 @@ obj-$(CONFIG_KUNIT) += test.o \ assert.o \ try-catch.o
-obj-$(CONFIG_KUNIT_TEST) += test-test.o \ - string-stream-test.o +obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
-obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += example-test.o +# string-stream-test compiles built-in only. +ifeq ($(CONFIG_KUNIT_TEST),y) +obj-$(CONFIG_KUNIT_TEST) += string-stream-test.o +endif + +obj-$(CONFIG_KUNIT_EXAMPLE_TEST) += kunit-example-test.o diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c index 9aca71c..b24bebc 100644 --- a/lib/kunit/assert.c +++ b/lib/kunit/assert.c @@ -26,6 +26,7 @@ void kunit_base_assert_format(const struct kunit_assert *assert, string_stream_add(stream, "%s FAILED at %s:%d\n", expect_or_assert, assert->file, assert->line); } +EXPORT_SYMBOL_GPL(kunit_base_assert_format);
void kunit_assert_print_msg(const struct kunit_assert *assert, struct string_stream *stream) @@ -33,6 +34,7 @@ void kunit_assert_print_msg(const struct kunit_assert *assert, if (assert->message.fmt) string_stream_add(stream, "\n%pV", &assert->message); } +EXPORT_SYMBOL_GPL(kunit_assert_print_msg);
void kunit_fail_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -40,6 +42,7 @@ void kunit_fail_assert_format(const struct kunit_assert *assert, kunit_base_assert_format(assert, stream); string_stream_add(stream, "%pV", &assert->message); } +EXPORT_SYMBOL_GPL(kunit_fail_assert_format);
void kunit_unary_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -58,6 +61,7 @@ void kunit_unary_assert_format(const struct kunit_assert *assert, unary_assert->condition); kunit_assert_print_msg(assert, stream); } +EXPORT_SYMBOL_GPL(kunit_unary_assert_format);
void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -78,6 +82,7 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, } kunit_assert_print_msg(assert, stream); } +EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format);
void kunit_binary_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -99,6 +104,7 @@ void kunit_binary_assert_format(const struct kunit_assert *assert, binary_assert->right_value); kunit_assert_print_msg(assert, stream); } +EXPORT_SYMBOL_GPL(kunit_binary_assert_format);
void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -120,6 +126,7 @@ void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, binary_assert->right_value); kunit_assert_print_msg(assert, stream); } +EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format);
void kunit_binary_str_assert_format(const struct kunit_assert *assert, struct string_stream *stream) @@ -141,3 +148,4 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert, binary_assert->right_value); kunit_assert_print_msg(assert, stream); } +EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format); diff --git a/lib/kunit/example-test.c b/lib/kunit/kunit-example-test.c similarity index 97% rename from lib/kunit/example-test.c rename to lib/kunit/kunit-example-test.c index f64a829..be1164e 100644 --- a/lib/kunit/example-test.c +++ b/lib/kunit/kunit-example-test.c @@ -85,4 +85,6 @@ static int example_test_init(struct kunit *test) * This registers the above test suite telling KUnit that this is a suite of * tests that need to be run. */ -kunit_test_suite(example_test_suite); +kunit_test_suites(&example_test_suite); + +MODULE_LICENSE("GPL v2"); diff --git a/lib/kunit/test-test.c b/lib/kunit/kunit-test.c similarity index 98% rename from lib/kunit/test-test.c rename to lib/kunit/kunit-test.c index 5a6cc04..ccb8d2e 100644 --- a/lib/kunit/test-test.c +++ b/lib/kunit/kunit-test.c @@ -102,7 +102,6 @@ static int kunit_try_catch_test_init(struct kunit *test) .init = kunit_try_catch_test_init, .test_cases = kunit_try_catch_test_cases, }; -kunit_test_suite(kunit_try_catch_test_suite);
/* * Context for testing test managed resources @@ -330,4 +329,6 @@ static void kunit_resource_test_exit(struct kunit *test) .exit = kunit_resource_test_exit, .test_cases = kunit_resource_test_cases, }; -kunit_test_suite(kunit_resource_test_suite); +kunit_test_suites(&kunit_try_catch_test_suite, &kunit_resource_test_suite); + +MODULE_LICENSE("GPL v2"); diff --git a/lib/kunit/string-stream-test.c b/lib/kunit/string-stream-test.c index 6c70dc8..110f3a9 100644 --- a/lib/kunit/string-stream-test.c +++ b/lib/kunit/string-stream-test.c @@ -50,4 +50,4 @@ static void string_stream_test_get_string(struct kunit *test) .name = "string-stream-test", .test_cases = string_stream_test_cases }; -kunit_test_suite(string_stream_test_suite); +kunit_test_suites(&string_stream_test_suite); diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 58a6227..87b5cf1 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -173,6 +173,7 @@ void kunit_do_assertion(struct kunit *test, if (assert->type == KUNIT_ASSERTION) kunit_abort(test); } +EXPORT_SYMBOL_GPL(kunit_do_assertion);
void kunit_init_test(struct kunit *test, const char *name) { @@ -181,6 +182,7 @@ void kunit_init_test(struct kunit *test, const char *name) test->name = name; test->success = true; } +EXPORT_SYMBOL_GPL(kunit_init_test);
/* * Initializes and runs test case. Does not clean up or do post validations. @@ -319,6 +321,7 @@ int kunit_run_tests(struct kunit_suite *suite)
return 0; } +EXPORT_SYMBOL_GPL(kunit_run_tests);
struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test, kunit_resource_init_t init, @@ -344,6 +347,7 @@ struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test,
return res; } +EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource);
static void kunit_resource_free(struct kunit *test, struct kunit_resource *res) { @@ -402,6 +406,7 @@ int kunit_resource_destroy(struct kunit *test, kunit_resource_free(test, resource); return 0; } +EXPORT_SYMBOL_GPL(kunit_resource_destroy);
struct kunit_kmalloc_params { size_t size; @@ -437,6 +442,7 @@ void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) gfp, ¶ms); } +EXPORT_SYMBOL_GPL(kunit_kmalloc);
void kunit_kfree(struct kunit *test, const void *ptr) { @@ -449,6 +455,7 @@ void kunit_kfree(struct kunit *test, const void *ptr)
WARN_ON(rc); } +EXPORT_SYMBOL_GPL(kunit_kfree);
void kunit_cleanup(struct kunit *test) { @@ -478,3 +485,4 @@ void kunit_cleanup(struct kunit *test) kunit_resource_free(test, resource); } } +EXPORT_SYMBOL_GPL(kunit_cleanup); diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 4a66d16..0247a28 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -20,6 +20,7 @@ void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch) try_catch->try_result = -EFAULT; complete_and_exit(try_catch->try_completion, -EFAULT); } +EXPORT_SYMBOL_GPL(kunit_try_catch_throw);
static int kunit_generic_run_threadfn_adapter(void *data) { @@ -107,3 +108,4 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
try_catch->catch(try_catch->context); } +EXPORT_SYMBOL_GPL(kunit_try_catch_run); diff --git a/lib/list-test.c b/lib/list-test.c index 363c600..76babb1 100644 --- a/lib/list-test.c +++ b/lib/list-test.c @@ -743,4 +743,6 @@ static void list_test_list_for_each_entry_reverse(struct kunit *test) .test_cases = list_test_cases, };
-kunit_test_suite(list_test_module); +kunit_test_suites(&list_test_module); + +MODULE_LICENSE("GPL v2");
On Wed, Dec 4, 2019 at 7:28 AM Alan Maguire alan.maguire@oracle.com wrote:
Thanks. Acked-by: Iurii Zaikin yzaikin@google.com # For inode-test, sysctl-test
-- 1.8.3.1
Hi Alan,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master] [also build test ERROR on linux/master v5.5-rc2 next-20191218] [cannot apply to ext4/dev] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Alan-Maguire/kunit-support-building... base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git b0d4beaa5a4b7d31070c41c2e50740304a3f1138 config: x86_64-randconfig-e002-20191218 (attached as .config) compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64
If you fix the issue, kindly add following tag Reported-by: kbuild test robot lkp@intel.com
All errors (new ones prefixed by >>):
drivers/base/power/qos-test.c:117:1: warning: data definition has no type or storage class kunit_test_suite(pm_qos_test_module); ^~~~~~~~~~~~~~~~
drivers/base/power/qos-test.c:117:1: error: type defaults to 'int' in declaration of 'kunit_test_suite' [-Werror=implicit-int]
drivers/base/power/qos-test.c:117:1: warning: parameter names (without types) in function declaration drivers/base/power/qos-test.c:113:27: warning: 'pm_qos_test_module' defined but not used [-Wunused-variable] static struct kunit_suite pm_qos_test_module = { ^~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors
vim +117 drivers/base/power/qos-test.c
14e087576081f4 Leonard Crestez 2019-11-26 112 14e087576081f4 Leonard Crestez 2019-11-26 113 static struct kunit_suite pm_qos_test_module = { 14e087576081f4 Leonard Crestez 2019-11-26 114 .name = "qos-kunit-test", 14e087576081f4 Leonard Crestez 2019-11-26 115 .test_cases = pm_qos_test_cases, 14e087576081f4 Leonard Crestez 2019-11-26 116 }; 14e087576081f4 Leonard Crestez 2019-11-26 @117 kunit_test_suite(pm_qos_test_module);
:::::: The code at line 117 was first introduced by commit :::::: 14e087576081f4f3a6fc6a229166b05b65cf98e5 PM / QoS: Initial kunit test
:::::: TO: Leonard Crestez leonard.crestez@nxp.com :::::: CC: Rafael J. Wysocki rafael.j.wysocki@intel.com
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
On Thu, 19 Dec 2019, kbuild test robot wrote:
Hi Alan,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master] [also build test ERROR on linux/master v5.5-rc2 next-20191218] [cannot apply to ext4/dev] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Alan-Maguire/kunit-support-building... base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git b0d4beaa5a4b7d31070c41c2e50740304a3f1138 config: x86_64-randconfig-e002-20191218 (attached as .config) compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64
If you fix the issue, kindly add following tag Reported-by: kbuild test robot lkp@intel.com
All errors (new ones prefixed by >>):
drivers/base/power/qos-test.c:117:1: warning: data definition has no type or storage class kunit_test_suite(pm_qos_test_module); ^~~~~~~~~~~~~~~~
I hadn't thought about the possibility that other trees would have added kunit tests in the interim; it probably makes most sense to not retire the kunit_test_suite() definition (it can be trivially defined via kunit_test_suites(). Converting the test suite isn't an option as it's not in the kselftest-test tree.
I'll spin up a v7 patchset with that 1-line change to patch 3 as I don't _think_ these changes have been pulled in yet.
Apologies for the noise!
Alan
On 12/19/19 7:28 AM, Alan Maguire wrote:
On Thu, 19 Dec 2019, kbuild test robot wrote:
Hi Alan,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master] [also build test ERROR on linux/master v5.5-rc2 next-20191218] [cannot apply to ext4/dev] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Alan-Maguire/kunit-support-building... base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git b0d4beaa5a4b7d31070c41c2e50740304a3f1138 config: x86_64-randconfig-e002-20191218 (attached as .config) compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=x86_64
If you fix the issue, kindly add following tag Reported-by: kbuild test robot lkp@intel.com
All errors (new ones prefixed by >>):
drivers/base/power/qos-test.c:117:1: warning: data definition has no type or storage class kunit_test_suite(pm_qos_test_module); ^~~~~~~~~~~~~~~~
I hadn't thought about the possibility that other trees would have added kunit tests in the interim; it probably makes most sense to not retire the kunit_test_suite() definition (it can be trivially defined via kunit_test_suites(). Converting the test suite isn't an option as it's not in the kselftest-test tree.
I'll spin up a v7 patchset with that 1-line change to patch 3 as I don't _think_ these changes have been pulled in yet.
Alan,
Please do send v7. I will pull it for 5.6.
thanks, -- Shuah
In discussion of how to handle timeouts, it was noted that if sysctl_hung_task_timeout_seconds is exceeded for a kunit test, the test task will be killed and an oops generated. This should suffice as a means of debugging such timeout issues for now.
Hence remove use of sysctl_hung_task_timeout_secs, which has the added benefit of avoiding the need to export that symbol from the core kernel.
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Stephen Boyd sboyd@kernel.org Acked-by: Brendan Higgins brendanhiggins@google.com --- lib/kunit/try-catch.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-)
diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c index 0247a28..0dd434e 100644 --- a/lib/kunit/try-catch.c +++ b/lib/kunit/try-catch.c @@ -11,7 +11,6 @@ #include <linux/completion.h> #include <linux/kernel.h> #include <linux/kthread.h> -#include <linux/sched/sysctl.h>
#include "try-catch-impl.h"
@@ -33,8 +32,6 @@ static int kunit_generic_run_threadfn_adapter(void *data)
static unsigned long kunit_test_timeout(void) { - unsigned long timeout_msecs; - /* * TODO(brendanhiggins@google.com): We should probably have some type of * variable timeout here. The only question is what that timeout value @@ -51,22 +48,11 @@ static unsigned long kunit_test_timeout(void) * * For more background on this topic, see: * https://mike-bland.com/2011/11/01/small-medium-large.html + * + * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, + * the task will be killed and an oops generated. */ - if (sysctl_hung_task_timeout_secs) { - /* - * If sysctl_hung_task is active, just set the timeout to some - * value less than that. - * - * In regards to the above TODO, if we decide on variable - * timeouts, this logic will likely need to change. - */ - timeout_msecs = (sysctl_hung_task_timeout_secs - 1) * - MSEC_PER_SEC; - } else { - timeout_msecs = 300 * MSEC_PER_SEC; /* 5 min */ - } - - return timeout_msecs; + return 300 * MSEC_PER_SEC; /* 5 min */ }
void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
Making kunit itself buildable as a module allows for "always-on" kunit configuration; specifying CONFIG_KUNIT=m means the module is built but only used when loaded. Kunit test modules will load kunit.ko as an implicit dependency, so simply running "modprobe my-kunit-tests" will load the tests along with the kunit module and run them.
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Brendan Higgins brendanhiggins@google.com --- lib/kunit/Kconfig | 2 +- lib/kunit/Makefile | 4 +++- lib/kunit/test.c | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig index 9ebd5e6..065aa16 100644 --- a/lib/kunit/Kconfig +++ b/lib/kunit/Kconfig @@ -3,7 +3,7 @@ #
menuconfig KUNIT - bool "KUnit - Enable support for unit tests" + tristate "KUnit - Enable support for unit tests" help Enables support for kernel unit tests (KUnit), a lightweight unit testing and mocking framework for the Linux kernel. These tests are diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index bc6e5e54..fab5564 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -1,4 +1,6 @@ -obj-$(CONFIG_KUNIT) += test.o \ +obj-$(CONFIG_KUNIT) += kunit.o + +kunit-objs += test.o \ string-stream.o \ assert.o \ try-catch.o diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 87b5cf1..9242f93 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -486,3 +486,16 @@ void kunit_cleanup(struct kunit *test) } } EXPORT_SYMBOL_GPL(kunit_cleanup); + +static int __init kunit_init(void) +{ + return 0; +} +late_initcall(kunit_init); + +static void __exit kunit_exit(void) +{ +} +module_exit(kunit_exit); + +MODULE_LICENSE("GPL v2");
Documentation should describe how to build kunit and tests as modules.
Co-developed-by: Knut Omang knut.omang@oracle.com Signed-off-by: Knut Omang knut.omang@oracle.com Signed-off-by: Alan Maguire alan.maguire@oracle.com Reviewed-by: Stephen Boyd swboyd@chromium.org Reviewed-by: Brendan Higgins brendanhiggins@google.com --- Documentation/dev-tools/kunit/faq.rst | 3 ++- Documentation/dev-tools/kunit/index.rst | 3 +++ Documentation/dev-tools/kunit/usage.rst | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/Documentation/dev-tools/kunit/faq.rst b/Documentation/dev-tools/kunit/faq.rst index bf20951..ea55b24 100644 --- a/Documentation/dev-tools/kunit/faq.rst +++ b/Documentation/dev-tools/kunit/faq.rst @@ -29,7 +29,8 @@ Yes, well, mostly.
For the most part, the KUnit core framework (what you use to write the tests) can compile to any architecture; it compiles like just another part of the -kernel and runs when the kernel boots. However, there is some infrastructure, +kernel and runs when the kernel boots, or when built as a module, when the +module is loaded. However, there is some infrastructure, like the KUnit Wrapper (``tools/testing/kunit/kunit.py``) that does not support other architectures.
diff --git a/Documentation/dev-tools/kunit/index.rst b/Documentation/dev-tools/kunit/index.rst index 26ffb46..7ddc385 100644 --- a/Documentation/dev-tools/kunit/index.rst +++ b/Documentation/dev-tools/kunit/index.rst @@ -48,6 +48,9 @@ to a standalone program that can be run like any other program directly inside of a host operating system; to be clear, it does not require any virtualization support; it is just a regular program.
+Alternatively, kunit and kunit tests can be built as modules and tests will +run when the test module is loaded. + KUnit is fast. Excluding build time, from invocation to completion KUnit can run several dozen tests in only 10 to 20 seconds; this might not sound like a big deal to some people, but having such fast and easy to run tests fundamentally diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index c6e6963..82f9213 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -539,6 +539,22 @@ Interspersed in the kernel logs you might see the following:
Congratulations, you just ran a KUnit test on the x86 architecture!
+In a similar manner, kunit and kunit tests can also be built as modules, +so if you wanted to run tests in this way you might add the following config +options to your ``.config``: + +.. code-block:: none + + CONFIG_KUNIT=m + CONFIG_KUNIT_EXAMPLE_TEST=m + +Once the kernel is built and installed, a simple + +.. code-block:: bash + modprobe example-test + +...will run the tests. + Writing new tests for other architectures -----------------------------------------
On Wed, Dec 4, 2019 at 7:27 AM Alan Maguire alan.maguire@oracle.com wrote:
The current kunit execution model is to provide base kunit functionality and tests built-in to the kernel. The aim of this series is to allow building kunit itself and tests as modules. This in turn allows a simple form of selective execution; load the module you wish to test. In doing so, kunit itself (if also built as a module) will be loaded as an implicit dependency.
Because this requires a core API modification - if a module delivers multiple suites, they must be declared with the kunit_test_suites() macro - we're proposing this patch set as a candidate to be applied to the test tree before too many kunit consumers appear. We attempt to deal with existing consumers in patch 3.
Hey Alan,
I just wanted to make sure you're not in the dark and wondering what happened in regards to this patchset. To my knowledge, I believe you have all necessary acks/reviewed-bys. As far as I am concerned, everything looks good here and is ready to go. The only remaining bit is Shuah picking it up, and sending it out in a pull request. Based on the nature of this series, it will have to wait until 5.6; however, I think we can accept it into kselftest/test (we are planning on renaming it to kunit-next or something like that) as soon as we cut that, which should be pretty soon.
Feel free to poke us if you have any questions!
Thanks again for all your hard work on this! I think this is going to be a valuable addition to KUnit.
Cheers
Hi Alan,
On 12/4/19 8:27 AM, Alan Maguire wrote:
The current kunit execution model is to provide base kunit functionality and tests built-in to the kernel. The aim of this series is to allow building kunit itself and tests as modules. This in turn allows a simple form of selective execution; load the module you wish to test. In doing so, kunit itself (if also built as a module) will be loaded as an implicit dependency.
Because this requires a core API modification - if a module delivers multiple suites, they must be declared with the kunit_test_suites() macro - we're proposing this patch set as a candidate to be applied to the test tree before too many kunit consumers appear. We attempt to deal with existing consumers in patch 3.
Changes since v5:
- fixed fs/ext4/Makefile to remove unneeded conditional compilation (Iurii, patch 3)
- added Reviewed-by, Acked-by to patches 3, 4, 5 and 6
Are you planning to send v7 to address the kbuild issue? I can pull them in for 5.6
thanks, -- Shuah
linux-kselftest-mirror@lists.linaro.org