Commit 100af58c authored by José Expósito's avatar José Expósito Committed by Miguel Ojeda
Browse files

rust: kunit: allow to know if we are in a test



In some cases, we need to call test-only code from outside the test
case, for example, to mock a function or a module.

In order to check whether we are in a test or not, we need to test if
`CONFIG_KUNIT` is set.
Unfortunately, we cannot rely only on this condition because:
- a test could be running in another thread,
- some distros compile KUnit in production kernels, so checking at runtime
  that `current->kunit_test != NULL` is required.

Forturately, KUnit provides an optimised check in
`kunit_get_current_test()`, which checks CONFIG_KUNIT, a global static
key, and then the current thread's running KUnit test.

Add a safe wrapper function around this to know whether or not we are in
a KUnit test and examples showing how to mock a function and a module.

Signed-off-by: default avatarJosé Expósito <jose.exposito89@gmail.com>
Co-developed-by: default avatarMiguel Ojeda <ojeda@kernel.org>
Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
Co-developed-by: default avatarDavid Gow <davidgow@google.com>
Signed-off-by: default avatarDavid Gow <davidgow@google.com>
Link: https://lore.kernel.org/r/20250307090103.918788-4-davidgow@google.com


Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent c0010452
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -288,11 +288,47 @@ macro_rules! kunit_unsafe_test_suite {
    };
}

/// Returns whether we are currently running a KUnit test.
///
/// In some cases, you need to call test-only code from outside the test case, for example, to
/// create a function mock. This function allows to change behavior depending on whether we are
/// currently running a KUnit test or not.
///
/// # Examples
///
/// This example shows how a function can be mocked to return a well-known value while testing:
///
/// ```
/// # use kernel::kunit::in_kunit_test;
/// fn fn_mock_example(n: i32) -> i32 {
///     if in_kunit_test() {
///         return 100;
///     }
///
///     n + 1
/// }
///
/// let mock_res = fn_mock_example(5);
/// assert_eq!(mock_res, 100);
/// ```
pub fn in_kunit_test() -> bool {
    // SAFETY: `kunit_get_current_test()` is always safe to call (it has fallbacks for
    // when KUnit is not enabled).
    !unsafe { bindings::kunit_get_current_test() }.is_null()
}

#[kunit_tests(rust_kernel_kunit)]
mod tests {
    use super::*;

    #[test]
    fn rust_test_kunit_example_test() {
        #![expect(clippy::eq_op)]
        assert_eq!(1 + 1, 2);
    }

    #[test]
    fn rust_test_kunit_in_kunit_test() {
        assert!(in_kunit_test());
    }
}