diff options
-rw-r--r-- | Documentation/dev-tools/kunit/usage.rst | 30 | ||||
-rw-r--r-- | include/kunit/test-bug.h | 53 |
2 files changed, 71 insertions, 12 deletions
diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index 22416ebb94ab..48f8196d5aad 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -641,17 +641,23 @@ as shown in next section: *Accessing The Current Test*. Accessing The Current Test -------------------------- -In some cases, we need to call test-only code from outside the test file. -For example, see example in section *Injecting Test-Only Code* or if -we are providing a fake implementation of an ops struct. Using -``kunit_test`` field in ``task_struct``, we can access it via -``current->kunit_test``. +In some cases, we need to call test-only code from outside the test file. This +is helpful, for example, when providing a fake implementation of a function, or +to fail any current test from within an error handler. +We can do this via the ``kunit_test`` field in ``task_struct``, which we can +access using the ``kunit_get_current_test()`` function in ``kunit/test-bug.h``. -The example below includes how to implement "mocking": +``kunit_get_current_test()`` is safe to call even if KUnit is not enabled. If +KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is +running in the current task, it will return ``NULL``. This compiles down to +either a no-op or a static key check, so will have a negligible performance +impact when no test is running. + +The example below uses this to implement a "mock" implementation of a function, ``foo``: .. code-block:: c - #include <linux/sched.h> /* for current */ + #include <kunit/test-bug.h> /* for kunit_get_current_test */ struct test_data { int foo_result; @@ -660,7 +666,7 @@ The example below includes how to implement "mocking": static int fake_foo(int arg) { - struct kunit *test = current->kunit_test; + struct kunit *test = kunit_get_current_test(); struct test_data *test_data = test->priv; KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg); @@ -691,7 +697,7 @@ Each test can have multiple resources which have string names providing the same flexibility as a ``priv`` member, but also, for example, allowing helper functions to create resources without conflicting with each other. It is also possible to define a clean up function for each resource, making it easy to -avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/test.rst. +avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/resource.rst. Failing The Current Test ------------------------ @@ -719,3 +725,9 @@ structures as shown below: static void my_debug_function(void) { } #endif +``kunit_fail_current_test()`` is safe to call even if KUnit is not enabled. If +KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is +running in the current task, it will do nothing. This compiles down to either a +no-op or a static key check, so will have a negligible performance impact when +no test is running. + diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h index 5fc58081d511..c1b2e14eab64 100644 --- a/include/kunit/test-bug.h +++ b/include/kunit/test-bug.h @@ -9,16 +9,63 @@ #ifndef _KUNIT_TEST_BUG_H #define _KUNIT_TEST_BUG_H -#define kunit_fail_current_test(fmt, ...) \ - __kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__) - #if IS_BUILTIN(CONFIG_KUNIT) +#include <linux/jump_label.h> /* For static branch */ +#include <linux/sched.h> + +/* Static key if KUnit is running any tests. */ +DECLARE_STATIC_KEY_FALSE(kunit_running); + +/** + * kunit_get_current_test() - Return a pointer to the currently running + * KUnit test. + * + * If a KUnit test is running in the current task, returns a pointer to its + * associated struct kunit. This pointer can then be passed to any KUnit + * function or assertion. If no test is running (or a test is running in a + * different task), returns NULL. + * + * This function is safe to call even when KUnit is disabled. If CONFIG_KUNIT + * is not enabled, it will compile down to nothing and will return quickly no + * test is running. + */ +static inline struct kunit *kunit_get_current_test(void) +{ + if (!static_branch_unlikely(&kunit_running)) + return NULL; + + return current->kunit_test; +} + + +/** + * kunit_fail_current_test() - If a KUnit test is running, fail it. + * + * If a KUnit test is running in the current task, mark that test as failed. + * + * This macro will only work if KUnit is built-in (though the tests + * themselves can be modules). Otherwise, it compiles down to nothing. + */ +#define kunit_fail_current_test(fmt, ...) do { \ + if (static_branch_unlikely(&kunit_running)) { \ + __kunit_fail_current_test(__FILE__, __LINE__, \ + fmt, ##__VA_ARGS__); \ + } \ + } while (0) + + extern __printf(3, 4) void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...); #else +static inline struct kunit *kunit_get_current_test(void) { return NULL; } + +/* We define this with an empty helper function so format string warnings work */ +#define kunit_fail_current_test(fmt, ...) \ + __kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__) + static inline __printf(3, 4) void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...) { |