Skip to content

Commit

Permalink
Merge pull request raspberrypi#757 from ojeda/tests
Browse files Browse the repository at this point in the history
Support running documentation tests in-kernel
  • Loading branch information
ojeda committed May 5, 2022
2 parents f063324 + d5e044e commit 8a46b49
Show file tree
Hide file tree
Showing 52 changed files with 637 additions and 273 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yaml
Expand Up @@ -266,6 +266,9 @@ jobs:
! grep -v 'at mm/debug_vm_pgtable.c:' qemu-stdout.log | grep '] WARNING:'
# Check
- run: |
grep '] ok 1 - rust_kernel_doctests$' qemu-stdout.log
- run: |
grep '] rust_minimal: Rust minimal sample (init)$' qemu-stdout.log
grep '] rust_minimal: Am I built-in? false$' qemu-stdout.log
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm-debug.config
Expand Up @@ -1802,7 +1802,7 @@ CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
Expand All @@ -1827,6 +1827,7 @@ CONFIG_RUST_OPT_LEVEL_2=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm-release.config
Expand Up @@ -1725,7 +1725,7 @@ CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
Expand Down Expand Up @@ -1785,6 +1785,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm64-debug-thinlto.config
Expand Up @@ -1450,7 +1450,7 @@ CONFIG_PID_IN_CONTEXTIDR=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
Expand All @@ -1476,6 +1476,7 @@ CONFIG_RUST_OPT_LEVEL_1=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm64-debug.config
Expand Up @@ -1445,7 +1445,7 @@ CONFIG_PID_IN_CONTEXTIDR=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
CONFIG_FUNCTION_ERROR_INJECTION=y
# CONFIG_FAULT_INJECTION is not set
Expand All @@ -1471,6 +1471,7 @@ CONFIG_RUST_OPT_LEVEL_1=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm64-release-thinlto.config
Expand Up @@ -1368,7 +1368,7 @@ CONFIG_SAMPLE_RUST_HOSTPROGS=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
Expand All @@ -1393,6 +1393,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-arm64-release.config
Expand Up @@ -1363,7 +1363,7 @@ CONFIG_SAMPLE_RUST_HOSTPROGS=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
Expand All @@ -1388,6 +1388,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/kernel-ppc64le-debug.config
Expand Up @@ -1592,6 +1592,7 @@ CONFIG_RUST_OPT_LEVEL_0=y
# CONFIG_RUST_OPT_LEVEL_Z is not set
CONFIG_RUST_BUILD_ASSERT_ALLOW=y
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-ppc64le-release.config
Expand Up @@ -1473,7 +1473,7 @@ CONFIG_PRINT_STACK_DEPTH=64
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
Expand All @@ -1496,6 +1496,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-riscv64-debug.config
Expand Up @@ -1296,7 +1296,7 @@ CONFIG_SAMPLE_RUST_HOSTPROGS=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
# CONFIG_FAULT_INJECTION is not set
CONFIG_ARCH_HAS_KCOV=y
Expand All @@ -1320,6 +1320,7 @@ CONFIG_RUST_OPT_LEVEL_0=y
# CONFIG_RUST_OPT_LEVEL_Z is not set
CONFIG_RUST_BUILD_ASSERT_ALLOW=y
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-riscv64-release.config
Expand Up @@ -1212,7 +1212,7 @@ CONFIG_SAMPLE_RUST_HOSTPROGS=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
Expand All @@ -1235,6 +1235,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/kernel-x86_64-debug-thinlto.config
Expand Up @@ -1543,6 +1543,7 @@ CONFIG_RUST_OPT_LEVEL_0=y
# CONFIG_RUST_OPT_LEVEL_Z is not set
CONFIG_RUST_BUILD_ASSERT_ALLOW=y
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/kernel-x86_64-debug.config
Expand Up @@ -1546,6 +1546,7 @@ CONFIG_RUST_OPT_LEVEL_0=y
# CONFIG_RUST_OPT_LEVEL_Z is not set
CONFIG_RUST_BUILD_ASSERT_ALLOW=y
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-x86_64-release-thinlto.config
Expand Up @@ -1420,7 +1420,7 @@ CONFIG_UNWINDER_ORC=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
Expand All @@ -1443,6 +1443,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/kernel-x86_64-release.config
Expand Up @@ -1415,7 +1415,7 @@ CONFIG_UNWINDER_ORC=y
#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
CONFIG_KUNIT=y
CONFIG_ARCH_HAS_KCOV=y
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
# CONFIG_KCOV is not set
Expand All @@ -1438,6 +1438,7 @@ CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# CONFIG_RUST_BUILD_ASSERT_WARN is not set
CONFIG_RUST_BUILD_ASSERT_DENY=y
CONFIG_RUST_KERNEL_KUNIT_TEST=y
# end of Rust hacking
# end of Kernel hacking

