feat(tester): support isolated full regression workflow
This commit is contained in:
@@ -35,6 +35,7 @@ catalog(整个测试集)
|
||||
| `session` | 可复用会话(浏览器 / 模拟器) | pytest fixture;Robot suite variable | 不是一条用例 |
|
||||
| `gate` | 项目细分闸门名 → 环境变量(`motion` / `hardware` / `weld`) | 授权开关 | 不是 `risk`,不要拿它代替风险等级 |
|
||||
| `authorize` | 风险档 → 环境变量。该档执行前必须为 `true` | pytest `skipif` 条件 | 不是认证(auth),是**授权** |
|
||||
| `execution_profile` | 执行环境策略:`standard` 或隔离可重置的 `isolated-full` | pytest marker/fixture policy | 不是风险等级;isolated-full 不会抹掉 `risk` |
|
||||
| `assume` | 额外跳过条件(gate / authorize 之外的环境表达式) | JUnit `assumeTrue`;pytest `skipif` | 不是授权开关的重复写法 |
|
||||
| `status_probe` | 分类级前置条件:请求一个 URL,命中即视为前置不满足 | pytest session fixture;Robot Suite Setup | 不是产品失败,不是整轮硬闸 |
|
||||
| `how` | 怎么测:`steps` / `run` / `url` / `timeout` | test steps | 不是判定标准 |
|
||||
@@ -55,7 +56,7 @@ catalog(整个测试集)
|
||||
| `pass` | 通过 | passed |
|
||||
| `fail` | 产品缺陷 | failed |
|
||||
| `environment-fail` | 前置/环境导致无法执行,**永远不是产品失败** | pytest error;JUnit aborted |
|
||||
| `skipped` | **主动**不跑:`retired` / `pending` / 超风险上限 / 未授权 / `assume` 不成立 | pytest skipped;JUnit disabled |
|
||||
| `skipped` | **主动**不跑:standard 下的 `retired` / `pending` / 超风险上限 / 未授权 / `assume` 不成立 | pytest skipped;JUnit disabled |
|
||||
| `not-run` | **被动**没轮到:失败即停后剩下的;分类被 `status_probe` 挡住整组没执行;`automation` 需人工而无人值守 | pytest not run;deselected |
|
||||
|
||||
## 2. 命名迁移对照(v1 → v2)
|
||||
@@ -82,6 +83,8 @@ catalog(整个测试集)
|
||||
- 三级**单调**:`readonly ⊂ mutating ⊂ destructive`,所以只需要一个上限 `default_max_risk` 和一个 `--max-risk`,不用组合矩阵。
|
||||
- 与 `gate` 正交:`risk` 说「影响多大」,`gate` 说「碰哪个子系统」。点动 vs 焊接这种细分授权用 `gate`,不要再造 risk 名。
|
||||
- `tag=smoke` 只能配 `risk=readonly`:冒烟测试不许留下变化。
|
||||
- 隔离可重置环境可设置 `execution_profile: isolated-full` 跑所有 active 用例;安全前置由
|
||||
test-preflight capability 与 cleanup/rollback 契约保证,原始 risk 仍必须报告。
|
||||
|
||||
### 3.2 `automation`:为什么是 `automated / assisted / manual`
|
||||
|
||||
@@ -93,6 +96,7 @@ catalog(整个测试集)
|
||||
- `assisted`:Agent 驱动,但至少一步需要人在场;该步在 `how.steps` 里以 `[人工]` 开头(可被 `validate` 机器判定)。
|
||||
- `manual`:只能人工执行;禁止 `driver`、禁止 `how.run`,必须有 `how.steps`。
|
||||
- 默认只跑 `automated`。无人值守时 `assisted` / `manual` 记 `not-run`;有人在场时 `assisted` 暂停等人确认,`manual` 由人工回报结果。
|
||||
- isolated-full 只取消风险/授权过滤,不伪造 assisted/manual 的人工步骤。
|
||||
|
||||
### 3.3 结果为什么拆出 `not-run`
|
||||
|
||||
|
||||
@@ -36,7 +36,11 @@
|
||||
| `destructive` | 难恢复或伤人/伤钱/伤环境 | 删库、真实扣费 | 清数据、内购 | 急停、断电、真焊 |
|
||||
|
||||
默认只跑 `readonly`。项目细分闸(点动 vs 焊接)用可选 `gate`,不要再发明 risk 名。
|
||||
隔离且可重置的项目可在 catalog 设置 `execution_profile: isolated-full`,此时所有 active
|
||||
用例按原始 risk 执行;`risk` 仍用于报告和 cleanup 设计,不能改写为 readonly。
|
||||
|
||||
`tag=smoke` 且 `risk!=readonly` 为非法。
|
||||
|
||||
不想跑某一档时,`authorize.<risk>` 指向的环境变量保持 false 即可——该档用例记 `skipped`,不是 `not-run`。
|
||||
standard 下不想跑某一档时,`authorize.<risk>` 指向的环境变量保持 false 即可——该档用例记
|
||||
`skipped`,不是 `not-run`。isolated-full 不使用这些授权开关,改由 preflight 能力探针和
|
||||
cleanup/rollback 契约阻断不安全环境。
|
||||
|
||||
@@ -72,7 +72,11 @@ iOS | … | … | page.writes | tester.ios | remote-ios
|
||||
|
||||
## 1. 选范围
|
||||
|
||||
未指定范围 → `--tag smoke`,风险上限 = `default_max_risk`,`automation` 默认只跑 `automated`。
|
||||
未指定范围 → `--tag smoke`,执行 profile = catalog 的 `execution_profile`(默认 `standard`),
|
||||
`standard` 的风险上限 = `default_max_risk`,`automation` 默认只跑 `automated`。
|
||||
`execution_profile=isolated-full` 只用于隔离可重置环境:不按风险上限或 `AUTHORIZE_*`/gate
|
||||
授权变量过滤 active 用例,保留每条用例原始 `risk`;安全门禁由 test-preflight 能力探针和
|
||||
cleanup/rollback 契约承担。
|
||||
|
||||
用户说分类、id、tag、风险上限时,原样传给 select:
|
||||
|
||||
@@ -80,6 +84,7 @@ iOS | … | … | page.writes | tester.ios | remote-ios
|
||||
python3 <skill-dir>/scripts/catalog.py select --root <root> \
|
||||
[--category CAT] [--id ID]... [--tag smoke|full|slow] \
|
||||
[--max-risk <risk>] [--driver script|browser|mobile] \
|
||||
[--execution-profile standard|isolated-full] \
|
||||
[--automation automated|assisted|manual|any] \
|
||||
[--test-type integration|journey] [--suite <client-or-integration-suite>] \
|
||||
[--platform android|ios]... \
|
||||
@@ -111,11 +116,11 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> --suite api-contract
|
||||
不能拿到 cases 后绕过闸门开始测试。默认 binding 是 `tester.<platform>`,所以 iOS
|
||||
会强制检查 `tester.ios`,不会回退到 `builder.ios` 或通用 `tester.test`。
|
||||
|
||||
`--automation` 默认 `automated`(需人工的条目会被跳过,并在 JSON `skipped` 里说明);用户明确要求现场配合时用 `assisted`,`any` 表示不按人工参与度筛。
|
||||
`--automation` 默认 `automated`(需人工的条目会被记为 `not-run`,不会伪造人工步骤);用户明确要求现场配合时用 `assisted`,`any` 表示不按人工参与度筛。
|
||||
|
||||
单根 `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` 里说明,不执行)。
|
||||
`standard` 的 `select` 已排除 `retired` 和风险高于上限的条目(后者若用户点了具体 id,会在 JSON 的 `skipped` 里说明);`isolated-full` 保留所有 active 条目,不因风险或授权变量 skipped。
|
||||
|
||||
若 catalog 有 `run_together`,命中组内任一条就把整组按 `ids` 顺序扩进列表(JSON 带 `run_together`)。这不是擅自扩大范围。
|
||||
|
||||
@@ -135,8 +140,9 @@ preflight 通过后,先按 catalog 顺序执行 `integration`,再按客户
|
||||
## 3. 运行前闸
|
||||
|
||||
- `HOST` 未设(环境变量 / `local.yaml` 都没有):全部停,environment-fail。
|
||||
- 命中条的 `risk` 在 catalog `authorize` 里有对应变量:变量不是 `true` 则该条 `skipped`。有 `gate` 时还要 `catalog.gates` 对应变量为 `true`;`assume` 不成立同样 `skipped`。即使用户点了 id 也不执行。
|
||||
- 授权/假设不成立是**主动不跑**(`skipped`),不是 `not-run`:这是我们决定不跑,不是没轮到。
|
||||
- `standard`:命中条的 `risk` 在 catalog `authorize` 里有对应变量时,变量不是 `true` 则该条 `skipped`;有 `gate` 时还要对应变量为 `true`,`assume` 不成立同样 `skipped`。即使用户点了 id 也不执行。
|
||||
- `isolated-full`:不读取 `AUTHORIZE_MUTATING`、`AUTHORIZE_DESTRUCTIVE`、`AUTHORIZE_ALBUM`、`AUTHORIZE_PASSWORD` 等人工开关;相册、照片权限/测试图片和中文拼音真实 composition/candidate 能力必须由 test-preflight 证明。
|
||||
- standard 中授权/假设不成立是**主动不跑**(`skipped`);isolated-full 的能力缺失是 preflight blocked/environment-fail,并为全部 testcase 写 `not-run` + `blocked_by: [test-preflight]`。
|
||||
- `status_probe` 是**分类级前置条件**(业界对应 pytest 的 session fixture / Robot 的 Suite Setup)。用 `select` 返回的 `status_probe` 解析生效值,不要自己读 catalog 猜。返回的 `probe.url` 已用 `vars` 展开,直接请求即可;`select` 同批返回 `vars`:
|
||||
|
||||
| `categories[].status_probe` | 生效探测 |
|
||||
@@ -221,7 +227,7 @@ Android+iOS 默认是全量 preflight 闸门:任一项不满足,另一平台
|
||||
|
||||
## 5. 执行
|
||||
|
||||
按 select 返回的顺序,一条一条来。select 按 `catalog.yaml` 的 `categories` 顺序,同一分类内按该 yaml 列表顺序(不是文件名字母序)。默认失败即停(产品 `fail` 或探测到的不安全状态)。用户说继续 / keep-going 才往后跑。
|
||||
按 select 返回的顺序,一条一条来。select 按 `catalog.yaml` 的 `categories` 顺序,同一分类内按该 yaml 列表顺序(不是文件名字母序)。同一 phase 的独立用例继续执行;只有显式 `depends_on` 的失败依赖才写 `not-run` + `blocked_by`。用户说 targeted rerun 时只重跑受影响用例,修复后再 full integration → journey。
|
||||
|
||||
例外:当前条和下一条同属 `run_together` 且该组 `continue_on_fail: true` 时,前一条产品 `fail` 仍跑后一条。`environment-fail` 仍整轮停。
|
||||
|
||||
@@ -253,7 +259,7 @@ python3 <skill-dir>/scripts/catalog.py run-script --root <root> --id <id>
|
||||
|
||||
## 6. 记录与报告
|
||||
|
||||
每条:`id, result, evidence, notes`。`result` 只能是 `pass` / `fail` / `environment-fail` / `skipped` / `not-run`。`skipped` 是主动不跑(retired / pending / 超风险上限 / 未授权 / `assume` 不成立),`not-run` 是没轮到(失败即停后剩下的 / 被前置整组挡住的 / 需人工而无人值守的)。
|
||||
每条:`id, result, evidence, notes`,依赖阻断时另有 `blocked_by`。`result` 只能是 `pass` / `fail` / `environment-fail` / `skipped` / `not-run`。`skipped` 是 standard 中主动不跑(retired / pending / 超风险上限 / 未授权 / `assume` 不成立);`not-run` 是没轮到或 preflight/依赖阻断。失败用例可在 YAML 顶层 `defects`(兼容 `test_issues`)记录 testcase、`issue_type=product|test`、expected/observed、artifact hash、environment、evidence path、reproduction、next step。
|
||||
|
||||
写入 `.pouch/tester/runs/<UTC时间>-<范围>-<随机后缀>.yaml`,可用
|
||||
`generate_run_csv.new_run_id(<范围>)` 生成同名 `runId`。记录包含唯一 `runId`、筛选条件、HOST 是否已设(可以写 HOST 值)、session 是否复用、每个分类的 `status_probe` 生效值与观测结果(`source` / `disabled` 原因 / `hit` / `observed`)、逐条结果。记录文件只创建一次,不覆盖已有文件。立刻用同一快照生成 CSV,不要手改:
|
||||
|
||||
@@ -25,6 +25,7 @@ runs/*.csv 同一次运行的成绩单;generate_run_csv.py 从对
|
||||
| `categories` | `{id, title, status_probe?}` 列表,id 与 `cases/<id小写>.yaml` 对应;列表顺序即 `select` / 执行顺序。`status_probe` 见下 |
|
||||
| `risks` | 从低到高,只能是 `readonly` → `mutating` → `destructive` 的一段,且以 `readonly` 开头。含义见 [levels.md](levels.md) |
|
||||
| `default_max_risk` | 未指定时的运行上限,必须是 `risks` 里的值 |
|
||||
| `execution_profile` | `standard`(默认)或 `isolated-full`。后者只用于隔离可重置环境,保留 risk 语义但不按 risk/authorize/gate 过滤 active 用例;安全边界由 preflight capability 与 cleanup/rollback 契约承担 |
|
||||
| `vars` | 可替换变量,如 `API_BASE: http://${HOST}:8095` |
|
||||
| `artifacts` | 可选的移动产物身份契约。按 `android` / `ios` 声明 `required` 和 `package` / `bundle_id`;每轮文件路径或下载地址由调用方提供,不提交临时产物路径。 |
|
||||
| `authorize` | 风险名 → 环境变量名。该档执行前变量必须为 `true`(`readonly` 不需要) |
|
||||
@@ -36,6 +37,10 @@ runs/*.csv 同一次运行的成绩单;generate_run_csv.py 从对
|
||||
| `client_suites` | 可选的标准套件声明;出现时必须完整包含 `client-smoke`、`client-regression`、`safety`。缺省运行仍按 `tag` 兼容旧目录 |
|
||||
| `integration_suites` | 可选的集成套件声明;标准值为 `api-contract`、`authorization`、`build-contract` |
|
||||
|
||||
`isolated-full` 不得把风险字段改成 `readonly`,也不得把 `AUTHORIZE_ALBUM`、
|
||||
`AUTHORIZE_PASSWORD`、`IME_PINYIN` 等变量当成能力门禁。移动用例必须通过 test-preflight
|
||||
的真实相册 picker、照片权限/测试图片和中文拼音 composition/candidate 检查。
|
||||
|
||||
`local.yaml` 与环境变量覆盖 `HOST` 和授权开关。模板中的 `HOST` 默认是
|
||||
`127.0.0.1`;远程目标必须显式覆盖。查找顺序:环境变量 > `local.yaml` >
|
||||
`catalog.yaml` 的 vars。
|
||||
@@ -91,6 +96,7 @@ terminal;运行结束用 `orca terminal close --terminal <handle>` 关闭本
|
||||
| `expected` | 是 | 怎么过,至少一条 `{kind, value}` |
|
||||
| `maps_to` | 否 | 对人文档的功能项 id |
|
||||
| `assume` | 否 | 额外跳过条件(环境变量表达式)。不要重复 `risk` / `gate` 已覆盖的授权变量,否则 `validate` 报错 |
|
||||
| `depends_on` | 否 | 依赖的 testcase id 列表;依赖 fail/environment-fail/not-run 时本条写 `not-run` 和 `blocked_by`,独立用例继续 |
|
||||
| `setup` | 否 | 人话前置 |
|
||||
| `teardown` | 否 | 跑完回退 |
|
||||
| `notes` | 否 | 备注 |
|
||||
@@ -170,3 +176,24 @@ cleanup:
|
||||
## 判定
|
||||
|
||||
`pass` / `fail` / `environment-fail` / `skipped` / `not-run`
|
||||
|
||||
## 运行失败回流
|
||||
|
||||
run YAML 的 `results` 必须保留每条 testcase 行。失败可在顶层 `defects`(兼容别名
|
||||
`test_issues`)追加:
|
||||
|
||||
```yaml
|
||||
defects:
|
||||
- testcase: TC-CLIENT-001
|
||||
issue_type: product # product | test
|
||||
expected: "候选词可选择"
|
||||
observed: "composition 成功但候选列表为空"
|
||||
artifact_hash: sha256:...
|
||||
environment: "Android emulator API 35 / tester.android"
|
||||
evidence_path: .pouch/tester/evidence/TC-CLIENT-001.png
|
||||
reproduction: "打开相册后输入 nihao"
|
||||
next_step: "开发修复候选词渲染后 targeted rerun"
|
||||
```
|
||||
|
||||
PR 触发的 run 可带 `feedback` 计划:先更新 PR/关联 issue,再通知 dispatcher 重新分配开发;
|
||||
需求/bug 触发则 route 直接为 development。tester 只记录计划,不隐式调用远端写操作。
|
||||
|
||||
Reference in New Issue
Block a user