| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- .. SPDX-License-Identifier: GPL-2.0
- Testing
- =======
- This document contains useful information how to test the Rust code in the
- kernel.
- There are three sorts of tests:
- - The KUnit tests.
- - The ``#[test]`` tests.
- - The Kselftests.
- The KUnit tests
- ---------------
- These are the tests that come from the examples in the Rust documentation. They
- get transformed into KUnit tests.
- Usage
- *****
- These tests can be run via KUnit. For example via ``kunit_tool`` (``kunit.py``)
- on the command line::
- ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y
- Alternatively, KUnit can run them as kernel built-in at boot. Refer to
- Documentation/dev-tools/kunit/index.rst for the general KUnit documentation
- and Documentation/dev-tools/kunit/architecture.rst for the details of kernel
- built-in vs. command line testing.
- To use these KUnit doctests, the following must be enabled::
- CONFIG_KUNIT
- Kernel hacking -> Kernel Testing and Coverage -> KUnit - Enable support for unit tests
- CONFIG_RUST_KERNEL_DOCTESTS
- Kernel hacking -> Rust hacking -> Doctests for the `kernel` crate
- in the kernel config system.
- KUnit tests are documentation tests
- ***********************************
- These documentation tests are typically examples of usage of any item (e.g.
- function, struct, module...).
- They are very convenient because they are just written alongside the
- documentation. For instance:
- .. code-block:: rust
- /// Sums two numbers.
- ///
- /// ```
- /// assert_eq!(mymod::f(10, 20), 30);
- /// ```
- pub fn f(a: i32, b: i32) -> i32 {
- a + b
- }
- In userspace, the tests are collected and run via ``rustdoc``. Using the tool
- as-is would be useful already, since it allows verifying that examples compile
- (thus enforcing they are kept in sync with the code they document) and as well
- as running those that do not depend on in-kernel APIs.
- For the kernel, however, these tests get transformed into KUnit test suites.
- This means that doctests get compiled as Rust kernel objects, allowing them to
- run against a built kernel.
- A benefit of this KUnit integration is that Rust doctests get to reuse existing
- testing facilities. For instance, the kernel log would look like::
- KTAP version 1
- 1..1
- KTAP version 1
- # Subtest: rust_doctests_kernel
- 1..59
- # rust_doctest_kernel_build_assert_rs_0.location: rust/kernel/build_assert.rs:13
- ok 1 rust_doctest_kernel_build_assert_rs_0
- # rust_doctest_kernel_build_assert_rs_1.location: rust/kernel/build_assert.rs:56
- ok 2 rust_doctest_kernel_build_assert_rs_1
- # rust_doctest_kernel_init_rs_0.location: rust/kernel/init.rs:122
- ok 3 rust_doctest_kernel_init_rs_0
- ...
- # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
- ok 59 rust_doctest_kernel_types_rs_2
- # rust_doctests_kernel: pass:59 fail:0 skip:0 total:59
- # Totals: pass:59 fail:0 skip:0 total:59
- ok 1 rust_doctests_kernel
- Tests using the `? <https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator>`_
- operator are also supported as usual, e.g.:
- .. code-block:: rust
- /// ```
- /// # use kernel::{spawn_work_item, workqueue};
- /// spawn_work_item!(workqueue::system(), || pr_info!("x\n"))?;
- /// # Ok::<(), Error>(())
- /// ```
- The tests are also compiled with Clippy under ``CLIPPY=1``, just like normal
- code, thus also benefitting from extra linting.
- In order for developers to easily see which line of doctest code caused a
- failure, a KTAP diagnostic line is printed to the log. This contains the
- location (file and line) of the original test (i.e. instead of the location in
- the generated Rust file)::
- # rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
- Rust tests appear to assert using the usual ``assert!`` and ``assert_eq!``
- macros from the Rust standard library (``core``). We provide a custom version
- that forwards the call to KUnit instead. Importantly, these macros do not
- require passing context, unlike those for KUnit testing (i.e.
- ``struct kunit *``). This makes them easier to use, and readers of the
- documentation do not need to care about which testing framework is used. In
- addition, it may allow us to test third-party code more easily in the future.
- A current limitation is that KUnit does not support assertions in other tasks.
- Thus, we presently simply print an error to the kernel log if an assertion
- actually failed. Additionally, doctests are not run for nonpublic functions.
- Since these tests are examples, i.e. they are part of the documentation, they
- should generally be written like "real code". Thus, for example, instead of
- using ``unwrap()`` or ``expect()``, use the ``?`` operator. For more background,
- please see:
- https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
- The ``#[test]`` tests
- ---------------------
- Additionally, there are the ``#[test]`` tests. Like for documentation tests,
- these are also fairly similar to what you would expect from userspace, and they
- are also mapped to KUnit.
- These tests are introduced by the ``kunit_tests`` procedural macro, which takes
- the name of the test suite as an argument.
- For instance, assume we want to test the function ``f`` from the documentation
- tests section. We could write, in the same file where we have our function:
- .. code-block:: rust
- #[kunit_tests(rust_kernel_mymod)]
- mod tests {
- use super::*;
- #[test]
- fn test_f() {
- assert_eq!(f(10, 20), 30);
- }
- }
- And if we run it, the kernel log would look like::
- KTAP version 1
- # Subtest: rust_kernel_mymod
- # speed: normal
- 1..1
- # test_f.speed: normal
- ok 1 test_f
- ok 1 rust_kernel_mymod
- Like documentation tests, the ``assert!`` and ``assert_eq!`` macros are mapped
- back to KUnit and do not panic. Similarly, the
- `? <https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator>`_
- operator is supported, i.e. the test functions may return either nothing (i.e.
- the unit type ``()``) or ``Result`` (i.e. any ``Result<T, E>``). For instance:
- .. code-block:: rust
- #[kunit_tests(rust_kernel_mymod)]
- mod tests {
- use super::*;
- #[test]
- fn test_g() -> Result {
- let x = g()?;
- assert_eq!(x, 30);
- Ok(())
- }
- }
- If we run the test and the call to ``g`` fails, then the kernel log would show::
- KTAP version 1
- # Subtest: rust_kernel_mymod
- # speed: normal
- 1..1
- # test_g: ASSERTION FAILED at rust/kernel/lib.rs:335
- Expected is_test_result_ok(test_g()) to be true, but is false
- # test_g.speed: normal
- not ok 1 test_g
- not ok 1 rust_kernel_mymod
- If a ``#[test]`` test could be useful as an example for the user, then please
- use a documentation test instead. Even edge cases of an API, e.g. error or
- boundary cases, can be interesting to show in examples.
- The ``rusttest`` host tests
- ---------------------------
- These are userspace tests that can be built and run in the host (i.e. the one
- that performs the kernel build) using the ``rusttest`` Make target::
- make LLVM=1 rusttest
- This requires the kernel ``.config``.
- Currently, they are mostly used for testing the ``macros`` crate's examples.
- The Kselftests
- --------------
- Kselftests are also available in the ``tools/testing/selftests/rust`` folder.
- The kernel config options required for the tests are listed in the
- ``tools/testing/selftests/rust/config`` file and can be included with the aid
- of the ``merge_config.sh`` script::
- ./scripts/kconfig/merge_config.sh .config tools/testing/selftests/rust/config
- The kselftests are built within the kernel source tree and are intended to
- be executed on a system that is running the same kernel.
- Once a kernel matching the source tree has been installed and booted, the
- tests can be compiled and executed using the following command::
- make TARGETS="rust" kselftest
- Refer to Documentation/dev-tools/kselftest.rst for the general Kselftest
- documentation.
|