Expand Down
2 changes: 1 addition & 1 deletion include/kunit/test.h
Expand Up @@ -774,7 +774,7 @@ void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...);
void kunit_do_failed_assertion(struct kunit *test,
const struct kunit_loc *loc,
enum kunit_assert_type type,
struct kunit_assert *assert,
const struct kunit_assert *assert,
const char *fmt, ...);

#define KUNIT_ASSERTION(test, assert_type, pass, assert_class, INITIALIZER, fmt, ...) do { \
Expand Down
12 changes: 12 additions & 0 deletions lib/Kconfig.debug
Expand Up @@ -2900,6 +2900,18 @@ config RUST_BUILD_ASSERT_DENY

endchoice

config RUST_KERNEL_KUNIT_TEST
bool "KUnit test for the `kernel` crate" if !KUNIT_ALL_TESTS
depends on RUST && KUNIT=y
default KUNIT_ALL_TESTS
help
This builds the documentation tests of the `kernel` crate
as KUnit tests.

For more information on KUnit and unit tests in general,
please refer to the KUnit documentation in Documentation/dev-tools/kunit/.

If unsure, say N.

endmenu # "Rust"

Expand Down
4 changes: 2 additions & 2 deletions lib/kunit/test.c
Expand Up @@ -241,7 +241,7 @@ static void kunit_print_string_stream(struct kunit *test,
}

static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
enum kunit_assert_type type, struct kunit_assert *assert,
enum kunit_assert_type type, const struct kunit_assert *assert,
const struct va_format *message)
{
struct string_stream *stream;
Expand Down Expand Up @@ -281,7 +281,7 @@ static void __noreturn kunit_abort(struct kunit *test)
void kunit_do_failed_assertion(struct kunit *test,
const struct kunit_loc *loc,
enum kunit_assert_type type,
struct kunit_assert *assert,
const struct kunit_assert *assert,
const char *fmt, ...)
{
va_list args;
Expand Down
2 changes: 2 additions & 0 deletions rust/.gitignore
Expand Up @@ -4,5 +4,7 @@ target.json
bindings_generated.rs
bindings_helpers_generated.rs
exports_*_generated.h
doctests_kernel_generated.rs
doctests_kernel_generated_kunit.c
doc/
test/
23 changes: 22 additions & 1 deletion rust/Makefile
Expand Up @@ -26,6 +26,9 @@ endif

obj-$(CONFIG_RUST) += exports.o

obj-$(CONFIG_RUST_KERNEL_KUNIT_TEST) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_KUNIT_TEST) += doctests_kernel_generated_kunit.o

# Avoids running `$(RUSTC)` for the sysroot when it may not be available.
ifdef CONFIG_RUST

Expand All @@ -38,9 +41,11 @@ ifeq ($(quiet),silent_)
cargo_quiet=-q
rust_test_quiet=-q
rustdoc_test_quiet=--test-args -q
rustdoc_test_kernel_quiet=>/dev/null
else ifeq ($(quiet),quiet_)
rust_test_quiet=-q
rustdoc_test_quiet=--test-args -q
rustdoc_test_kernel_quiet=>/dev/null
else
cargo_quiet=--verbose
endif
Expand Down Expand Up @@ -139,6 +144,23 @@ quiet_cmd_rustdoc_test = RUSTDOC T $<
-L$(objtree)/$(obj)/test --output $(objtree)/$(obj)/doc \
--crate-name $(subst rusttest-,,$@) $<

quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
cmd_rustdoc_test_kernel = \
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_flags) \
@$(objtree)/include/generated/rustc_cfg \
-L$(objtree)/$(obj) --extern alloc --extern kernel \
--extern build_error --extern macros \
--no-run --crate-name kernel -Zunstable-options \
--test-builder $(srctree)/scripts/rustdoc_test_builder.py \
$< $(rustdoc_test_kernel_quiet); \
$(srctree)/scripts/rustdoc_test_gen.py

