|
| 1 | +--- |
| 2 | +status: collected |
| 3 | +title: "Testing" |
| 4 | +author: Linux Kernel Community |
| 5 | +collector: mudongliang |
| 6 | +collected_date: 20250917 |
| 7 | +link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/rust/testing.rst |
| 8 | +--- |
| 9 | + |
| 10 | +# Testing |
| 11 | + |
| 12 | +This document contains useful information how to test the Rust code in |
| 13 | +the kernel. |
| 14 | + |
| 15 | +There are three sorts of tests: |
| 16 | + |
| 17 | +- The KUnit tests. |
| 18 | +- The `#[test]` tests. |
| 19 | +- The Kselftests. |
| 20 | + |
| 21 | +## The KUnit tests |
| 22 | + |
| 23 | +These are the tests that come from the examples in the Rust |
| 24 | +documentation. They get transformed into KUnit tests. |
| 25 | + |
| 26 | +### Usage |
| 27 | + |
| 28 | +These tests can be run via KUnit. For example via `kunit_tool` |
| 29 | +(`kunit.py`) on the command line: |
| 30 | + |
| 31 | + ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y |
| 32 | + |
| 33 | +Alternatively, KUnit can run them as kernel built-in at boot. Refer to |
| 34 | +Documentation/dev-tools/kunit/index.rst for the general KUnit |
| 35 | +documentation and Documentation/dev-tools/kunit/architecture.rst for the |
| 36 | +details of kernel built-in vs. command line testing. |
| 37 | + |
| 38 | +To use these KUnit doctests, the following must be enabled: |
| 39 | + |
| 40 | + CONFIG_KUNIT |
| 41 | + Kernel hacking -> Kernel Testing and Coverage -> KUnit - Enable support for unit tests |
| 42 | + CONFIG_RUST_KERNEL_DOCTESTS |
| 43 | + Kernel hacking -> Rust hacking -> Doctests for the `kernel` crate |
| 44 | + |
| 45 | +in the kernel config system. |
| 46 | + |
| 47 | +### KUnit tests are documentation tests |
| 48 | + |
| 49 | +These documentation tests are typically examples of usage of any item |
| 50 | +(e.g. function, struct, module\...). |
| 51 | + |
| 52 | +They are very convenient because they are just written alongside the |
| 53 | +documentation. For instance: |
| 54 | + |
| 55 | +``` rust |
| 56 | +/// Sums two numbers. |
| 57 | +/// |
| 58 | +/// ``` |
| 59 | +/// assert_eq!(mymod::f(10, 20), 30); |
| 60 | +/// ``` |
| 61 | +pub fn f(a: i32, b: i32) -> i32 { |
| 62 | + a + b |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +In userspace, the tests are collected and run via `rustdoc`. Using the |
| 67 | +tool as-is would be useful already, since it allows verifying that |
| 68 | +examples compile (thus enforcing they are kept in sync with the code |
| 69 | +they document) and as well as running those that do not depend on |
| 70 | +in-kernel APIs. |
| 71 | + |
| 72 | +For the kernel, however, these tests get transformed into KUnit test |
| 73 | +suites. This means that doctests get compiled as Rust kernel objects, |
| 74 | +allowing them to run against a built kernel. |
| 75 | + |
| 76 | +A benefit of this KUnit integration is that Rust doctests get to reuse |
| 77 | +existing testing facilities. For instance, the kernel log would look |
| 78 | +like: |
| 79 | + |
| 80 | + KTAP version 1 |
| 81 | + 1..1 |
| 82 | + KTAP version 1 |
| 83 | + # Subtest: rust_doctests_kernel |
| 84 | + 1..59 |
| 85 | + # rust_doctest_kernel_build_assert_rs_0.location: rust/kernel/build_assert.rs:13 |
| 86 | + ok 1 rust_doctest_kernel_build_assert_rs_0 |
| 87 | + # rust_doctest_kernel_build_assert_rs_1.location: rust/kernel/build_assert.rs:56 |
| 88 | + ok 2 rust_doctest_kernel_build_assert_rs_1 |
| 89 | + # rust_doctest_kernel_init_rs_0.location: rust/kernel/init.rs:122 |
| 90 | + ok 3 rust_doctest_kernel_init_rs_0 |
| 91 | + ... |
| 92 | + # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150 |
| 93 | + ok 59 rust_doctest_kernel_types_rs_2 |
| 94 | + # rust_doctests_kernel: pass:59 fail:0 skip:0 total:59 |
| 95 | + # Totals: pass:59 fail:0 skip:0 total:59 |
| 96 | + ok 1 rust_doctests_kernel |
| 97 | + |
| 98 | +Tests using the |
| 99 | +[?](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) |
| 100 | +operator are also supported as usual, e.g.: |
| 101 | + |
| 102 | +``` rust |
| 103 | +/// ``` |
| 104 | +/// # use kernel::{spawn_work_item, workqueue}; |
| 105 | +/// spawn_work_item!(workqueue::system(), || pr_info!("x\n"))?; |
| 106 | +/// # Ok::<(), Error>(()) |
| 107 | +/// ``` |
| 108 | +``` |
| 109 | + |
| 110 | +The tests are also compiled with Clippy under `CLIPPY=1`, just like |
| 111 | +normal code, thus also benefitting from extra linting. |
| 112 | + |
| 113 | +In order for developers to easily see which line of doctest code caused |
| 114 | +a failure, a KTAP diagnostic line is printed to the log. This contains |
| 115 | +the location (file and line) of the original test (i.e. instead of the |
| 116 | +location in the generated Rust file): |
| 117 | + |
| 118 | + # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150 |
| 119 | + |
| 120 | +Rust tests appear to assert using the usual `assert!` and `assert_eq!` |
| 121 | +macros from the Rust standard library (`core`). We provide a custom |
| 122 | +version that forwards the call to KUnit instead. Importantly, these |
| 123 | +macros do not require passing context, unlike those for KUnit testing |
| 124 | +(i.e. `struct kunit *`). This makes them easier to use, and readers of |
| 125 | +the documentation do not need to care about which testing framework is |
| 126 | +used. In addition, it may allow us to test third-party code more easily |
| 127 | +in the future. |
| 128 | + |
| 129 | +A current limitation is that KUnit does not support assertions in other |
| 130 | +tasks. Thus, we presently simply print an error to the kernel log if an |
| 131 | +assertion actually failed. Additionally, doctests are not run for |
| 132 | +nonpublic functions. |
| 133 | + |
| 134 | +Since these tests are examples, i.e. they are part of the documentation, |
| 135 | +they should generally be written like \"real code\". Thus, for example, |
| 136 | +instead of using `unwrap()` or `expect()`, use the `?` operator. For |
| 137 | +more background, please see: |
| 138 | + |
| 139 | +> <https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust> |
| 140 | +
|
| 141 | +## The `#[test]` tests |
| 142 | + |
| 143 | +Additionally, there are the `#[test]` tests. Like for documentation |
| 144 | +tests, these are also fairly similar to what you would expect from |
| 145 | +userspace, and they are also mapped to KUnit. |
| 146 | + |
| 147 | +These tests are introduced by the `kunit_tests` procedural macro, which |
| 148 | +takes the name of the test suite as an argument. |
| 149 | + |
| 150 | +For instance, assume we want to test the function `f` from the |
| 151 | +documentation tests section. We could write, in the same file where we |
| 152 | +have our function: |
| 153 | + |
| 154 | +``` rust |
| 155 | +#[kunit_tests(rust_kernel_mymod)] |
| 156 | +mod tests { |
| 157 | + use super::*; |
| 158 | + |
| 159 | + #[test] |
| 160 | + fn test_f() { |
| 161 | + assert_eq!(f(10, 20), 30); |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +And if we run it, the kernel log would look like: |
| 167 | + |
| 168 | + KTAP version 1 |
| 169 | + # Subtest: rust_kernel_mymod |
| 170 | + # speed: normal |
| 171 | + 1..1 |
| 172 | + # test_f.speed: normal |
| 173 | + ok 1 test_f |
| 174 | + ok 1 rust_kernel_mymod |
| 175 | + |
| 176 | +Like documentation tests, the `assert!` and `assert_eq!` macros are |
| 177 | +mapped back to KUnit and do not panic. Similarly, the |
| 178 | +[?](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) |
| 179 | +operator is supported, i.e. the test functions may return either nothing |
| 180 | +(i.e. the unit type `()`) or `Result` (i.e. any `Result<T, E>`). For |
| 181 | +instance: |
| 182 | + |
| 183 | +``` rust |
| 184 | +#[kunit_tests(rust_kernel_mymod)] |
| 185 | +mod tests { |
| 186 | + use super::*; |
| 187 | + |
| 188 | + #[test] |
| 189 | + fn test_g() -> Result { |
| 190 | + let x = g()?; |
| 191 | + assert_eq!(x, 30); |
| 192 | + Ok(()) |
| 193 | + } |
| 194 | +} |
| 195 | +``` |
| 196 | + |
| 197 | +If we run the test and the call to `g` fails, then the kernel log would |
| 198 | +show: |
| 199 | + |
| 200 | + KTAP version 1 |
| 201 | + # Subtest: rust_kernel_mymod |
| 202 | + # speed: normal |
| 203 | + 1..1 |
| 204 | + # test_g: ASSERTION FAILED at rust/kernel/lib.rs:335 |
| 205 | + Expected is_test_result_ok(test_g()) to be true, but is false |
| 206 | + # test_g.speed: normal |
| 207 | + not ok 1 test_g |
| 208 | + not ok 1 rust_kernel_mymod |
| 209 | + |
| 210 | +If a `#[test]` test could be useful as an example for the user, then |
| 211 | +please use a documentation test instead. Even edge cases of an API, e.g. |
| 212 | +error or boundary cases, can be interesting to show in examples. |
| 213 | + |
| 214 | +## The `rusttest` host tests |
| 215 | + |
| 216 | +These are userspace tests that can be built and run in the host (i.e. |
| 217 | +the one that performs the kernel build) using the `rusttest` Make |
| 218 | +target: |
| 219 | + |
| 220 | + make LLVM=1 rusttest |
| 221 | + |
| 222 | +This requires the kernel `.config`. |
| 223 | + |
| 224 | +Currently, they are mostly used for testing the `macros` crate\'s |
| 225 | +examples. |
| 226 | + |
| 227 | +## The Kselftests |
| 228 | + |
| 229 | +Kselftests are also available in the `tools/testing/selftests/rust` |
| 230 | +folder. |
| 231 | + |
| 232 | +The kernel config options required for the tests are listed in the |
| 233 | +`tools/testing/selftests/rust/config` file and can be included with the |
| 234 | +aid of the `merge_config.sh` script: |
| 235 | + |
| 236 | + ./scripts/kconfig/merge_config.sh .config tools/testing/selftests/rust/config |
| 237 | + |
| 238 | +The kselftests are built within the kernel source tree and are intended |
| 239 | +to be executed on a system that is running the same kernel. |
| 240 | + |
| 241 | +Once a kernel matching the source tree has been installed and booted, |
| 242 | +the tests can be compiled and executed using the following command: |
| 243 | + |
| 244 | + make TARGETS="rust" kselftest |
| 245 | + |
| 246 | +Refer to Documentation/dev-tools/kselftest.rst for the general Kselftest |
| 247 | +documentation. |
0 commit comments