第二百零五章:测试之道
飞升期涉及内核源码:
一
林小源从审查海域继续前行,来到一座巨大的试炼场。试炼场的地面由无数方格组成,每个方格上都运行着一段测试代码。有的方格闪烁着绿光——测试通过;有的方格闪烁着红光——测试失败。
试炼场的中央站着一位身披铁甲的守护者,他的铠甲上刻满了测试用例的编号。他的手中握着一把锤子,不断地敲打着那些红色方格,每敲一下,方格中的代码就发出一声哀鸣。
"你提交的补丁,"守护者头也不回地说,"没有测试。"
林小源一愣:"我的补丁能编译通过……"
"编译通过不代表正确,"守护者转身,锤子指向林小源,"你的补丁修复了一个内存泄漏,但你没有写测试。三个月后有人重构那段代码,不小心把你的修复弄丢了,谁来发现?没有测试的代码,就是在沙子上建房子。"
守护者将锤子插入地面,整个试炼场震动起来。地面上浮现出四个巨大的法阵,每个法阵中都运行着不同的测试系统。
"内核有四大测试体系,"守护者指着法阵,"kselftest 在用户空间测试内核功能,kunit 在内核内部做单元测试,syzkaller 用随机输入做模糊测试,0-day 机器人自动编译和回归测试。你的补丁至少要通过其中一个,才有资格被合并。"
/*
* 内核测试:
*
* 1. kselftest
* 内核自测试
* 用户空间测试程序
* 测试内核功能
*
* 2. kunit
* 内核单元测试
* 在内核中运行
* 快速、轻量
*
* 3. syzkaller
* 模糊测试
* 自动生成系统调用
* 发现崩溃和 bug
*
* 4. 0-day 机器人
* 自动编译测试
* 自动回归测试
* 自动报告问题
*
* 测试类型:
* 单元测试 — 测试单个函数
* 集成测试 — 测试多个组件
* 回归测试 — 测试 bug 是否修复
* 性能测试 — 测试性能
*
* 测试工具:
* kselftest — 用户空间测试
* kunit — 内核单元测试
* syzkaller — 模糊测试
* perf — 性能测试
*/
/* 模拟测试用例 */
struct test_case {
char name[64];
char description[128];
int (*run)(void);
int passed;
};
int test_add(void) {
/* 测试加法函数 */
return 1; /* 通过 */
}
int test_sub(void) {
/* 测试减法函数 */
return 1; /* 通过 */
}
int test_div(void) {
/* 测试除法函数 */
return 0; /* 失败: 除以零 */
}
void run_test(struct test_case *test) {
test->passed = test->run();
printf(" [%s] %s: %s\n",
test->passed ? "PASS" : "FAIL",
test->name, test->description);
}
printf("=== 测试之道 — 内核的质量保障 ===\n\n");
printf("测试是内核质量的保障:\n\n");
/* 测试用例 */
struct test_case tests[] = {
{"test_add", "测试加法函数", test_add, 0},
{"test_sub", "测试减法函数", test_sub, 0},
{"test_div", "测试除法函数", test_div, 0},
};
int n = sizeof(tests) / sizeof(tests[0]);
printf("--- 运行测试 ---\n");
for (int i = 0; i < n; i++) {
run_test(&tests[i]);
}
printf("\n--- 测试框架 ---\n");
printf("kselftest:\n");
printf(" 内核自测试\n");
printf(" 用户空间测试程序\n");
printf(" tools/testing/selftests/\n\n");
printf("kunit:\n");
printf(" 内核单元测试\n");
printf(" 在内核中运行\n");
printf(" 快速、轻量\n\n");
printf("syzkaller:\n");
printf(" 模糊测试\n");
printf(" 自动生成系统调用\n");
printf(" 发现崩溃和 bug\n\n");
printf("0-day 机器人:\n");
printf(" 自动编译测试\n");
printf(" 自动回归测试\n");
printf(" 自动报告问题\n\n");
printf("--- 测试类型 ---\n");
printf("单元测试:\n");
printf(" 测试单个函数\n\n");
printf("集成测试:\n");
printf(" 测试多个组件\n\n");
printf("回归测试:\n");
printf(" 测试 bug 是否修复\n\n");
printf("性能测试:\n");
printf(" 测试性能\n\n");
printf("--- 运行测试 ---\n");
printf("kselftest:\n");
printf(" make kselftest\n\n");
printf("kunit:\n");
printf(" ./tools/testing/kunit/kunit.py run\n\n");
printf("syzkaller:\n");
printf(" 配置 syzkaller\n");
printf(" 运行模糊测试\n");#include <stdio.h>
#include <string.h>
/*
* 内核测试:
*
* 1. kselftest
* 内核自测试
* 用户空间测试程序
* 测试内核功能
*
* 2. kunit
* 内核单元测试
* 在内核中运行
* 快速、轻量
*
* 3. syzkaller
* 模糊测试
* 自动生成系统调用
* 发现崩溃和 bug
*
* 4. 0-day 机器人
* 自动编译测试
* 自动回归测试
* 自动报告问题
*
* 测试类型:
* 单元测试 — 测试单个函数
* 集成测试 — 测试多个组件
* 回归测试 — 测试 bug 是否修复
* 性能测试 — 测试性能
*
* 测试工具:
* kselftest — 用户空间测试
* kunit — 内核单元测试
* syzkaller — 模糊测试
* perf — 性能测试
*/
/* 模拟测试用例 */
struct test_case {
char name[64];
char description[128];
int (*run)(void);
int passed;
};
int test_add(void) {
/* 测试加法函数 */
return 1; /* 通过 */
}
int test_sub(void) {
/* 测试减法函数 */
return 1; /* 通过 */
}
int test_div(void) {
/* 测试除法函数 */
return 0; /* 失败: 除以零 */
}
void run_test(struct test_case *test) {
test->passed = test->run();
printf(" [%s] %s: %s\n",
test->passed ? "PASS" : "FAIL",
test->name, test->description);
}
int main() {
printf("=== 测试之道 — 内核的质量保障 ===\n\n");
printf("测试是内核质量的保障:\n\n");
/* 测试用例 */
struct test_case tests[] = {
{"test_add", "测试加法函数", test_add, 0},
{"test_sub", "测试减法函数", test_sub, 0},
{"test_div", "测试除法函数", test_div, 0},
};
int n = sizeof(tests) / sizeof(tests[0]);
printf("--- 运行测试 ---\n");
for (int i = 0; i < n; i++) {
run_test(&tests[i]);
}
printf("\n--- 测试框架 ---\n");
printf("kselftest:\n");
printf(" 内核自测试\n");
printf(" 用户空间测试程序\n");
printf(" tools/testing/selftests/\n\n");
printf("kunit:\n");
printf(" 内核单元测试\n");
printf(" 在内核中运行\n");
printf(" 快速、轻量\n\n");
printf("syzkaller:\n");
printf(" 模糊测试\n");
printf(" 自动生成系统调用\n");
printf(" 发现崩溃和 bug\n\n");
printf("0-day 机器人:\n");
printf(" 自动编译测试\n");
printf(" 自动回归测试\n");
printf(" 自动报告问题\n\n");
printf("--- 测试类型 ---\n");
printf("单元测试:\n");
printf(" 测试单个函数\n\n");
printf("集成测试:\n");
printf(" 测试多个组件\n\n");
printf("回归测试:\n");
printf(" 测试 bug 是否修复\n\n");
printf("性能测试:\n");
printf(" 测试性能\n\n");
printf("--- 运行测试 ---\n");
printf("kselftest:\n");
printf(" make kselftest\n\n");
printf("kunit:\n");
printf(" ./tools/testing/kunit/kunit.py run\n\n");
printf("syzkaller:\n");
printf(" 配置 syzkaller\n");
printf(" 运行模糊测试\n");
return 0;
}二
守护者带林小源走向试炼场的角落,那里有一个被黑色迷雾笼罩的区域。迷雾中传来各种奇怪的声音——系统调用的编号在空中随机组合,形成各种荒诞的指令序列。
"这是 syzkaller 的领地,"守护者的语气中带着一丝敬畏,"模糊测试。它不关心你的代码在正常情况下能不能工作,它只关心在疯狂的输入下,你的代码会不会崩溃。"
迷雾中突然爆出一声巨响,一个内核路径在随机输入下触发了空指针解引用,系统直接崩溃。
"看到了吗?"守护者指着崩溃的现场,"syzkaller 发现了数千个这样的 bug。正常测试永远找不到它们,因为没有人类会输入这么疯狂的参数组合。但现实中,恶意攻击者会。"
林小源看着那团迷雾,心中升起一股寒意。模糊测试不是为了验证代码正确,而是为了暴露代码在极端情况下的脆弱。
三
守护者从铠甲上取下一枚特殊的徽章,徽章上刻着一个机器人的眼睛。
"0-day 机器人,"守护者将徽章递给林小源,"它是内核的自动守卫。你提交补丁的几分钟内,它就会自动编译你的代码,运行回归测试,检查是否有已知的 bug 被重新引入。"
林小源接过徽章,感受到其中蕴含的自动化力量。
"人类审查者可能需要几天才能看到你的补丁,"守护者继续说,"但 0-day 机器人从不睡觉。它在全球的服务器上运行,监控每一个进入邮件列表的补丁。如果它发现了问题,会在几分钟内报告到邮件列表。"
守护者望向远方,那里有一排排闪烁的服务器,每台服务器都在不知疲倦地运行着测试。"自动化是效率的来源。人类负责创造和判断,机器负责重复和验证。内核的质量,靠的是两者的配合。"
道藏笔记
内核启示
测试是内核质量的保障。
测试框架:
- kselftest — 用户空间测试
- kunit — 内核单元测试
- syzkaller — 模糊测试
- 0-day — 自动化测试
测试类型:
- 单元测试 — 测试单个函数
- 集成测试 — 测试多个组件
- 回归测试 — 测试 bug 修复
- 性能测试 — 测试性能
模糊测试:
- 自动生成随机输入
- 发现崩溃和 bug
- syzkaller 发现数千个 bug
测试是保障——让代码经得起考验。
测试之试
测试之道中,面向内核自测试、提交前应运行的重要测试框架是什么?