KUnit Architecture¶
The KUnit architecture is divided into two parts:
In-Kernel Testing Framework¶
The kernel testing library supports KUnit tests written in C using KUnit. These KUnit tests are kernel code. KUnit performs the following tasks:
Organizes tests
Reports test results
Provides test utilities
Test Cases¶
The test case is the fundamental unit in KUnit. KUnit test cases are organised
into suites. A KUnit test case is a function with type signature
void (*)(struct kunit *test)
. These test case functions are wrapped in a
struct called struct kunit_case
.
Each KUnit test case receives a struct kunit
context object that tracks a
running test. The KUnit assertion macros and other KUnit utilities use the
struct kunit
context object. As an exception, there are two fields:
->priv
: The setup functions can use it to store arbitrary test user data.->param_value
: It contains the parameter value which can be retrieved in the parameterized tests.
Test Suites¶
A KUnit suite includes a collection of test cases. The KUnit suites
are represented by the struct kunit_suite
. For example:
static struct kunit_case example_test_cases[] = {
KUNIT_CASE(example_test_foo),
KUNIT_CASE(example_test_bar),
KUNIT_CASE(example_test_baz),
{}
};
static struct kunit_suite example_test_suite = {
.name = "example",
.init = example_test_init,
.exit = example_test_exit,
.test_cases = example_test_cases,
};
kunit_test_suite(example_test_suite);
In the above example, the test suite example_test_suite
, runs the
test cases example_test_foo
, example_test_bar
, and
example_test_baz
. Before running the test, the example_test_init
is called and after running the test, example_test_exit
is called.
The kunit_test_suite(example_test_suite)
registers the test suite
with the KUnit test framework.
Executor¶
The KUnit executor can list and run built-in KUnit tests on boot.
The Test suites are stored in a linker section
called .kunit_test_suites
. For the code, see KUNIT_TABLE()
macro
definition in
include/asm-generic/vmlinux.lds.h.
The linker section consists of an array of pointers to
struct kunit_suite
, and is populated by the kunit_test_suites()
macro. The KUnit executor iterates over the linker section array in order to
run all the tests that are compiled into the kernel.
On the kernel boot, the KUnit executor uses the start and end addresses
of this section to iterate over and run all tests. For the implementation of the
executor, see
lib/kunit/executor.c.
When built as a module, the kunit_test_suites()
macro defines a
module_init()
function, which runs all the tests in the compilation
unit instead of utilizing the executor.
In KUnit tests, some error classes do not affect other tests
or parts of the kernel, each KUnit case executes in a separate thread
context. See the kunit_try_catch_run()
function in
lib/kunit/try-catch.c.
Assertion Macros¶
KUnit tests verify state using expectations/assertions.
All expectations/assertions are formatted as:
KUNIT_{EXPECT|ASSERT}_<op>[_MSG](kunit, property[, message])
{EXPECT|ASSERT}
determines whether the check is an assertion or an expectation. In the event of a failure, the testing flow differs as follows:For expectations, the test is marked as failed and the failure is logged.
Failing assertions, on the other hand, result in the test case being terminated immediately.
Assertions call the function:
void __noreturn __kunit_abort(struct kunit *)
.__kunit_abort
calls the function:void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
.kunit_try_catch_throw
calls the function:void kthread_complete_and_exit(struct completion *, long) __noreturn;
and terminates the special thread context.
<op>
denotes a check with options:TRUE
(supplied property has the boolean value “true”),EQ
(two supplied properties are equal),NOT_ERR_OR_NULL
(supplied pointer is not null and does not contain an “err” value).[_MSG]
prints a custom message on failure.
Test Result Reporting¶
KUnit prints the test results in KTAP format. KTAP is based on TAP14, see The Kernel Test Anything Protocol (KTAP), version 1. KTAP works with KUnit and Kselftest. The KUnit executor prints KTAP results to dmesg, and debugfs (if configured).
Parameterized Tests¶
Each KUnit parameterized test is associated with a collection of
parameters. The test is invoked multiple times, once for each parameter
value and the parameter is stored in the param_value
field.
The test case includes a KUNIT_CASE_PARAM()
macro that accepts a
generator function. The generator function is passed the previous parameter
and returns the next parameter. It also includes a macro for generating
array-based common-case generators.
kunit_tool (Command-line Test Harness)¶
kunit_tool
is a Python script, found in tools/testing/kunit/kunit.py
. It
is used to configure, build, execute, parse test results and run all of the
previous commands in correct order (i.e., configure, build, execute and parse).
You have two options for running KUnit tests: either build the kernel with KUnit
enabled and manually parse the results (see
Run Tests without kunit_tool) or use kunit_tool
(see Running tests with kunit_tool).
configure
command generates the kernel.config
from a.kunitconfig
file (and any architecture-specific options). The Python scripts available inqemu_configs
folder (for example,tools/testing/kunit/qemu configs/powerpc.py
) contains additional configuration options for specific architectures. It parses both the existing.config
and the.kunitconfig
files to ensure that.config
is a superset of.kunitconfig
. If not, it will combine the two and runmake olddefconfig
to regenerate the.config
file. It then checks to see if.config
has become a superset. This verifies that all the Kconfig dependencies are correctly specified in the file.kunitconfig
. Thekunit_config.py
script contains the code for parsing Kconfigs. The code which runsmake olddefconfig
is part of thekunit_kernel.py
script. You can invoke this command through:./tools/testing/kunit/kunit.py config
and generate a.config
file.build
runsmake
on the kernel tree with required options (depends on the architecture and some options, for example: build_dir) and reports any errors. To build a KUnit kernel from the current.config
, you can use thebuild
argument:./tools/testing/kunit/kunit.py build
.exec
command executes kernel results either directly (using User-mode Linux configuration), or through an emulator such as QEMU. It reads results from the log using standard output (stdout), and passes them toparse
to be parsed. If you already have built a kernel with built-in KUnit tests, you can run the kernel and display the test results with theexec
argument:./tools/testing/kunit/kunit.py exec
.parse
extracts the KTAP output from a kernel log, parses the test results, and prints a summary. For failed tests, any diagnostic output will be included.