11 KiB
tester 运行
只在用户要跑测试时读本文件。
Agent、执行目标和临时 terminal 的完整协议见 execution.md。每轮运行
都要先解析并更新 agent,输出生效配置列表,准备目标项目并创建一个全新的 terminal;不能复用
已有 terminal。
测试结束、失败、超时或中断时,都要关闭本轮创建的 terminal。
0. 准备执行目标
先按 execution.md 处理目标机器和项目目录,输出配置更新结果,再进入测试流程。目标项目必须包含
可读取的 .pouch/tester/;如果目标目录没有测试目录,记为 environment-fail,不要
偷偷回退到当前项目,也不要把测试文件复制过去。
catalog.py select 输出的 agent 是本轮使用的配置快照。记录中要保留 Agent、目标
环境、主机、项目、路径、worktree id、terminal handle,以及 terminal 是否成功关闭。
1. 选范围
未指定范围 → --tag smoke,风险上限 = default_max_risk,automation 默认只跑 automated。
用户说分类、id、tag、风险上限时,原样传给 select:
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(需人工的条目会被跳过,并在 JSON skipped 里说明);用户明确要求现场配合时用 assisted,any 表示不按人工参与度筛。
select 的 JSON 字段:max_risk / automation / count / vars(已展开的变量,用来替换 how 里的 ${…})/ skipped / run_together / status_probe(按分类,url 已展开)/ cases。
select 已排除 retired 和风险高于上限的条目(后者若用户点了具体 id,会在 JSON 的 skipped 里说明,不执行)。
若 catalog 有 run_together,命中组内任一条就把整组按 ids 顺序扩进列表(JSON 带 run_together)。这不是擅自扩大范围。
无命中:停下说明筛选条件,不要扩大范围。
2. 运行前闸
-
HOST未设(环境变量 /HX_TEST_HOST/local.yaml都没有):全部停,environment-fail。 -
命中条的
risk在 catalogauthorize里有对应变量:变量不是true则该条skipped。有gate时还要catalog.gates对应变量为true;assume不成立同样skipped。即使用户点了 id 也不执行。 -
授权/假设不成立是主动不跑(
skipped),不是not-run:这是我们决定不跑,不是没轮到。 -
status_probe是分类级前置条件(业界对应 pytest 的 session fixture / Robot 的 Suite Setup)。用select返回的status_probe解析生效值,不要自己读 catalog 猜。返回的probe.url已用vars展开,直接请求即可;select同批返回vars:categories[].status_probe生效探测 未声明 继承顶层 catalog.status_probe(source: global)false该分类不做闸( source: disabled)mapping 整体覆盖顶层,不合并( source: category) -
同一生效探测一次运行只请求一次,结果复用。
-
探测不可达:用它的分类标 environment-fail,其余分类照跑。
-
命中
stop_if:把用它的分类标 environment-fail 并记observed值,其余分类照跑;所有选中分类都被挡住时,整轮结论才是 environment-fail。
2.1 移动端平台环境闸门与用户引导
driver=mobile 不是一个可以互换的平台。运行前必须根据 catalog session、用例变量或用户指定,明确本轮是 Android 还是 iOS;无法判断时先停下询问平台,不得猜测。两类平台分别执行以下闸门:
Android
按顺序确认:
adb可执行,且版本与当前 SDK 配置一致。adb devices -l至少有一个状态为device的目标;unauthorized、offline或空列表都不能继续。多个目标时必须显式设置ANDROID_SERIAL。- 被测 APK 已安装,包名与 catalog 的变量一致;可用
adb -s "$ANDROID_SERIAL" shell pm path "$PACKAGE"验证。 - 测试所需的 HOST、端口、局域网/DNS 和权限可从设备访问。
iOS
按顺序确认:
- 运行节点是 macOS,并且
xcrun、Xcode Command Line Tools 和simctl可用。Linux/Windows 节点不能伪装成 iOS 环境;需要 macOS 或可访问的远程 Mac。 - 模拟器用
xcrun simctl list devices available确认目标存在且已启动,再用xcrun simctl bootstatus <UDID> -b确认完成启动;真机用xcrun xctrace list devices确认已连接、已信任且允许开发。 - 被测 IPA/App 已安装,Bundle ID 与 catalog 的变量一致;模拟器可用
xcrun simctl get_app_container <UDID> <BUNDLE_ID>验证。 - 测试所需的 HOST、端口、局域网/DNS 和权限可从该模拟器/真机访问。
任一项不满足,都要在执行记录中把受影响的移动用例标为 environment-fail,不能改成 API 测试、不能把它们标成产品 fail,也不要继续初始化后续移动 session。记录实际探测命令及简短输出,不要把整段设备日志塞进对话。
环境缺失时的用户引导
对话中必须输出一段可执行的引导,至少包含以下字段:
## tester 环境引导:需要补齐
平台: Android | iOS
状态: environment-fail
缺失: <具体探测项和观测结果>
请完成:
1. <修复动作;不要只写“检查设备”>
2. <如需连接/启动/安装,写出动作>
验证:
<一条或多条可复制的验证命令>
完成后: 回复“环境已就绪”,然后重跑原 tester 命令。
可按实际缺失替换为以下平台化提示:
- Android 无设备:提示用户连接并解锁设备、开启 USB 调试、接受 RSA 授权;多个设备时设置
ANDROID_SERIAL;再运行adb devices -l,直到目标状态为device。 - Android 未安装 APK:提示用户构建/安装与当前测试环境匹配的 APK,并用
adb -s "$ANDROID_SERIAL" shell pm path "$PACKAGE"验证包名。 - iOS 非 macOS 或无 Xcode:明确说明 iOS 测试需要 macOS + Xcode/Command Line Tools,提示用户切换到本机 Mac 或配置可访问的远程 Mac;不要建议在 Linux 上安装一个同名命令来绕过检查。
- iOS 模拟器未启动:提示用户在 Xcode 或
simctl中创建/启动可用设备,使用xcrun simctl bootstatus <UDID> -b验证。 - iOS 真机未就绪:提示用户连接数据线、解锁并信任此电脑、开启开发者模式并确认设备出现在
xcrun xctrace list devices。
以下是两个可复现的引导示例,测试 skill 行为时应得到同类结果:
- Android:
adb devices -l只有List of devices attached。期望状态为environment-fail,引导连接/授权设备并给出adb devices -l验证命令。 - iOS:Linux 节点没有
xcrun。期望状态为environment-fail,引导切换到 macOS + Xcode 节点,并说明不能用 API 或 Android session 代替。
环境引导只负责让用户补齐前置条件;除 catalog 已明确授权的 session 初始化外,不自动安装 SDK、配对真机、修改系统安全设置或上传产物。
3. Session
看命中条用到的 session 键:
- 尚未初始化:按 catalog
sessions.<name>.init做。reuse: persist的先probe,活着就附着。 - 本轮已初始化:直接用,不要重开浏览器或模拟器。
reuse: run:整轮结束再关。persist:不关。- 中途 session 挂了:后续同 driver 标 environment-fail,不要标产品失败。
4. 执行
按 select 返回的顺序,一条一条来。select 按 catalog.yaml 的 categories 顺序,同一分类内按该 yaml 列表顺序(不是文件名字母序)。默认失败即停(产品 fail 或探测到的不安全状态)。用户说继续 / keep-going 才往后跑。
例外:当前条和下一条同属 run_together 且该组 continue_on_fail: true 时,前一条产品 fail 仍跑后一条。environment-fail 仍整轮停。
automation
automated:Agent 端到端执行。assisted:照常驱动,但遇到以[人工]开头的how.steps时停下,请现场人员执行并回报,确认后再继续。无人值守时该条记not-run。manual:没有driver,run-script会直接返回not-run。只能由人执行、回报结果,Agent 负责记录。
script
有 how.run:
python3 <skill-dir>/scripts/catalog.py run-script --root <root> --id <id>
这个命令必须发送到本轮创建的 terminal 中执行;<root> 是目标机器上的项目根,
不是发起端当前目录。远程目标上的 skill 脚本不可用时,直接在该 terminal 中执行
how.run 展开后的命令,并保留同样的 stdout/exit 证据。run-script 只跑命令,返回
executed + stdout/exit(或 skipped / environment-fail)。pass/fail 仍由 Agent 对照
expected 判定,不要把 curl 退出码 0 当成产品通过。
没有 run:按 how.steps 做,证据对照 expected。不要发明 steps 里没有的调用。
browser / mobile
挂到已有 session,执行 how.steps,对照 expected。必须留下可见文本、URL 或交互证据。
5. 记录与报告
每条:id, result, evidence, notes。result 只能是 pass / fail / environment-fail / skipped / not-run。skipped 是主动不跑(retired / pending / 超风险上限 / 未授权 / assume 不成立),not-run 是没轮到(失败即停后剩下的 / 被前置整组挡住的 / 需人工而无人值守的)。
写入 .pouch/tester/runs/<UTC时间>-<范围>-<随机后缀>.yaml,可用
generate_run_csv.new_run_id(<范围>) 生成同名 runId。记录包含唯一 runId、筛选条件、HOST 是否已设(可以写 HOST 值)、session 是否复用、每个分类的 status_probe 生效值与观测结果(source / disabled 原因 / hit / observed)、逐条结果。记录文件只创建一次,不覆盖已有文件。立刻用同一快照生成 CSV,不要手改:
python3 <skill-dir>/scripts/generate_run_csv.py --root <root> --run <yaml>
这会写出与快照同名的 .pouch/tester/runs/<run-id>.csv(executed=yes|no),不会修改 cases.csv。对话里两个路径都报。
对话报告:
## tester 运行:完成 | 部分完成 | 阻塞
范围: …
风险上限: …
session: browser=复用|新开|未用;mobile=…
Agent: <cli> / <model> / <permissionMode>
执行目标: <environment>/<host>:<project>:<path>
terminal: 新建 <handle>,已关闭|清理失败
计数: pass=N fail=N environment-fail=N skipped=N not-run=N
失败: id + 一句证据
跳过: id + 原因
快照: .pouch/tester/runs/<file>.yaml
成绩单: .pouch/tester/runs/<file>.csv
下一步: 一句话