ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux 内核 KUnit 单元测试框架常见问题与故障排查实战指南(FAQ 精读)

Linux 内核 KUnit 单元测试框架常见问题与故障排查实战指南(FAQ 精读) Linux 内核 KUnit 单元测试框架常见问题与故障排查实战指南FAQ 精读【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文以内核文档Documentation/dev-tools/kunit/faq.rst为核心系统讲解 KUnit 与 Autotest/kselftest 等测试体系的本质区别、单元测试与集成/端到端测试的边界、跨架构UML、QEMU、裸机运行方式以及一套完整的“KUnit 跑不起来”七步排查法并结合tools/testing/kunit/kunit.py的源码实现与lib/kunit/Kconfig配置项帮助开发者建立对 KUnit 的准确定位并具备独立定位问题的能力。一、KUnit 与 Autotest、kselftest 的区别为什么只有 KUnit 是“单元测试框架”FAQ 开宗明义KUnit 是一个单元测试框架unit testing framework而 Autotest、kselftest 等不是。这一定位差异不是命名游戏而是由“单元测试”的定义决定的。单元测试的核心要求FAQ 原文的界定测试单一代码单元a single unit of code并使其与其他组件隔离运行单元测试应是最细粒度的测试允许对“被测代码”中所有可能的代码路径逐一验证这只有在被测代码足够小、且不存在测试控制之外的外部依赖例如硬件时才可能实现。而 FAQ 指出的关键事实是当时文档语境下内核中尚不存在“不需要把被测内核安装到测试机或虚拟机上”就能工作的测试框架。Autotest、kselftest 等框架都要求测试代码写在用户态userspace并运行在被测内核之上——它们测试的是“运行着内核的用户态程序的行为”而非内核代码单元本身因此被“取消资格”disqualifying为单元测试框架。可以对照仓库中的两类测试来理解这种边界用户态测试如 kselftest 风格位于tools/testing/selftests/下通过系统调用、ioctl 等内核对外接口来验证行为天然依赖完整的内核运行环境KUnit 测试编译进内核built-in 或模块与被测代码处于同一上下文。仓库中 KUnit 框架自身位于 lib/kunit/示例测试 lib/kunit/kunit-example-test.c 可直接在内核态访问内部数据结构这正是“隔离测试单一单元”得以实现的前提。从源码结构看KUnit 框架由 lib/kunit/executor.c执行器、lib/kunit/test.c测试注册与调度、lib/kunit/assert.c断言、lib/kunit/resource.c测试资源生命周期管理等模块构成是一个轻量级的“测试注册—执行—断言—结果输出”框架而非用户态测试套件。二、KUnit 是否只能在 UML 上运行——跨架构运行能力FAQ 对此的回答是明确的KUnit 可以在任何架构上运行受限的只是kunit.py工具能直接驱动构建与运行的架构范围其中 UML 是默认。具体有两条路径路径 1完全脱离 kunit.py任意架构手工运行只要启用CONFIG_KUNITy并启动内核测试即可运行。FAQ 指引读者参阅 run_manual.rst。该文档说明了两种形态built-in 测试内核启动时自动执行结果以 TAP 格式写入内核日志dmesg模块测试加载模块时执行例如modprobe example-test结果同样出现在dmesg中。如果启用CONFIG_KUNIT_DEBUGFS还可以通过 debugfs 访问/sys/kernel/debug/kunit/test_suite/results读取 TAP 结果甚至向/sys/kernel/debug/kunit/test_suite/run写入内容在启动后手动触发内置测试注意使用 init data 的套件以及并发运行均不支持此特性详见 run_manual.rst。路径 2使用 kunit.py QEMU 跨架构运行kunit.py借助交叉编译器 QEMU 模拟器支持许多常见架构涉及两个关键参数FAQ 原文--arch在运行测试时指定目标架构--cross_compile在构建时指定交叉工具链前缀当宿主编译器不支持该架构时。例如在 x86_64 宿主上直接跑 x86_64 QEMU 内核只需./tools/testing/kunit/kunit.py run --archx86_64交叉编译示例以 s390 为例./tools/testing/kunit/kunit.py run \ --archs390 \ --cross_compiles390x-linux-gnu-这一点在 kunit.py 源码中可以得到印证add_common_opts()里--arch的默认值就是um其帮助文本明确写道“非 UML 架构会在 QEMU 上运行”Non-UML architectures run on QEMU--cross_compile则说明它设置的是 make 的CROSS_COMPILE变量应填工具链路径前缀如sparc64-linux-gnu-。若目标架构不在内置列表中还可以用--qemu_config传入自定义的QemuArchParamsPython 文件示例见 qemu_configs/x86_64.py。FAQ 同时提醒编写面向其他架构的测试时要牢记 running_tips.rst 中关于非 UML 架构的注意事项对应文档中的kunit-on-non-uml锚点。三、单元测试与集成测试、端到端测试的本质区别FAQ 将“现有的绝大多数内核测试”归入集成测试或端到端测试类别并给出三者精确定义完整继承 FAQ 原文测试类型定义典型内核场景单元测试unit test在隔离条件下测试单一代码单元是最细粒度可覆盖被测代码所有路径要求被测代码小且无测试控制外的外部依赖如硬件用一个 KUnit 套件测试lib/中的字符串/位操作函数不依赖真实硬件集成测试integration test测试最小集合组件之间通常两三个的交互测试某个驱动与某块硬件的交互或测试内核提供的用户态库与内核本身的交互。但一般不会把整个内核连同硬件、用户态交互全部纳入端到端测试end-to-end test从被测代码的视角测试整个系统在生产硬件上安装生产级内核配置、配上生产用户态然后演练某种依赖硬件—内核—用户态三方交互的行为理解这个分类的价值在于它回答了“为什么我写的内核测试不是单元测试”——不是写法问题而是被测对象粒度和外部依赖问题。若你的测试需要真实网卡、真实磁盘或完整的用户态进程它就天然属于集成/端到端测试KUnit 的目标是用更细粒度的单元测试去覆盖其中的纯逻辑单元。四、KUnit 不工作时的七步排查法FAQ 核心排障清单FAQ 坦承 KUnit 有很多东西可能出错并给出一套由浅入深的排查清单。以下逐条继承并补充源码/配置层面的依据。1. 用--raw_output查看被解析器吞掉的原始输出./tools/testing/kunit/kunit.py run --raw_outputkunit.py会对内核输出做 TAP 解析解析器可能隐藏细节或错误信息。从 kunit.py 源码可见--raw_output支持三种取值--raw_output或--raw_outputkunit默认行为只过滤出 KUnit 的 TAP 行--raw_outputall/--raw_outputfull显示完整内核输出包括 TAP 行之外的所有日志。2. 分步执行config/build/exec定位故障阶段./tools/testing/kunit/kunit.py config # 仅生成/校验 .config ./tools/testing/kunit/kunit.py build # 仅构建内核 ./tools/testing/kunit/kunit.py exec # 仅运行已构建的内核并解析run等价于按顺序执行上述三步源码中run_tests()依次调用config_tests()、build_tests()、exec_tests()任一步失败立即返回对应状态码。若怀疑是解析器的问题还可以用kunit.py parse手动解析stdin或文件dmesg | ./tools/testing/kunit/kunit.py parse3. 直接运行 UML 的vmlinux二进制构建 UML 内核后例如通过kunit.py build直接执行输出目录下的vmlinux默认为./.kunit/vmlinux。kunit_tool忽略的错误信息往往在此暴露。FAQ 特别警告了两个 UML 的特殊性UML 对宿主有一些特殊要求例如宿主需要挂载 tmpfs 文件系统历史上在静态构建 宿主开启 KASLR时出现过问题。老内核宿主上可执行setarch $(uname -m) -R ./vmlinux关闭 KASLR 后重试。4. 换用其他架构运行./tools/testing/kunit/kunit.py run --archx86_64在 x86_64 宿主上--archx86_64QEMU 路径是排查 UML 特有问题的好起点。5. 检查.config中CONFIG_KUNITy与至少一个测试项确保内核配置包含CONFIG_KUNITy以及至少一个具体测试如CONFIG_KUNIT_EXAMPLE_TESTy。kunit_tool会保留其生成的.config运行kunit.py run之后可以回看实际使用的配置它也会保留你对配置的改动——可以用make ARCHum menuconfig构建目录默认为.kunit调整后再重跑。对照仓库中的配置证据KUnit 框架的测试配置片段 lib/kunit/.kunitconfig 内容即CONFIG_KUNITy、CONFIG_KUNIT_TESTy、CONFIG_KUNIT_EXAMPLE_TESTy三项默认配置 tools/testing/kunit/configs/default.config 在框架配置之上还启用了CONFIG_KUNIT_ALL_TESTSy和CONFIG_SPIy。相关 Kconfig 定义见 lib/kunit/KconfigCONFIG_KUNIT_ALL_TESTS会启用所有依赖满足的 KUnit 测试CONFIG_KUNIT_DEFAULT_ENABLED控制内核参数kunit.enable的默认值默认为 Y即默认执行测试CONFIG_KUNIT_DEFAULT_TIMEOUT默认为 300 秒并随测试速度等级DEFAULT/KUNIT_SPEED_SLOW/KUNIT_SPEED_VERY_SLOW分别 1x/3x/12x放大。6. 运行make ARCHum defconfig清理残留配置在运行kunit.py run之前执行make ARCHum defconfig可能清理掉导致问题的残留配置项。7. 完全手工运行 KUnit不经过 kunit.pyKUnit 可以编译进任何内核也可以构建成模块在运行时加载built-in 测试在内核启动时执行模块在加载时自动执行关联测试测试结果可从/sys/kernel/debug/kunit/test suite/results收集并用kunit.py parse解析。更多细节见 run_manual.rst。若以上手段均无效FAQ 建议将问题反馈给 KUnit 开发邮件列表kunit-devgooglegroups.com。五、排障时值得记住的参数速查基于 kunit.py 源码结合 kunit.py 的参数定义以下默认值与行为在排查配置类问题时非常有用参数默认值/行为排障意义--build_dir.kunit若设置了KBUILD_OUTPUT环境变量则为$KBUILD_OUTPUT/.kunit.kunitconfig、.config与编译产物都位于此目录是排查第 5 步的现场--archum确认自己到底跑在 UML 还是 QEMU 上--timeout300秒不含构建时间超时导致的失败会表现为测试被终止可先调大排除--jobs宿主 CPU 核数构建阶段排障时可手动指定--kunitconfig无指定自定义配置片段传目录时自动补/.kunitconfig后缀可重复指定多片段直接拼接可能冲突--kconfig_add无追加单个 Kconfig 项如CONFIG_KASANy可重复filter_glob位置参数空用 bash glob 过滤要运行的套件/测试如kunit-resource*--run_isolated关按suite/test粒度逐个启动内核用于排查“受前序测试影响”的非隔离测试--list_tests/--list_suites关先列出将被执行的测试/套件确认过滤是否正确生效完整的命令行参数说明可参考 run_wrapper.rst其中还包括--json/--junit结果输出、--filter属性过滤以及 bash 补全脚本 kunit-completion.sh 的用法。六、小结KUnit 的价值在于“内核态、隔离、最细粒度”的单元测试与用户态测试框架Autotest/kselftest在测试对象与依赖模型上存在本质差异KUnit 与架构无关受架构限制的只是kunit.py的自动驱动能力CONFIG_KUNITy即可让任意内核在启动或模块加载时执行测试单元测试与集成/端到端测试的边界在于“被测单元的大小与外部依赖”这是判断一个测试属于哪一类的标准遇到 KUnit 跑不起来时按“--raw_output→ 分步执行 → 直接跑vmlinux→ 换--arch→ 查.config→defconfig清理 → 手工运行”七步法逐级收敛配合.kunit构建目录中保留的.config与 lib/kunit/Kconfig 中的配置语义基本可以定位绝大多数问题。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表