这份手册描述当前已落地的两层测试体系、PR 阻塞运行方式、长时回归运行方式,以及未来接入 CI 的建议路线。
当前唯一真值环境是 Mac + QEMU + OpenWrt ARM VM。UTM 只用于人工调试,不作为验收结果来源。若要上 CI,需要 自托管 Apple Silicon runner,不能假设云 CI 自带可用执行环境。
早期版本中存在独立的 VM-backed API 契约测试脚本(test-api-contract.sh)和浏览器驱动的 E2E 测试(Playwright)。它们已被移除,原因如下:
- API 契约覆盖:
server/*_test.go中的 Go 单元测试通过MemoryNft+MemoryFileStoremock 对所有 API 端点进行契约验证,覆盖 happy path、负例矩阵、幂等性、错误 fixture 等场景,维护成本远低于需要真实 VM 的 shell 脚本,且在任何环境下都可运行。 - 浏览器 E2E 覆盖:portal 是一个结构简单的管理仪表板,Go API 测试加上前端组件测试已提供足够覆盖,不需要完整的 Playwright E2E 层。
执行任一 VM-backed 测试前,需要满足以下前提:
- 宿主机是 macOS,且可运行 QEMU。
- 已具备 OpenWrt ARM VM 所需依赖与本地权限。
- 仓库中的 OpenWrt VM 脚本可正常执行,尤其是
scripts/openwrt-vm/test-common.sh --ensure-vm-ready。 /api/refresh-route必须走 fixture seam,不能把公网 APNIC 当成测试依赖。
其中,bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready 是当前 VM readiness 与 deploy 真值入口。它会串行完成 boot、wait-ready、单二进制 deploy、首启自举,以及 canonical service wiring 断言。
当前测试体系分两层,边界固定,不要混用。
这层不依赖真实 VM,目标是快速验证后端 API 处理逻辑、前端 Preact 组件、状态流转、反馈文案和交互禁用语义。
后端 Go 测试覆盖所有 API 端点的契约、nftables 操作、健康检查生命周期等,使用 mock 实现,在本地和 CI 上均可稳定运行。
入口命令:
# 后端快速层
cd server && go test ./...
# 前端快速层
cd portal && npm run test:component适用场景:
- PR 快速阻塞
- 后端 API 处理逻辑与端点契约回归
- 前端状态机与组件反馈回归
- 在 VM 还没启动前先发现明显后端/前端逻辑问题
这层通过真实 OpenWrt VM 验证平台级行为,包括 opkg 生命周期(热插拔、安装、升级、卸载)以及 LuCI 入口探针。它不依赖浏览器,专注于 guest 副作用与平台集成正确性。
入口命令:
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready
bash scripts/openwrt-vm/test-ipk-install.sh --service-only
bash scripts/openwrt-vm/test-ipk-upgrade-uninstall.sh
bash scripts/openwrt-vm/test-luci-proxy-probe.sh适用场景:
- IPK 打包与 opkg 安装/升级/卸载流程验证
- 配置持久化、LuCI 缓存清理等平台级回归
- LuCI/uhttpd 同源承载可行性探针
当前 VM 环路的真值不是预置 tar 包、预置目录树,也不是手工把 config/init/files 整包拷进 guest。唯一真值是:
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready该入口当前会执行以下步骤:
- 若 VM 未运行,则先执行
boot-vm.sh。 - 执行
wait-ready.sh,确认 SSH/ubus 可用。 - 调用
scripts/openwrt-vm/deploy.sh,把 host 侧刚编译的单个linux/arm64二进制上传到 guest 临时目录。 - deploy 只把这个单二进制安装到
/etc/transparent-proxy/server,不会额外上传 tar.gz、配置目录树或托管文件目录。 - deploy 直接触发首启自举,由
/etc/transparent-proxy/server -c /etc/transparent-proxy/config.yaml负责生成 canonicalconfig.yaml、/etc/init.d/transparent-proxy与所需托管资产。 test-common.sh最后断言 canonical layout 和 service wiring 已成立,其中 init 脚本必须包含/etc/transparent-proxy/server -c /etc/transparent-proxy/config.yaml。
因此,后续平台集成测试链路看到的 guest 状态,都是"复制单个二进制并触发首启自举"后的结果,而不是历史上的预装资产模型。
在推进 LuCI 入口方案前,先运行专用探针判断"是否能在当前 VM 镜像上通过 LuCI/uhttpd 暴露受保护同源子路径给 transparent-proxy"。
入口命令:
bash scripts/openwrt-vm/test-luci-proxy-probe.sh
bash scripts/openwrt-vm/test-luci-proxy-probe.sh --force-negative行为约定:
- 脚本会先调用
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready作为 readiness 真值入口。 - 输出二值结果:
SAME_ORIGIN_SUPPORTED=1或SAME_ORIGIN_SUPPORTED=0。 - 当前状态:在当前 OpenWrt VM 镜像上,探针结果已锁定为
SAME_ORIGIN_SUPPORTED=0。这意味着 LuCI 插件目前仅支持 fallback-only 模式,即 LuCI 界面仅作为跳转到独立管理页面的入口。 - 退出码契约:
0=支持,20=不支持(探针已完成并写出证据),1=脚本执行失败。 - 机器可读结果写入:
.tmp/openwrt-vm/luci-probe.env。 - 证据写入:
.tmp/openwrt-vm/luci-probe-summary.txt.sisyphus/evidence/task-1-luci-proxy-probe.txt- 负路径时额外写
.sisyphus/evidence/task-1-luci-proxy-probe-error.txt
--force-negative用于强制演练失败分支,并显式打出 Task 9 fallback marker。
随着 ipk 分发路径的引入,测试体系新增了针对 opkg 生命周期和 LuCI 入口的回归验证。
验证 opkg install 流程以及在 SAME_ORIGIN_SUPPORTED=0 模式下的 LuCI 降级表现。
入口命令:
bash scripts/openwrt-vm/test-ipk-install.sh --service-only
bash scripts/openwrt-vm/test-luci-entry.sh行为约定:
- 两个脚本都会先调用
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready。 test-ipk-install.sh --service-only:- 本地构建
transparent-proxyipk; - 在 VM 上执行
opkg install; - 验证 canonical service 资产、
/api/status健康检查,以及"未安装 LuCI 包时 LuCI 路由保持 404"; - 证据写入
.sisyphus/evidence/task-10-service-only.txt。
- 本地构建
test-luci-entry.sh:- 本地构建
transparent-proxy与luci-app-transparent-proxyipk; - 在 VM 上安装 service + LuCI 包;
- 验证
/api/status健康、LuCI route 存在、fallbackNotice/fallbackTarget 已注入,以及交付的 LuCI view JS 继续锁定 fallback-only 语义; - 证据写入
.sisyphus/evidence/task-10-luci-entry.txt。
- 本地构建
验证 opkg upgrade 和 opkg remove 流程,确保配置持久化和 LuCI 缓存清理。
入口命令:
bash scripts/openwrt-vm/test-ipk-upgrade-uninstall.sh行为约定:
- 脚本会先调用
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready。 - 之后会分别构建 old/new 两组
transparent-proxy与luci-app-transparent-proxyipk,并在 VM 中固定验证以下回归点:- 配置持久化:升级
transparent-proxy时,用户编辑过的config.yaml保持字节级不变。 - 缓存清理:升级
luci-app-transparent-proxy时,自动清理/tmp/luci-indexcache.*与/tmp/luci-modulecache/,确保 UI 不会出现白屏或旧版本残留。 - 卸载回归:卸载
luci-app-transparent-proxy后,服务仍可通过http://127.0.0.1:1444独立访问,且 LuCI 路由回到404。 - 部分卸载:卸载
transparent-proxy后,LuCI 路由应消失或返回降级说明页,不得出现 5xx 错误。
- 配置持久化:升级
- 证据写入:
.sisyphus/evidence/task-11-upgrade-cache.txt.sisyphus/evidence/task-11-upgrade-cache.png.sisyphus/evidence/task-11-uninstall.txt
/api/refresh-route 的测试必须显式依赖 fixture seam,而不是公网。
关键环境变量:
TP_REFRESH_ROUTE_FIXTURETP_CHNROUTE_FIXTURE_PATH
当前约定:
TP_REFRESH_ROUTE_FIXTURE提供默认 fixture 路径。- wrapper 和测试套件会把该 seam 显式注入到 guest 进程。
refresh-route测试不依赖公网,不应把ftp.apnic.net可用性当成阻塞条件。
也就是说,只要 fixture 正常,/api/refresh-route 的成功路径和失败路径都可以在离线或受限网络下稳定复现。
以下变量是本手册里最重要的运行契约:
TP_API_BASE_URL:VM API 基础地址,默认http://127.0.0.1:1444。TP_REFRESH_ROUTE_FIXTURE:refresh-route默认 fixture 文件。TP_CHNROUTE_FIXTURE_PATH:chnroute fixture 文件路径。
PR 阻塞应跑最短但仍覆盖两层真值的组合:
bash scripts/openwrt-vm/test-all.sh --tier blocking等价串行步骤为:
cd server && go test ./...
cd portal && npm run test:component
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready
bash scripts/openwrt-vm/test-ipk-install.sh --service-only适合放进 PR 阻塞的原因:
- 先用快速层尽早发现后端/前端逻辑回归(包括 API 端点契约验证)
- 再用
scripts/openwrt-vm/test-common.sh --ensure-vm-ready固定单文件 deploy 与 canonical wiring 真值 - 再验证 IPK 安装与 service 启动的平台集成正确性
长时回归应跑完整回归分层:
bash scripts/openwrt-vm/test-all.sh --tier regression等价串行步骤为:
cd server && go test ./...
cd portal && npm run test:component
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready
bash scripts/openwrt-vm/test-ipk-install.sh --service-only
bash scripts/openwrt-vm/test-ipk-upgrade-uninstall.sh
bash scripts/openwrt-vm/test-luci-proxy-probe.sh适合在以下时机执行:
- 合并前人工回归
- 夜间或长时本地回归
- 自托管 runner 上的定时回归
仓库提供统一串行入口:
bash scripts/openwrt-vm/test-all.sh --tier blocking
bash scripts/openwrt-vm/test-all.sh --tier regression行为约定:
--tier blocking:Go 测试 -> 组件 -> VM ready / 单文件 deploy 断言 -> IPK install blocking--tier regression:Go 测试 -> 组件 -> VM ready / 单文件 deploy 断言 -> IPK install -> upgrade/uninstall -> LuCI probe- 任一步失败即退出,适合本地和未来 CI 直接复用
- 该脚本只编排现有入口,不改变既有测试语义
VM 相关日志和失败留痕默认位于:
.tmp/openwrt-vm/artifacts/
.tmp/openwrt-vm/logs/
.tmp/openwrt-vm/run/其中:
collect-artifacts.sh会在 wrapper 或 suite 失败时尽力补采 guest 证据- QEMU、deploy、wait-ready 等辅助信息也会落在
.tmp/openwrt-vm/下 - 若失败发生在 readiness/deploy 阶段,优先把
test-common.sh --ensure-vm-ready视为真值入口回放问题
先跑快速层:
cd server && go test ./...
cd portal && npm run test:component需要完整真值验证时再跑:
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready
bash scripts/openwrt-vm/test-all.sh --tier blocking需要更长回归时再跑:
bash scripts/openwrt-vm/test-all.sh --tier regression建议把 blocking 作为 PR 阻塞线,把 regression 作为人工或定时回归线。当前不要直接假设现有云 CI 能承载 OpenWrt ARM VM。
排查时按下面顺序走,最快也最省时间:
- 快速层:先确认
cd server && go test ./...和cd portal && npm run test:component是否通过。Go 测试失败通常意味着 API 端点契约、nftables 逻辑或健康检查行为有问题;前端测试失败意味着组件状态、渲染或交互语义有问题。 - VM readiness / deploy 层:再看
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready,先确认单二进制上传、首启自举、canonical wiring 是否成立。 - 平台集成层:然后看
test-ipk-install.sh、test-ipk-upgrade-uninstall.sh等。如果这里已经失败,排查 IPK 打包、opkg 生命周期和 guest 副作用。 - VM artifacts:最后看
.tmp/openwrt-vm/artifacts/、.tmp/openwrt-vm/logs/、guest 侧收集结果,确认是不是 VM 未就绪、单文件 deploy 未完成、首启自举失败或 OpenWrt 侧命令失败。
一句话版顺序:Go/组件 -> ensure-vm-ready -> 平台集成 -> VM artifacts。
当前只写路线建议,不直接启用新的 CI pipeline。
建议分层如下:
- Tier 1,轻量阻塞
- 先在普通环境跑
cd server && go test ./...和cd portal && npm run test:component - 这层不要求 VM,涵盖所有 API 契约验证
- 先在普通环境跑
- Tier 2,VM-backed PR 阻塞
- 在自托管 Apple Silicon runner 上跑
bash scripts/openwrt-vm/test-all.sh --tier blocking - 其真值前提仍是
scripts/openwrt-vm/test-common.sh --ensure-vm-ready所代表的单文件安装契约 - 这是最有价值的 PR 真值阻塞线
- 在自托管 Apple Silicon runner 上跑
- Tier 3,定时或人工长时回归
- 在同类 runner 上跑
bash scripts/openwrt-vm/test-all.sh --tier regression - 适合 nightly、release candidate、合并前人工确认
- 在同类 runner 上跑
不建议:
- 假设 GitHub-hosted 或其他云 runner 默认带有可用 Apple Silicon + QEMU + OpenWrt VM 能力
- 把 regression 直接塞进每个 PR 的阻塞链路,导致反馈时间过长
# 快速层(后端 + 前端,含所有 API 契约验证)
cd server && go test ./...
cd portal && npm run test:component
# VM readiness / 单文件 deploy 真值入口
bash scripts/openwrt-vm/test-common.sh --ensure-vm-ready
# LuCI/uhttpd 同源承载可行性探针
bash scripts/openwrt-vm/test-luci-proxy-probe.sh
bash scripts/openwrt-vm/test-luci-proxy-probe.sh --force-negative
# IPK 安装回归
bash scripts/openwrt-vm/test-ipk-install.sh --service-only
# IPK 升级与卸载回归
bash scripts/openwrt-vm/test-ipk-upgrade-uninstall.sh
# tier 单入口
bash scripts/openwrt-vm/test-all.sh --tier blocking
bash scripts/openwrt-vm/test-all.sh --tier regression