blob: d0383964f32e138f4773772477d3b93877e3919d [file] [log] [blame] [edit]
HOW TO RUN KUNIT TESTS IN ANDROID
=================================
Prerequisites
-------------
If you want to run a vendor module KUnit tests, please run the tests with a
"no trim" kernel (e.g. add `--notrim` to bazel build command).
Run tests on a physical or virtual device:
------------------------------------------
```
$ kernel/tests/tools/run_test_only.sh -t kunit -s <serial_number> -td <test_dir>
```
test_dir is the same directory as specified when running:
```
$ tools/bazel run //common:kunit_tests_arm64 -- -v --destdir <test_dir>
```
Before the tests, you can use the following command to launch a virtual device:
```
$ kernel/tests/tools/launch_cvd.sh
```
After the tests, you can use the following command to remove the virtual device:
```
$ prebuilts/asuite/acloud/linux-x86/acloud delete
```
The following are command examples:
* Build kernel and launch a virtual device from a specific platform build:
```
$ kernel/tests/tools/launch_cvd.sh -pb \
ab://aosp-main/aosp_cf_x86_64_phone-trunk_staging-userdebug/12505199
```
* Run a specific test:
```
$ kernel/tests/tools/run_test_only.sh \
-t 'kunit soc-utils-test' -s <serial_number>
```
* Check other available options:
```
$ kernel/tests/tools/launch_cvd.sh -h
$ kernel/tests/tools/run_test_only.sh -h
```
Load and run a test module on Android device manually
-----------------------------------------------------
* Push the KUnit test framework module kunit.ko over to the device. For
example:
```
$ adb push kunit.ko /data
```
* Load test module on device:
```
$ cd /data
$ insmod kunit.ko enable=1
```
If the kunit.ko has been installed already but without enable=1 passed,
it needs to remove it first via the rmmod command, and install again
via the insmod command
* Push the KUnit test module over to the device. For example using adb:
```
$ adb push kunit-example-test.ko /data
```
* (Optional) - Mount debugfs on device:
```
$ mount -t debugfs debugfs /sys/kernel/debug
```
* Load test module on device:
```
$ cd /data
$ insmod kunit-example-test.ko
```
* View test results
* If debugfs is mounted:
```
$ cat /sys/kernel/debug/kunit/<test name>/results
KTAP version 1
1..1
KTAP version 1
# Subtest: example
1..4
# example_simple_test: initializing
ok 1 example_simple_test
....
```
* Via dmesg (check before log cycles out):
```
$ dmesg
....
[172434.032618] 1..1
[172434.032618] KTAP version 1
[172434.032618] # Subtest: example
[172434.032618] 1..4
[172434.032618] # example_simple_test: initializing
[172434.032618]
[172434.032618] ok 1 example_simple_test
....
```
Run KUnit tests on Android Device via test automation infrastructure tradefed
-----------------------------------------------------------------------------
* Build ACK KUnit tests and install (e.g. /tmp/kunit_tests):
```
$ tools/bazel run -- //common:kunit_tests_x86_64 -v --destdir /tmp/kunit_tests
```
Or
```
$ tools/bazel run -- //common:kunit_tests_arm64 -v --destdir /tmp/kunit_tests
```
* With device connected and accessible via adb run the tests:
```
$ prebuilts/tradefed/filegroups/tradefed/tradefed.sh run commandAndExit \
template/local_min --template:map test=suite/test_mapping_suite \
--include-filter kunit --tests-dir=/tmp/kunit_tests \
-s <your_device_serial_number>
....
=======================================================
=============== Summary ===============
Total Run time: 23s
1/1 modules completed
Total Tests : 9
PASSED : 9
FAILED : 0
============== End of Results ==============
============================================
....
```
Troubleshooting
---------------
1. Test module fails to load.
Check dmesg for load errors. If undefined symbol errors are shown, you're
likely running with a trimmed kernel where the symbols are not available.
Run with a "no trim" kernel.
Check the test module dependency with `modinfo <module_name>.ko` on your
local host machine or on the Android device with
`adb shell modinfo <module_name>.ko`.
All dependent modules need to be installed before the test module can be
installed successfully.
Check if the module is already installed with `adb shell lsmod`. The
`adb shell rmmod` can be used to remove the already installed test module,
and installing the test module again will trigger the test rerun.
`adb shell lsmod` will also show the module dependency for your test module
in the `Used by` column. You can not remove a module with `adb shell rmmod`
if it is being used by another module. Other modules that are using it need
to be removed first.
2. Test module loaded but no test results.
Check dmesg for KUnit errors.
```
$ dmesg | grep kunit
```
If "kunit: disabled" is shown then kunit.ko is not installed with
`enable=1`.
If kunit.ko or \<module_name\>.ko fails to install, check for whether they
are already installed with `adb shell lsmod`.
HOW TO WRITE KUNIT TESTS
========================
If you want to
just run the example test and skip through the walkthrough, it is sufficient to
apply [patch1.txt](patch1.txt) and [patch2.txt](patch2.txt) and
then [run the test](#run-tests-on-a-physical-or-virtual-device).
Walkthrough
-----------
This section follows the
[Writing Your First Test](https://docs.kernel.org/dev-tools/kunit/start.html#writing-your-first-test)
example from the KUnit docs.
### Create an example driver to test
1. Create the header file for the driver `common/drivers/misc/example.h`:
```c
int misc_example_add(int left, int right);
```
2. Define and export `misc_example_add` that will be tested later
`common/drivers/misc/example.c`:
```c
#include <linux/module.h>
#include "example.h"
int misc_example_add(int left, int right)
{
return left + right;
}
EXPORT_SYMBOL_GPL(misc_example_add);
```
3. Add a kconfig option for the driver to `common/drivers/misc/Kconfig`:
```
config MISC_EXAMPLE
bool "My example"
```
4. Add the build rule to `common/drivers/misc/Makefile`:
```makefile
obj-$(CONFIG_MISC_EXAMPLE) += example.o
```
### Write the test case
1. Define the test functions and suite `common/drivers/misc/example_test.c`:
```c
#include <kunit/test.h>
#include "example.h"
/* Define the test cases. */
static void misc_example_add_test_basic(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, 1, misc_example_add(1, 0));
KUNIT_EXPECT_EQ(test, 2, misc_example_add(1, 1));
KUNIT_EXPECT_EQ(test, 0, misc_example_add(-1, 1));
KUNIT_EXPECT_EQ(test, INT_MAX, misc_example_add(0, INT_MAX));
KUNIT_EXPECT_EQ(test, -1, misc_example_add(INT_MAX, INT_MIN));
}
static void misc_example_test_failure(struct kunit *test)
{
KUNIT_FAIL(test, "This test never passes.");
}
static struct kunit_case misc_example_test_cases[] = {
KUNIT_CASE(misc_example_add_test_basic),
KUNIT_CASE(misc_example_test_failure),
{}
};
static struct kunit_suite misc_example_test_suite = {
.name = "misc-example",
.test_cases = misc_example_test_cases,
};
kunit_test_suite(misc_example_test_suite);
MODULE_DESCRIPTION("KUnit test for misc_example_add");
MODULE_LICENSE("GPL");
```
Consult the
[KUnit usage guide](https://docs.kernel.org/dev-tools/kunit/usage.html#) and
the
[KUnit API reference](https://docs.kernel.org/dev-tools/kunit/api/index.html)
for more in-depth guidance on the test API.
2. Create a kconfig option for the test `common/drivers/misc/Kconfig`:
```
config MISC_EXAMPLE_TEST
tristate "Test for my example" if !KUNIT_ALL_TESTS
depends on MISC_EXAMPLE && KUNIT
default KUNIT_ALL_TESTS
```
3. Add the build rule to the makefile `common/drivers/misc/Makefile`:
```makefile
obj-$(CONFIG_MISC_EXAMPLE_TEST) += example_test.o
```
4. Add the kconfig options for kunit.py `common/drivers/misc/.kunitconfig`:
```bash
CONFIG_KUNIT=y
CONFIG_MISC_EXAMPLE=y
CONFIG_MISC_EXAMPLE_TEST=y
```
### Run the test against User-mode Linux
1. The test can then be run against User-mode Linux using the kunit.py script:
```
$ cd $REPO/common
$ tools/testing/kunit/kunit.py run --kunitconfig drivers/misc
[01:21:36] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[01:21:38] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make ARCH=um O=.kunit --jobs=96
[01:21:49] Starting KUnit Kernel (1/1)...
[01:21:49] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[01:22:01] ================ misc-example (2 subtests) =================
[01:22:01] [PASSED] misc_example_add_test_basic
[01:22:01] # misc_example_test_failure: EXPECTATION FAILED at drivers/misc/example_test.c:17
[01:22:01] This test never passes.
[01:22:01] [FAILED] misc_example_test_failure
[01:22:01] # module: example_test
[01:22:01] # misc-example: pass:1 fail:1 skip:0 total:2
[01:22:01] # Totals: pass:1 fail:1 skip:0 total:2
[01:22:01] ================== [FAILED] misc-example ===================
[01:22:01] ============================================================
[01:22:01] Testing complete. Ran 2 tests: passed: 1, failed: 1
[01:22:01] Elapsed time: 24.906s total, 2.271s configuring, 10.889s building, 11.694s running
```
2. `kunit.py` will create symlinks under the `.kunit` directory that interfere
with Kleaf/Bazel. This directory is ignored by `.bazelignore`.
### Configure the test for Android
Now that the example test is created, the test needs to be configured for
Android. We will need to add build rules for Kleaf/Bazel and create a Tradefed
test config.
1. Set `CONFIG_MISC_EXAMPLE=y` and `CONFIG_MISC_EXAMPLE_TEST=m` in
[gki_defconfig](https://source.corp.google.com/h/android/kernel/superproject/+/common-android-mainline:common/arch/x86/configs/gki_defconfig).
(This can be done using menuconfig; refer to the
[Kleaf documentation](https://android.googlesource.com/kernel/build/+/refs/heads/main-kernel/kleaf/docs/kernel_config.md)):
```
$ cd $REPO
$ tools/bazel run //common:kernel_x86_64_config -- menuconfig
```
2. Add the test module to `_KUNIT_COMMON_MODULES_LIST` in `common/modules.bzl`:
```bazel
_KUNIT_COMMON_MODULES_LIST = [
....
"drivers/misc/example_test.ko",
....
]
```
3. Add the test under `KUnitModuleTest` in the tradefed configuration
`common/tools/testing/kunit/android/tradefed_configs/config_x86_64.xml`:
```xml
<test class="com.android.tradefed.testtype.binary.KUnitModuleTest" >
....
<option name='binary' key='drivers/misc/example_test' value='/data/kunit/arm64/example_test.ko' />
....
</test>
```