fix tester multi-root fan-out execution

This commit is contained in:
2026-10-14 15:35:13 +08:00
parent fbf0ca8cd8
commit db92baf3a7
6 changed files with 370 additions and 15 deletions
+68 -9
View File
@@ -7,12 +7,60 @@ Agent、执行目标和临时 terminal 的完整协议见 [execution.md](executi
已有 terminal。
测试结束、失败、超时或中断时,都要关闭本轮创建的 terminal。
## 0. 准备执行目标
## 0. 建立测试矩阵并完成全量 preflight
测试不是“找到一个能跑的设备就开始”。每轮先建立一份测试矩阵;移动端每个目标产物
必须单独占一行:
```text
平台 | 产物路径/下载地址 | commit | 包名或 Bundle ID | tester 绑定 | 执行环境
Android | … | … | page.writes | tester.android | local-app
iOS | … | … | page.writes | tester.ios | remote-ios
```
矩阵来源按优先级使用:用户明确指定的产物、builder/CI 已成功并已 obtain 的产物、
项目本地明确标记的候选产物。不能根据“曾经构建成功过”或 `builder.<platform>`
绑定猜测本轮产物。缺少路径、下载地址、commit 或平台身份时,先报告“待确认”并停止。
平台绑定是测试执行目标,不是构建目标:`builder.ios` 只能证明构建配置,不能替代
`tester.ios`;`builder.android` 同理。多平台运行不得使用无法表达平台的通用
`tester.test` 绑定。每一行都必须解析出独立的 tester Agent、Orca 环境、项目和路径。
完成矩阵后,按以下顺序检查**所有行**,但不执行测试用例:
1. 产物:文件或下载地址存在,SHA/commit(若有)与本轮目标一致;Android APK 的
package、iOS IPA 的 Bundle ID 与矩阵一致。
2. 执行目标:按 [execution.md](execution.md) 精确解析每个平台的 `tester` 绑定;
不允许把本机 worktree 当成远程 Mac 的 worktree,也不允许用旧 commit 的远程目录
代替本轮产物对应的项目目录。
3. 平台环境:Android 执行 adb、设备、APK、HOST 检查;iOS 在 macOS 执行
`uname`、`xcrun`/`simctl`、模拟器或真机、App 安装、HOST 检查。
4. 依赖环境:浏览器、权限、网络、测试账号或 catalog 明确要求的其它 session 前置。
所有检查完成后才能进入下方的 `select` 和 session 初始化。任一行不可用时,必须返回
完整清单并停止:
```text
## tester preflight:阻塞
目标产物: Android, iOS
可用: <平台 + 产物 + 环境>
不可用:
- <平台>: <具体检查项和观测结果>
修复: <用户可执行动作>
验证: <可复制命令>
本轮未创建测试 session,未执行测试用例。
完成修复后重跑原 tester 命令。
```
不能因为 Android 可用就先测 Android,也不能用 API、另一平台或旧产物替代不可用行。
先按 `execution.md` 处理目标机器和项目目录,输出配置更新结果,再进入测试流程。目标测试项目必须包含
可读取的 `.pouch/tester/catalog.yaml`。父仓库可能只是包含多个测试子项目;运行前用
`catalog.py roots --root <repo-root>` 发现并选择目标根,不能把父仓库无 catalog 当成失败,
也不能偷偷回退到另一个子项目或复制测试文件。每个目标根单独生成运行快照。
可读取的 `.pouch/tester/catalog.yaml`。父仓库可能包含多个测试子项目;运行前用
`catalog.py roots --root <repo-root>` 发现全部目标根,不能把父仓库无 catalog 当成失败,
也不能偷偷回退到某一个子项目或复制测试文件。所有目标根都要被 fan-out 调度,每个根独立
做产物/环境 preflight,并单独生成运行快照。
`catalog.py select` 输出的 `agent` 是本轮使用的配置快照。记录中要保留 Agent、目标
环境、主机、项目、路径、worktree id、terminal handle,以及 terminal 是否成功关闭。
@@ -27,12 +75,21 @@ Agent、执行目标和临时 terminal 的完整协议见 [execution.md](executi
python3 <skill-dir>/scripts/catalog.py select --root <root> \
[--category CAT] [--id ID]... [--tag smoke|full|slow] \
[--max-risk <risk>] [--driver script|browser|mobile] \
[--automation automated|assisted|manual|any]
[--automation automated|assisted|manual|any] \
[--platform android|ios]... \
[--artifact android=<path-or-url>] [--artifact ios=<path-or-url>] \
[--binding android=tester.android] [--binding ios=tester.ios]
```
选中任一 `driver=mobile` 用例时,`--platform`、每个平台的 `--artifact` 和对应
`tester` binding 是硬性参数;`catalog.py select` 会检查产物文件/下载地址和
`.pouch/agent.yaml` 中的 binding。缺任何一项直接返回非零并打印 `preflight: blocked`,
不能拿到 cases 后绕过闸门开始测试。默认 binding 是 `tester.<platform>`,所以 iOS
会强制检查 `tester.ios`,不会回退到 `builder.ios` 或通用 `tester.test`。
`--automation` 默认 `automated`(需人工的条目会被跳过,并在 JSON `skipped` 里说明);用户明确要求现场配合时用 `assisted`,`any` 表示不按人工参与度筛。
`select` 的 JSON 字段:`max_risk` / `automation` / `count` / `vars`(已展开的变量,用来替换 `how` 里的 `${…}`)/ `skipped` / `run_together` / `status_probe`(按分类,`url` 已展开)/ `cases`。
单根 `select` 的 JSON 字段:`max_risk` / `automation` / `count` / `vars`(已展开的变量,用来替换 `how` 里的 `${…}`)/ `artifacts` / `preflight` / `skipped` / `run_together` / `status_probe`(按分类,`url` 已展开)/ `cases`。从父仓库 fan-out 时返回 `mode: fan-out` 和每个根的独立结果,不能把多个根的 cases 拼成一个列表。
`select` 已排除 `retired` 和风险高于上限的条目(后者若用户点了具体 id,会在 JSON 的 `skipped` 里说明,不执行)。
@@ -54,8 +111,8 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> \
| mapping | 整体覆盖顶层,不合并(`source: category`)|
- 同一生效探测一次运行只请求一次,结果复用。
- 探测不可达:用它的分类标 environment-fail,其余分类照跑。
- 命中 `stop_if`:把用它的分类标 environment-fail 并记 `observed` 值,其余分类照跑;所有选中分类都被挡住时,整轮结论才是 environment-fail。
- 探测不可达或命中 `stop_if`:在 preflight 阶段记录对应分类/平台的不可用项并停止整轮;
先返回用户处理,不创建后续测试 session。只有所有本轮目标环境通过,才进入用例执行。
## 2.1 移动端平台环境闸门与用户引导
@@ -79,7 +136,9 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> \
3. 被测 IPA/App 已安装,Bundle ID 与 catalog 的变量一致;模拟器可用 `xcrun simctl get_app_container <UDID> <BUNDLE_ID>` 验证。
4. 测试所需的 HOST、端口、局域网/DNS 和权限可从该模拟器/真机访问。
任一项不满足,都要在执行记录中把受影响的移动用例标为 `environment-fail`,不能改成 API 测试、不能把它们标成产品 `fail`,也不要继续初始化后续移动 session。记录实际探测命令及简短输出,不要把整段设备日志塞进对话。
任一项不满足,都要在 preflight 汇总中列出平台、具体检查项、实际探测命令和简短输出,
然后停止整轮;不能先执行其它平台,不能改成 API 测试,也不能把它们标成产品 `fail`。
只有 preflight 全部通过后,才把对应移动用例的结果写入运行快照。
### 环境缺失时的用户引导