14 · 测试、CI 与发布
对维护工具而言,测试的第一条要求不是覆盖率,而是测试运行本身绝不能触发真实 sudo、AppleScript 或系统服务修改。
测试规模与分层
固定提交中可统计到 72 个 tests/ 文件、约 1289 个 Bats @test,Go 侧约 306 个 Test* 与 1 个 benchmark。数量不是质量证明,但显示安全边界并非只靠人工约定。
scripts/test.sh 同时运行 Shell 单元/集成测试与 Go 测试。Bats 文件可并行执行,CI 默认 6 workers,并生成 JUnit 报告列出最慢文件。性能断言通过环境变量给出预算,降低不同 CI 机器上的随机失败。
测试宿主机隔离
运行器设置 MOLE_TEST_NO_AUTH=1,并把 stub sudo、osascript、launchctl 放到 PATH 最前。真实授权请求必然失败,launchctl 只记录调用。每个测试使用独立 HOME,遗留超过 60 分钟的临时目录才被清理,避免与仍在运行的长测试竞争。
Go TUI helper 预先构建到临时目录供 CLI 测试使用;即使构建失败,测试也能按能力降级。NO_COLOR 在测试中清除,使 ANSI 输出断言不受开发者环境影响。
静态质量门
scripts/check.sh 覆盖 shfmt、goimports/gofmt、golangci-lint(不可用时 go vet)、ShellCheck 与全量 Bash 语法。Check workflow 把格式和质量拆成依赖 job;format job只检查 diff,避免 CI 自动改文件。
Security job 额外:
- 搜索未通过安全 wrapper 或明确注释的
rm -rf; - 运行关键应用保护 smoke test;
- 使用 gitleaks 扫描秘密;
- 保留完整 git history 供安全扫描。
兼容矩阵运行 macOS 14 与 15,并对 core safe functions、timeout、regression、CLI 做子集验证。
Release 的可追溯产物
标签 V* 触发 release。amd64 与 arm64 都在 macOS runner 上以纯 Go 构建,随后检查最低 macOS 版本。发布 job 合并二进制与 Homebrew tarball,按确定顺序生成 SHA256SUMS,再使用 GitHub artifact attestation 生成 provenance。
release asset、checksum 与 provenance 是安装器校验链的生产端。之后 workflow 自动准备 Homebrew Core 更新,URL 与源码 SHA-256 从 tag 计算,避免手工复制错误。
仍然存在的测试边界
大量 Bats 测试可以验证字符串、路径与 stubbed 系统命令,但无法完全模拟 APFS、TCC 隐私拒绝、外置卷 Trash、真实 Spotlight 索引和不同企业 EDR。因此代码仍选择保守失败,并保留 macOS 实机矩阵;这不是测试不足的借口,而是对不可模拟边界的明确承认。
关键源码索引
scripts/test.sh:测试隔离、并发与汇总。scripts/check.sh:格式、lint 与语法门。.github/workflows/test.yml:测试、安全与兼容矩阵。.github/workflows/check.yml:质量检查。.github/workflows/release.yml:跨架构产物、checksum 与证明。
下一章抽离具体命令,总结哪些架构模式可以迁移,哪些复杂度是 Mole 特定风险换来的。