요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
==================
KUnit Architecture
==================
The KUnit architecture is divided into two parts:
- `In-Kernel Testing Framework`_
- `kunit_tool (Command-line Test Harness)`_
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.
.. note:
``generate_params`` is optional for non-parameterized tests.
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:
.. code-block:: c
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 <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v6.0#n950>`_.
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.
.. kernel-figure:: kunit_suitememorydiagram.svg
:alt: KUnit Suite Memory
KUnit Suite Memory Diagram
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 <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/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 <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58>`_.
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
Documentation/dev-tools/ktap.rst.
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
Documentation/dev-tools/kunit/run_manual.rst) or use ``kunit_tool``
(see Documentation/dev-tools/kunit/run_wrapper.rst).
- ``configure`` command generates the kernel ``.config`` from a
``.kunitconfig`` file (and any architecture-specific options).
The Python scripts available in ``qemu_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 run ``make 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``. The ``kunit_config.py`` script contains the code for parsing
Kconfigs. The code which runs ``make olddefconfig`` is part of the
``kunit_kernel.py`` script. You can invoke this command through:
``./tools/testing/kunit/kunit.py config`` and
generate a ``.config`` file.
- ``build`` runs ``make`` 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 the
``build`` 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 to ``parse`` 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 the ``exec``
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.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
KUnit architecture의 두 영역
1-11SPDX 라이선스 식별자: GPL-2.0
KUnit Architecture
KUnit architecture는 다음 두 부분으로 나뉩니다.
In-Kernel Testing Framework
kunit_tool, 즉 command-line test harness
In-kernel framework와 test case
12-43In-Kernel Testing Framework
Kernel testing library는 C로 작성된 KUnit test를 지원합니다. 이 KUnit test는 kernel code이며 KUnit은 테스트 구성, 테스트 결과 보고, test utility 제공을 담당합니다.
Test Case
Test case는 KUnit의 기본 단위이며 suite로 구성됩니다. KUnit test case는 `void (*)(struct kunit *test)` type signature를 가진 함수입니다. 이 함수는 struct kunit_case라는 struct로 감쌉니다.
참고: parameterized test가 아니라면 `generate_params`는 선택 사항입니다.
각 KUnit test case는 실행 중인 테스트를 추적하는 `struct kunit` context object를 받습니다. KUnit assertion macro와 다른 utility도 이 object를 사용합니다. 다음 두 field는 특별한 용도가 있습니다.
`->priv`: setup function이 임의의 test user data를 저장하는 데 사용할 수 있습니다.
`->param_value`: parameterized test에서 가져올 수 있는 parameter 값을 담습니다.
Test suite 등록과 lifecycle
44-73Test Suite
KUnit suite는 test case 모음을 포함하며 `struct kunit_suite`로 표현합니다.
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);
위 예에서 `example_test_suite`는 `example_test_foo`, `example_test_bar`, `example_test_baz`를 실행합니다. 테스트 전에는 `example_test_init`을 호출하고 테스트 후에는 `example_test_exit`을 호출합니다. `kunit_test_suite(example_test_suite)`는 suite를 KUnit test framework에 등록합니다.
Suite 등록부터 각 case 실행 전후의 초기화와 정리 순서를 나타냅니다.
Linker section 기반 executor
74-104Executor
KUnit executor는 부팅할 때 built-in KUnit test를 나열하고 실행할 수 있습니다. Test suite는 `.kunit_test_suites`라는 linker section에 저장됩니다. 관련 코드는 `include/asm-generic/vmlinux.lds.h`의 `KUNIT_TABLE()` macro 정의를 참조하십시오.
Linker section은 `struct kunit_suite` pointer 배열이며 `kunit_test_suites()` macro가 채웁니다. KUnit executor는 이 배열을 순회해 커널에 compile된 모든 테스트를 실행합니다.
원문의 KUnit Suite Memory figure 지시문은 다음과 같습니다.
.. kernel-figure:: kunit_suitememorydiagram.svg
:alt: KUnit Suite Memory
KUnit Suite Memory Diagram
Linker section에 모인 suite pointer를 executor가 경계 주소로 순회하는 구조입니다.
Kernel boot 때 KUnit executor는 이 section의 시작과 끝 주소를 사용해 모든 테스트를 순회하고 실행합니다. 구현은 `lib/kunit/executor.c`를 참조하십시오.
Module로 build하면 `kunit_test_suites()` macro는 executor를 이용하는 대신 해당 compilation unit의 모든 테스트를 실행하는 `module_init()` function을 정의합니다.
일부 오류 class가 다른 테스트나 kernel 영역에 영향을 주지 않도록 각 KUnit case는 별도의 thread context에서 실행됩니다. `lib/kunit/try-catch.c`의 `kunit_try_catch_run()`을 참조하십시오.
Assertion 동작과 KTAP 결과
105-144Assertion Macro
KUnit test는 expectation과 assertion으로 상태를 검증합니다. 모든 expectation과 assertion 형식은 `KUNIT_{EXPECT|ASSERT}_<op>[_MSG](kunit, property[, message])`입니다.
`{EXPECT|ASSERT}`는 검사가 assertion인지 expectation인지 결정합니다. 실패할 때 흐름이 다릅니다.
Expectation이 실패하면 테스트를 실패로 표시하고 failure를 log하지만 테스트 실행은 계속됩니다.
Assertion이 실패하면 test case를 즉시 종료합니다. Assertion은 `void __noreturn __kunit_abort(struct kunit *)`를 호출합니다. `__kunit_abort`는 `void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)`를 호출합니다. 이어서 `kunit_try_catch_throw`는 `void kthread_complete_and_exit(struct completion *, long) __noreturn;`를 호출하여 전용 thread context를 종료합니다.
`<op>`는 검사 연산입니다. `TRUE`는 전달된 property의 boolean 값이 true인지, `EQ`는 두 property가 같은지, `NOT_ERR_OR_NULL`은 pointer가 null이 아니며 err 값을 포함하지 않는지 검사합니다.
`[_MSG]`는 실패 시 custom message를 출력합니다.
같은 property 검사라도 실패 뒤의 실행 제어가 다릅니다.
Test Result Reporting
KUnit은 테스트 결과를 KTAP 형식으로 출력합니다. KTAP는 TAP14를 기반으로 하며 `Documentation/dev-tools/ktap.rst`를 참조하십시오. KTAP는 KUnit과 Kselftest에서 동작합니다. KUnit executor는 KTAP 결과를 dmesg와, 구성되어 있다면 debugfs에 출력합니다.
Parameterized test
145-155Parameterized Test
각 KUnit parameterized test에는 parameter 모음이 연결됩니다. 각 parameter 값마다 테스트를 한 번씩 실행하고 값은 `param_value` field에 저장합니다.
Test case는 generator function을 받는 KUNIT_CASE_PARAM() macro를 포함합니다. Generator는 이전 parameter를 전달받아 다음 parameter를 반환합니다. 배열을 기반으로 하는 일반적인 generator를 만드는 macro도 제공합니다.
kunit_tool command pipeline
156-196kunit_tool, command-line test harness
`kunit_tool`은 `tools/testing/kunit/kunit.py`에 있는 Python script입니다. Kernel 구성, build, 실행, test result parsing을 수행하고 이 명령들을 올바른 순서인 configure, build, execute, parse로 모두 실행할 수 있습니다.
KUnit test 실행 방법은 두 가지입니다. KUnit을 활성화해 커널을 build하고 결과를 직접 parsing하는 방법은 `Documentation/dev-tools/kunit/run_manual.rst`를 참조하고, `kunit_tool`을 사용하는 방법은 `Documentation/dev-tools/kunit/run_wrapper.rst`를 참조하십시오.
`configure`: `.kunitconfig`와 architecture별 option으로 kernel `.config`를 생성합니다. `qemu_configs` 폴더의 Python script, 예를 들어 `tools/testing/kunit/qemu configs/powerpc.py`는 architecture별 추가 option을 담습니다.
기존 `.config`와 `.kunitconfig`를 parsing해 `.config`가 `.kunitconfig`의 superset인지 확인합니다. 아니면 둘을 결합한 뒤 `make olddefconfig`로 `.config`를 다시 만들고 superset이 되었는지 재확인합니다. 이 과정은 `.kunitconfig`에 모든 Kconfig dependency가 올바르게 지정되었는지 검증합니다.
Kconfig parsing 코드는 `kunit_config.py`에 있고 `make olddefconfig` 실행 코드는 `kunit_kernel.py`에 있습니다. `./tools/testing/kunit/kunit.py config`로 이 명령을 호출해 `.config`를 생성합니다.
`build`: architecture와 build_dir 같은 option에 필요한 인수를 적용해 kernel tree에서 `make`를 실행하고 오류를 보고합니다. 현재 `.config`에서 KUnit kernel을 build하려면 `./tools/testing/kunit/kunit.py build`를 사용합니다.
`exec`: User-mode Linux 구성을 사용해 직접 실행하거나 QEMU 같은 emulator를 통해 kernel 결과를 실행합니다. Standard output인 stdout에서 log 결과를 읽어 `parse`로 전달합니다. Built-in KUnit test가 포함된 kernel을 이미 build했다면 `./tools/testing/kunit/kunit.py exec`로 kernel을 실행하고 결과를 표시할 수 있습니다.
`parse`: kernel log에서 KTAP 출력을 추출하고 test result를 parsing해 summary를 출력합니다. 실패한 테스트에는 diagnostic output도 포함됩니다.
하나의 command-line harness가 KUnit 실행 전 과정을 순서대로 연결합니다.
요약과 해설
architecture.rst:1-196KUnit은 struct kunit_case를 suite로 묶어 linker section에 등록하고 boot executor 또는 module_init에서 실행합니다. 각 case는 별도 thread context를 사용하며 expectation은 실패 후 계속하고 assertion은 try-catch 경로로 case를 즉시 종료합니다.
사용자는 결과를 KTAP로 받고 parameter generator로 같은 case를 여러 입력에 적용할 수 있습니다. Python 기반 kunit_tool은 .kunitconfig 검증부터 kernel build, UML·QEMU 실행, KTAP parsing까지 반복 가능한 command pipeline으로 제공합니다.