%/doctests_kernel_generated.rs %/doctests_kernel_generated_kunit.c: $(src)/kernel/lib.rs $(obj)/kernel.o FORCE
$(call if_changed,rustdoc_test_kernel)

# We cannot use `-Zpanic-abort-tests` because some tests are dynamic,
# so for the moment we skip `-Cpanic=abort`.
quiet_cmd_rustc_test = RUSTC T $<
Expand Down Expand Up @@ -217,7 +239,6 @@ rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \
rusttestlib-build_error rusttestlib-macros FORCE
$(call if_changed,rustc_test)
$(call if_changed,rustc_test_library)
$(call if_changed,rustdoc_test)

filechk_rust_target = $(objtree)/scripts/generate_rust_target < $<

Expand Down
4 changes: 4 additions & 0 deletions rust/bindgen_parameters
Expand Up @@ -5,6 +5,10 @@
--opaque-type arch_lbr_state
--opaque-type local_apic

# `try` is a reserved keyword since Rust 2018; solved in `bindgen` v0.59.2,
# commit 2aed6b021680 ("context: Escape the try keyword properly").
--opaque-type kunit_try_catch

# If SMP is disabled, `arch_spinlock_t` is defined as a ZST which triggers a Rust
# warning. We don't need to peek into it anyway.
--opaque-type spinlock
Expand Down
2 changes: 0 additions & 2 deletions rust/kernel/amba.rs
Expand Up @@ -204,7 +204,6 @@ unsafe impl device::RawDevice for Device {
/// # Examples
///
/// ```ignore
/// # use kernel::prelude::*;
/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
/// #
/// struct MyDriver;
Expand Down Expand Up @@ -237,7 +236,6 @@ macro_rules! module_amba_driver {
/// # Examples
///
/// ```
/// # use kernel::prelude::*;
/// # use kernel::{amba, define_amba_id_table};
/// #
/// # struct Sample;
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/bindings_helper.h
Expand Up @@ -7,6 +7,7 @@
*/

#include <asm/io.h>
#include <kunit/test.h>
#include <linux/amba/bus.h>
#include <linux/cdev.h>
#include <linux/clk.h>
Expand Down
10 changes: 6 additions & 4 deletions rust/kernel/build_assert.rs
Expand Up @@ -15,6 +15,9 @@
/// fn foo(a: usize) -> usize {
/// a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
/// }
///
/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
/// // foo(usize::MAX); // Fails to compile.
/// ```
#[macro_export]
macro_rules! build_error {
Expand All @@ -39,8 +42,8 @@ macro_rules! build_error {
/// These examples show that different types of [`assert!`] will trigger errors
/// at different stage of compilation. It is preferred to err as early as
/// possible, so [`static_assert!`] should be used whenever possible.
/// ```compile_fail
/// # use kernel::prelude::*;
// TODO: Could be `compile_fail` when supported.
/// ```ignore
/// fn foo() {
/// static_assert!(1 > 1); // Compile-time error
/// build_assert!(1 > 1); // Build-time error
Expand All @@ -50,8 +53,7 @@ macro_rules! build_error {
///
/// When the condition refers to generic parameters or parameters of an inline function,
/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
/// ```no_run
/// # use kernel::prelude::*;
/// ```
/// fn foo<const N: usize>() {
/// // `static_assert!(N > 1);` is not allowed
/// build_assert!(N > 1); // Build-time check
Expand Down

0 comments on commit 8a46b49

Please sign in to comment.