310 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			310 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. 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
 |