跳到主要内容

Std 白名单测试

cargo xtask test 是 axbuild 在 host 端执行的 Rust std 测试入口。它不是 cargo test --workspace:TGOSKits workspace 中混合了大量 #![no_std] 内核 crate,它们无法在标准 cargo test 环境下运行;盲目全量测试会因平台/特性不兼容大面积失败。本命令只测试一份显式维护的白名单,普通 package 执行 cargo test -p <package>,需要 host adapter 的 package 执行仓库定义的固定 feature profile。这样纯算法库以及可通过正式 host 边界测试的内核组件都能保持回归覆盖。

测试设计与 Rust 布局统一遵循仓库 test-quality:源码末尾的单元测试验证算法和业务逻辑,{crate}/tests/ 只通过公开 API 验证完整能力,不通过 #[path] 或其他源码包含方式引入生产实现。白名单决定执行哪些软件包,不要求为新增软件包复制固定实例测试。

1. 白名单边界

TGOSKits workspace 目前包含近 150 个 crate,其中绝大多数是面向裸机/内核环境的 #![no_std] crate,依赖 axcpu、特定 target triple 和明确的内核 feature 组合才能编译。直接对全 workspace 跑 cargo test 会触发两类系统性失败:

  1. no_std crate 无法在 std 环境编译:这些 crate 的 #[cfg(test)] 模块通常不存在,或依赖内核特性。
  2. target/feature 不匹配:许多 crate 需要 --target aarch64-unknown-none-softfloat 和特定 feature 组合才能编译,host 端 cargo test 无法满足。

白名单机制把 host 可测的 crate(算法库、工具库、序列化库等)显式列出,CI 对这一固定集合做全量回归,既保证覆盖又避免噪声。

2. 执行架构

标准测试将白名单解析和逐包执行分开,以便在 host 环境稳定验证明确支持的 crate。下图对应 run_std_test_command() 的主要数据流。

3. 白名单数据

白名单位于 scripts/test/std_crates.csv,格式极简——每行一个包名,首行为表头 package

package
aarch64_sysreg
ax-io
ax-sync
irq-framework
memory_addr
rsext4
scope-local
...

当前白名单覆盖架构寄存器、I/O 抽象、锁原语、内存地址、文件系统、调度器、中断框架以及 Starry kernel 等可在 host 端测试的组件。

3.1 解析校验

parse_std_crates_csv 对 CSV 内容执行严格校验,确保白名单与 workspace 实际状态一致:

校验项规则失败行为
文件非空至少有表头行std crate csv is empty
表头首行必须为 package(自动去除 BOM \u{feff} 前缀)invalid header at line N: expected 'package', found '...'
空行空行与首尾空白被忽略,不产生条目跳过
已知包每个包名必须是当前 workspace 的成员(对照 workspace_package_namesunknown workspace package at line N
去重同一包名不允许出现两次duplicate package at line N

所有错误信息都带行号,便于快速定位 CSV 中的问题条目。workspace_package_names 通过 cargo metadata--no-deps 模式,因为只需要 workspace 成员信息)获取当前 workspace 的全部成员包名集合——这意味着如果某个包被从 workspace 移除但 CSV 未同步更新,校验阶段就会报错。

3.2 编码处理

CSV 文件首行可能包含 UTF-8 BOM(\u{feff}),常见于 Windows 编辑器保存的文件。parse_std_crates_csv 通过 header.trim_start_matches('\u{feff}') 自动去除 BOM 后再校验表头,确保跨平台兼容。

4. 测试执行

run_std_test_command 是 CLI 入口(Commands::Testtest::std::run_std_test_command())。加载白名单后,run_std_tests 对普通 package 执行默认命令;对需要特定正式 host adapter 的 package 执行静态定义的 profile。例如:

cargo test -p starry-kernel
cargo test -p ax-fs-ng
cargo test -p ax-hal --features host-test
cargo test -p ax-task --features host-test

ax-hal 等关键 profile 先用同一参数追加 -- --list,并把发现到的测试名与静态预期集合 精确比较。这样 feature 改名或 cfg 漂移导致的“命令成功但实际运行 0 个关键测试”会直接失败。该机制用于确认必需功能实际运行,不是要求为每个测试名、参数或 profile 新增固定断言;清理测试时仍需保持发现和零测试拒绝有效。

