fix tester multi-root fan-out execution
This commit is contained in:
@@ -10,12 +10,21 @@
|
||||
|
||||
```yaml
|
||||
bindings:
|
||||
tester.test:
|
||||
tester.android:
|
||||
adapter: tester
|
||||
location: local-app
|
||||
profile: test-agent
|
||||
tester.ios:
|
||||
adapter: tester
|
||||
location: remote-ios
|
||||
profile: test-agent
|
||||
```
|
||||
|
||||
`tester.android` / `tester.ios` 是推荐的平台绑定名。`builder.android`、`builder.ios`
|
||||
只负责构建,不能被 tester 自动继承;这条边界用于防止 iOS 构建成功却仍在 Linux
|
||||
上执行测试。`tester.test` 只能用于明确的单平台或非移动测试;同一轮包含 Android
|
||||
和 iOS 时必须分别解析两个 tester 绑定。
|
||||
|
||||
`locations` 和 `profiles` 的定义见共享 `agent-runtime`。tester adapter 只把它 materialize
|
||||
到本轮兼容配置;每轮 terminal 仍然新建并在结束时关闭,不能因为 binding 是 persistent
|
||||
就复用测试 terminal。
|
||||
@@ -54,7 +63,8 @@ terminal。
|
||||
- Orca terminal id,例如 `term_...`;
|
||||
- 不提供定位信息,使用当前项目。
|
||||
|
||||
有定位信息时优先使用解析脚本,避免手工拼接 Orca JSON:
|
||||
有定位信息时优先使用解析脚本,避免手工拼接 Orca JSON。多平台运行要对每个
|
||||
`tester.<platform>` 绑定分别解析,不能只解析一次 `tester.test` 后复用到所有平台:
|
||||
|
||||
```bash
|
||||
python3 <skill-dir>/scripts/resolve_agent.py \
|
||||
|
||||
@@ -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 全部通过后,才把对应移动用例的结果写入运行快照。
|
||||
|
||||
### 环境缺失时的用户引导
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ runs/*.csv 同一次运行的成绩单;generate_run_csv.py 从对
|
||||
| `risks` | 从低到高,只能是 `readonly` → `mutating` → `destructive` 的一段,且以 `readonly` 开头。含义见 [levels.md](levels.md) |
|
||||
| `default_max_risk` | 未指定时的运行上限,必须是 `risks` 里的值 |
|
||||
| `vars` | 可替换变量,如 `API_BASE: http://${HOST}:8095` |
|
||||
| `artifacts` | 可选的本轮移动产物契约。按 `android` / `ios` 声明 `required` 和 `package` / `bundle_id`;具体文件路径、下载地址、commit 和 SHA 由每轮测试矩阵提供,不提交临时产物路径。 |
|
||||
| `authorize` | 风险名 → 环境变量名。该档执行前变量必须为 `true`(`readonly` 不需要) |
|
||||
| `gates` | 可选。项目细分闸名 → 环境变量。用在用例的 `gate` 上,不要拿它代替 `risk` |
|
||||
| `sessions` | 可复用会话。`kind`: `browser` / `mobile`;`reuse`: `run`(本轮结束关掉)或 `persist`(probe 活着就附着) |
|
||||
|
||||
Reference in New Issue
Block a user