| .. SPDX-License-Identifier: GPL-2.0 |
| |
| =============== |
| Getting Started |
| =============== |
| |
| This page contains an overview of the kunit_tool and KUnit framework, |
| teaching how to run existing tests and then how to write a simple test case, |
| and covers common problems users face when using KUnit for the first time. |
| |
| Installing Dependencies |
| ======================= |
| KUnit has the same dependencies as the Linux kernel. As long as you can |
| build the kernel, you can run KUnit. |
| |
| Running tests with kunit_tool |
| ============================= |
| kunit_tool is a Python script, which configures and builds a kernel, runs |
| tests, and formats the test results. From the kernel repository, you |
| can run kunit_tool: |
| |
| .. code-block:: bash |
| |
| ./tools/testing/kunit/kunit.py run |
| |
| .. note :: |
| You may see the following error: |
| "The source tree is not clean, please run 'make ARCH=um mrproper'" |
| |
| This happens because internally kunit.py specifies ``.kunit`` |
| (default option) as the build directory in the command ``make O=output/dir`` |
| through the argument ``--build_dir``. Hence, before starting an |
| out-of-tree build, the source tree must be clean. |
| |
| There is also the same caveat mentioned in the "Build directory for |
| the kernel" section of the :doc:`admin-guide </admin-guide/README>`, |
| that is, its use, it must be used for all invocations of ``make``. |
| The good news is that it can indeed be solved by running |
| ``make ARCH=um mrproper``, just be aware that this will delete the |
| current configuration and all generated files. |
| |
| If everything worked correctly, you should see the following: |
| |
| .. code-block:: |
| |
| Configuring KUnit Kernel ... |
| Building KUnit Kernel ... |
| Starting KUnit Kernel ... |
| |
| The tests will pass or fail. |
| |
| .. note :: |
| Because it is building a lot of sources for the first time, |
| the ``Building KUnit Kernel`` step may take a while. |
| |
| For detailed information on this wrapper, see: |
| Documentation/dev-tools/kunit/run_wrapper.rst. |
| |
| Selecting which tests to run |
| ---------------------------- |
| |
| By default, kunit_tool runs all tests reachable with minimal configuration, |
| that is, using default values for most of the kconfig options. However, |
| you can select which tests to run by: |
| |
| - `Customizing Kconfig`_ used to compile the kernel, or |
| - `Filtering tests by name`_ to select specifically which compiled tests to run. |
| |
| Customizing Kconfig |
| ~~~~~~~~~~~~~~~~~~~ |
| A good starting point for the ``.kunitconfig`` is the KUnit default config. |
| If you didn't run ``kunit.py run`` yet, you can generate it by running: |
| |
| .. code-block:: bash |
| |
| cd $PATH_TO_LINUX_REPO |
| tools/testing/kunit/kunit.py config |
| cat .kunit/.kunitconfig |
| |
| .. note :: |
| ``.kunitconfig`` lives in the ``--build_dir`` used by kunit.py, which is |
| ``.kunit`` by default. |
| |
| Before running the tests, kunit_tool ensures that all config options |
| set in ``.kunitconfig`` are set in the kernel ``.config``. It will warn |
| you if you have not included dependencies for the options used. |
| |
| There are many ways to customize the configurations: |
| |
| a. Edit ``.kunit/.kunitconfig``. The file should contain the list of kconfig |
| options required to run the desired tests, including their dependencies. |
| You may want to remove CONFIG_KUNIT_ALL_TESTS from the ``.kunitconfig`` as |
| it will enable a number of additional tests that you may not want. |
| If you need to run on an architecture other than UML see :ref:`kunit-on-qemu`. |
| |
| b. Enable additional kconfig options on top of ``.kunit/.kunitconfig``. |
| For example, to include the kernel's linked-list test you can run:: |
| |
| ./tools/testing/kunit/kunit.py run \ |
| --kconfig_add CONFIG_LIST_KUNIT_TEST=y |
| |
| c. Provide the path of one or more .kunitconfig files from the tree. |
| For example, to run only ``FAT_FS`` and ``EXT4`` tests you can run:: |
| |
| ./tools/testing/kunit/kunit.py run \ |
| --kunitconfig ./fs/fat/.kunitconfig \ |
| --kunitconfig ./fs/ext4/.kunitconfig |
| |
| d. If you change the ``.kunitconfig``, kunit.py will trigger a rebuild of the |
| ``.config`` file. But you can edit the ``.config`` file directly or with |
| tools like ``make menuconfig O=.kunit``. As long as its a superset of |
| ``.kunitconfig``, kunit.py won't overwrite your changes. |
| |
| |
| .. note :: |
| |
| To save a .kunitconfig after finding a satisfactory configuration:: |
| |
| make savedefconfig O=.kunit |
| cp .kunit/defconfig .kunit/.kunitconfig |
| |
| Filtering tests by name |
| ~~~~~~~~~~~~~~~~~~~~~~~ |
| If you want to be more specific than Kconfig can provide, it is also possible |
| to select which tests to execute at boot-time by passing a glob filter |
| (read instructions regarding the pattern in the manpage :manpage:`glob(7)`). |
| If there is a ``"."`` (period) in the filter, it will be interpreted as a |
| separator between the name of the test suite and the test case, |
| otherwise, it will be interpreted as the name of the test suite. |
| For example, let's assume we are using the default config: |
| |
| a. inform the name of a test suite, like ``"kunit_executor_test"``, |
| to run every test case it contains:: |
| |
| ./tools/testing/kunit/kunit.py run "kunit_executor_test" |
| |
| b. inform the name of a test case prefixed by its test suite, |
| like ``"example.example_simple_test"``, to run specifically that test case:: |
| |
| ./tools/testing/kunit/kunit.py run "example.example_simple_test" |
| |
| c. use wildcard characters (``*?[``) to run any test case that matches the pattern, |
| like ``"*.*64*"`` to run test cases containing ``"64"`` in the name inside |
| any test suite:: |
| |
| ./tools/testing/kunit/kunit.py run "*.*64*" |
| |
| Running Tests without the KUnit Wrapper |
| ======================================= |
| If you do not want to use the KUnit Wrapper (for example: you want code |
| under test to integrate with other systems, or use a different/ |
| unsupported architecture or configuration), KUnit can be included in |
| any kernel, and the results are read out and parsed manually. |
| |
| .. note :: |
| ``CONFIG_KUNIT`` should not be enabled in a production environment. |
| Enabling KUnit disables Kernel Address-Space Layout Randomization |
| (KASLR), and tests may affect the state of the kernel in ways not |
| suitable for production. |
| |
| Configuring the Kernel |
| ---------------------- |
| To enable KUnit itself, you need to enable the ``CONFIG_KUNIT`` Kconfig |
| option (under Kernel Hacking/Kernel Testing and Coverage in |
| ``menuconfig``). From there, you can enable any KUnit tests. They |
| usually have config options ending in ``_KUNIT_TEST``. |
| |
| KUnit and KUnit tests can be compiled as modules. The tests in a module |
| will run when the module is loaded. |
| |
| Running Tests (without KUnit Wrapper) |
| ------------------------------------- |
| Build and run your kernel. In the kernel log, the test output is printed |
| out in the TAP format. This will only happen by default if KUnit/tests |
| are built-in. Otherwise the module will need to be loaded. |
| |
| .. note :: |
| Some lines and/or data may get interspersed in the TAP output. |
| |
| Writing Your First Test |
| ======================= |
| In your kernel repository, let's add some code that we can test. |
| |
| 1. Create a file ``drivers/misc/example.h``, which includes: |
| |
| .. code-block:: c |
| |
| int misc_example_add(int left, int right); |
| |
| 2. Create a file ``drivers/misc/example.c``, which includes: |
| |
| .. code-block:: c |
| |
| #include <linux/errno.h> |
| |
| #include "example.h" |
| |
| int misc_example_add(int left, int right) |
| { |
| return left + right; |
| } |
| |
| 3. Add the following lines to ``drivers/misc/Kconfig``: |
| |
| .. code-block:: kconfig |
| |
| config MISC_EXAMPLE |
| bool "My example" |
| |
| 4. Add the following lines to ``drivers/misc/Makefile``: |
| |
| .. code-block:: make |
| |
| obj-$(CONFIG_MISC_EXAMPLE) += example.o |
| |
| Now we are ready to write the test cases. |
| |
| 1. Add the below test case in ``drivers/misc/example_test.c``: |
| |
| .. code-block:: 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_LICENSE("GPL"); |
| |
| 2. Add the following lines to ``drivers/misc/Kconfig``: |
| |
| .. code-block:: kconfig |
| |
| config MISC_EXAMPLE_TEST |
| tristate "Test for my example" if !KUNIT_ALL_TESTS |
| depends on MISC_EXAMPLE && KUNIT |
| default KUNIT_ALL_TESTS |
| |
| Note: If your test does not support being built as a loadable module (which is |
| discouraged), replace tristate by bool, and depend on KUNIT=y instead of KUNIT. |
| |
| 3. Add the following lines to ``drivers/misc/Makefile``: |
| |
| .. code-block:: make |
| |
| obj-$(CONFIG_MISC_EXAMPLE_TEST) += example_test.o |
| |
| 4. Add the following lines to ``.kunit/.kunitconfig``: |
| |
| .. code-block:: none |
| |
| CONFIG_MISC_EXAMPLE=y |
| CONFIG_MISC_EXAMPLE_TEST=y |
| |
| 5. Run the test: |
| |
| .. code-block:: bash |
| |
| ./tools/testing/kunit/kunit.py run |
| |
| You should see the following failure: |
| |
| .. code-block:: none |
| |
| ... |
| [16:08:57] [PASSED] misc-example:misc_example_add_test_basic |
| [16:08:57] [FAILED] misc-example:misc_example_test_failure |
| [16:08:57] EXPECTATION FAILED at drivers/misc/example-test.c:17 |
| [16:08:57] This test never passes. |
| ... |
| |
| Congrats! You just wrote your first KUnit test. |
| |
| Next Steps |
| ========== |
| |
| If you're interested in using some of the more advanced features of kunit.py, |
| take a look at Documentation/dev-tools/kunit/run_wrapper.rst |
| |
| If you'd like to run tests without using kunit.py, check out |
| Documentation/dev-tools/kunit/run_manual.rst |
| |
| For more information on writing KUnit tests (including some common techniques |
| for testing different things), see Documentation/dev-tools/kunit/usage.rst |