Skip to content

Commit

Permalink
rust: kunit: allow to know if we are in a test
Browse files Browse the repository at this point in the history
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: José Expósito <jose.exposito89@gmail.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Link: https://lore.kernel.org/r/20250307090103.918788-4-davidgow@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
José Expósito authored and Miguel Ojeda committed Mar 20, 2025
1 parent c001045 commit 100af58
Showing 1 changed file with 36 additions and 0 deletions.
36 changes: 36 additions & 0 deletions rust/kernel/kunit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

0 comments on commit 100af58

Please sign in to comment.