Skip to content

Commit 91c6bcc

Browse files
committed
collect rust/testing.rst
1 parent 27ad65f commit 91c6bcc

File tree

1 file changed

+247
-0
lines changed

1 file changed

+247
-0
lines changed

sources/kernel/rust/testing.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
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

Comments
 (0)