关键设计决策:

决策说明
非 fail-fast单包失败不中断后续包,所有包都会跑完,最终汇总全部失败
固定 feature profile只运行源码中逐 package 声明的 host profile,不展开任意 feature 矩阵
无 target 指定使用 host 默认 target,不交叉编译
继承进程环境cargo test 继承当前进程的全部环境变量

非 fail-fast 的设计动机:std 测试是回归门禁,开发者需要一次性看到所有失败包,而非逐个修复后再跑。这与 Clippy 的 fail-fast(快速暴露首个问题以减少 CI 资源占用)形成互补——两者面向不同场景。

4.1 进度输出

每个包执行时打印进度和结果:

[1/45] cargo test -p aarch64_sysreg
ok: aarch64_sysreg
[2/45] cargo test -p ax-io
ok: ax-io
...
[14/45] cargo test -p memory_addr
failed: memory_addr
...

进度前缀 [N/M] 中 M 是白名单总数,N 是当前序号(从 1 开始)。

4.2 运行约束

白名单测试固定使用 host target,不展开未声明的 feature 组合,也不会因一个 package 失败提前停止。--since <REF> 可根据 Cargo 依赖图只选取受影响的白名单成员;增量分析失败时会明确回退到完整白名单。

5. 结果汇总

全部包执行完毕后,根据 failed 列表判定最终结果:

情况输出退出码
全部通过all std tests passed0
存在失败std tests failed for N package(s): <pkg1>, <pkg2>, ...非 0(bail!

失败列表以逗号分隔,按执行顺序(非字母序)排列。

6. 执行抽象

CargoRunner trait 把"执行 cargo test"这一副作用抽象出来,便于单元测试:

trait CargoRunner {
fn run(
&mut self,
workspace_root: &Path,
invocation: &CargoTestInvocation,
) -> anyhow::Result<CargoRunOutput>;
}

生产代码使用 ProcessCargoRunner(实际调用 cargo 子进程),测试代码使用 FakeCargoRunner(按完整 invocation 返回预设结果)。std.rs#[cfg(test)] mod tests 覆盖:

  • CSV 解析:合法格式、空行、空文件、非法表头、未知包、重复包
  • 执行器:多包失败汇总、固定 feature profile、预期测试发现和零测试拒绝
  • 增量选择:保持白名单顺序、无受影响 package,以及失败时全量回退
  • workspace 集成:workspace_package_name_extraction_reads_current_workspace 确认能正确读取当前 workspace 的包名

7. 白名单维护

白名单不是静态的——随着 workspace 演进,新的可测 crate 需要加入,不再适用的需要移除。审计与更新流程由 update-std-tests 技能封装(.agents/skills/update-std-tests/SKILL.md):

  • 比较 workspace packages 与 CSV,列出"在 workspace 中但不在 CSV"的候选(可能需要加入)
  • 列出"在 CSV 中但不在 workspace"的条目(必须移除,否则校验报错)
  • 对候选包逐一验证 cargo test -p <pkg> 是否在 host 通过,通过的才加入白名单

手动编辑 CSV 时,确保每个新增包名是 workspace 成员且 cargo test -p <pkg> 在 host 通过即可。

8. 模块职责

白名单测试代码集中在 std 测试模块及其可替换的 CargoRunner 抽象中。下表说明各部分在校验和执行阶段的职责。

代码位置作用
scripts/axbuild/src/test/std.rs全部逻辑:CLI 入口 run_std_test_command、CSV 解析 parse_std_crates_csv、执行器 run_std_tests + CargoRunner trait、单元测试
scripts/test/std_crates.csv白名单数据(包名一行一个,首行表头 package

9. 命令示例

默认命令读取完整 CSV 并输出每个 package 的进度和最终汇总;--since 可用于本地增量验证。

# 运行白名单中所有 crate 的 std 测试(CI 默认)
cargo xtask test

# 只运行自指定 ref 以来受影响的白名单 package
cargo xtask test --since origin/dev

要新增或移除白名单条目,编辑 scripts/test/std_crates.csv,并按 update-std-tests 技能流程验证对应默认命令或固定 profile。