Skip to content

第二百零五章:测试之道

飞升期

涉及内核源码:

林小源从审查海域继续前行,来到一座巨大的试炼场。试炼场的地面由无数方格组成,每个方格上都运行着一段测试代码。有的方格闪烁着绿光——测试通过;有的方格闪烁着红光——测试失败。

试炼场的中央站着一位身披铁甲的守护者,他的铠甲上刻满了测试用例的编号。他的手中握着一把锤子,不断地敲打着那些红色方格,每敲一下,方格中的代码就发出一声哀鸣。

"你提交的补丁,"守护者头也不回地说,"没有测试。"

林小源一愣:"我的补丁能编译通过……"

"编译通过不代表正确,"守护者转身,锤子指向林小源,"你的补丁修复了一个内存泄漏,但你没有写测试。三个月后有人重构那段代码,不小心把你的修复弄丢了,谁来发现?没有测试的代码,就是在沙子上建房子。"

守护者将锤子插入地面,整个试炼场震动起来。地面上浮现出四个巨大的法阵,每个法阵中都运行着不同的测试系统。

"内核有四大测试体系,"守护者指着法阵,"kselftest 在用户空间测试内核功能,kunit 在内核内部做单元测试,syzkaller 用随机输入做模糊测试,0-day 机器人自动编译和回归测试。你的补丁至少要通过其中一个,才有资格被合并。"

c
/*
 * 内核测试:
 *
 * 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");

守护者带林小源走向试炼场的角落,那里有一个被黑色迷雾笼罩的区域。迷雾中传来各种奇怪的声音——系统调用的编号在空中随机组合,形成各种荒诞的指令序列。

"这是 syzkaller 的领地,"守护者的语气中带着一丝敬畏,"模糊测试。它不关心你的代码在正常情况下能不能工作,它只关心在疯狂的输入下,你的代码会不会崩溃。"

迷雾中突然爆出一声巨响,一个内核路径在随机输入下触发了空指针解引用,系统直接崩溃。

"看到了吗?"守护者指着崩溃的现场,"syzkaller 发现了数千个这样的 bug。正常测试永远找不到它们,因为没有人类会输入这么疯狂的参数组合。但现实中,恶意攻击者会。"

林小源看着那团迷雾,心中升起一股寒意。模糊测试不是为了验证代码正确,而是为了暴露代码在极端情况下的脆弱。

守护者从铠甲上取下一枚特殊的徽章,徽章上刻着一个机器人的眼睛。

"0-day 机器人,"守护者将徽章递给林小源,"它是内核的自动守卫。你提交补丁的几分钟内,它就会自动编译你的代码,运行回归测试,检查是否有已知的 bug 被重新引入。"

林小源接过徽章,感受到其中蕴含的自动化力量。

"人类审查者可能需要几天才能看到你的补丁,"守护者继续说,"但 0-day 机器人从不睡觉。它在全球的服务器上运行,监控每一个进入邮件列表的补丁。如果它发现了问题,会在几分钟内报告到邮件列表。"

守护者望向远方,那里有一排排闪烁的服务器,每台服务器都在不知疲倦地运行着测试。"自动化是效率的来源。人类负责创造和判断,机器负责重复和验证。内核的质量,靠的是两者的配合。"


道藏笔记

内核启示

测试是内核质量的保障。

测试框架:

  • kselftest — 用户空间测试
  • kunit — 内核单元测试
  • syzkaller — 模糊测试
  • 0-day — 自动化测试

测试类型:

  • 单元测试 — 测试单个函数
  • 集成测试 — 测试多个组件
  • 回归测试 — 测试 bug 修复
  • 性能测试 — 测试性能

模糊测试:

  • 自动生成随机输入
  • 发现崩溃和 bug
  • syzkaller 发现数千个 bug

测试是保障——让代码经得起考验。


破关试炼

测试之试

测试之道中,面向内核自测试、提交前应运行的重要测试框架是什么?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道