Skip to content

Commit d578ff1

Browse files
committed
feat(testing): add test methodology and report tooling
1 parent 8d13857 commit d578ff1

20 files changed

Lines changed: 2716 additions & 0 deletions

File tree

REUSE.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ path = "**/src/generated/*"
203203
SPDX-FileCopyrightText = "NONE"
204204
SPDX-License-Identifier = "CC0-1.0"
205205

206+
[[annotations]]
207+
path = "tools/dstack-test/tests/fixtures/**"
208+
SPDX-FileCopyrightText = "NONE"
209+
SPDX-License-Identifier = "CC0-1.0"
210+
206211
[[annotations]]
207212
path = "dstack/gateway/assets/*"
208213
SPDX-FileCopyrightText = "NONE"
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<!-- SPDX-FileCopyrightText: © 2026 Phala Network <dstack@phala.network> -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
4+
<a id="dstack-test-methodology"></a>
5+
# dstack 测试方法
6+
7+
本文规定 dstack 版本测试从需求分析、风险建模、用例设计、环境执行、证据采集到发布判定的统一方法。具体用例格式见[测试用例编写规范](test-case-authoring-spec.md#dstack-test-case-authoring-spec),执行产物格式见[测试报告输出规范](test-report-output-spec.md#dstack-test-report-output-spec)
8+
9+
<a id="methodology-goals"></a>
10+
## 1. 目标
11+
12+
测试应当提供可重复、可审计且可追踪的发布证据,而不只是证明某个脚本曾经退出为零。任一结论都应能从需求或风险追踪到用例、步骤、命令原文、观察结果和附件。
13+
14+
测试工作的完成条件是:
15+
16+
1. 版本变化、产品需求和主要风险均有明确测试覆盖;
17+
2. 测试规格可由不了解实现细节的执行者独立复现;
18+
3. 每一步实际执行的命令、退出码、标准输出和标准错误均保存;
19+
4. 模拟测试和真实硬件测试分别报告,不能互相替代;
20+
5. 汇总状态可由工具从原子结果重新计算;
21+
6. 报告中的引用、附件摘要和统计均可机器校验。
22+
23+
<a id="methodology-artifacts"></a>
24+
## 2. 测试资料分层
25+
26+
测试资料分为四类,禁止混写:
27+
28+
| 资料 | 作用 | 是否随执行变化 |
29+
|---|---|---|
30+
| 测试说明 `README.md` | 范围、环境配置、公共前置条件、执行与清理方法 ||
31+
| 测试索引 `index.json` | 章、节、用例顺序及机器可读引用 ||
32+
| 用例规格 `case.md` | 单条用例的目标、前置条件、数据、步骤和预期结果 ||
33+
| 执行结果 `results/<run-id>/` | 实际版本、命令证据、观察结果、附件和状态 ||
34+
35+
测试规格是只读输入。执行器只能在 `results/` 下创建当前 run 的产物,不得根据执行结果反向修改预期结果。
36+
37+
<a id="methodology-organization"></a>
38+
## 3. 组织结构
39+
40+
测试计划固定使用“章/节/用例”三个层级。每条用例必须拥有独立目录,便于附带 fixture、脚本和多次执行结果。
41+
42+
```text
43+
<plan>/
44+
├── index.json
45+
├── README.md
46+
├── schemas/
47+
├── results/<run-id>/run.json
48+
└── <chapter>/
49+
└── <section>/
50+
└── <case-id>/
51+
├── case.md
52+
├── fixtures/ # 可选
53+
├── scripts/ # 可选
54+
└── results/<run-id>/
55+
```
56+
57+
目录名建议使用两位数字前缀维持人工浏览顺序;权威执行顺序仍来自 `index.json`,执行器不得通过文件名猜测顺序。
58+
59+
<a id="methodology-input-analysis"></a>
60+
## 4. 测试输入分析
61+
62+
在编写用例前,测试负责人应收集并冻结:
63+
64+
- 上一个发布版本及本次候选 revision;
65+
- change log、PR、schema、RPC 和配置变化;
66+
- 产品需求及用户场景;
67+
- 安全不变量和信任边界;
68+
- 已知缺陷、迁移约束和运维方式;
69+
- 可用的真实硬件、模拟器与外部服务。
70+
71+
每项变化至少回答:谁使用它、正常行为是什么、错误输入如何处理、升级时如何兼容、失败后如何恢复、会影响哪些旧功能。
72+
73+
<a id="methodology-traceability"></a>
74+
## 5. 追踪与覆盖
75+
76+
每条用例应引用至少一个需求或风险。推荐维护以下关系:
77+
78+
```text
79+
Change / Requirement / Risk
80+
81+
Test case
82+
83+
Step
84+
85+
Command and output
86+
87+
Assertion/result
88+
```
89+
90+
覆盖审计至少包含:
91+
92+
1. 新增和改变的功能;
93+
2. 受影响功能的回归;
94+
3. 新旧组件组合兼容;
95+
4. 配置和 API 的合法、边界及错误输入;
96+
5. 有状态组件的创建、运行、停止、重启、升级、回滚和恢复;
97+
6. 安全策略的允许、拒绝及恢复;
98+
7. 并发、隔离、幂等和重试;
99+
8. 资源耗尽、依赖不可用和网络故障;
100+
9. 可观测性、错误信息及审计记录。
101+
102+
覆盖数量不是质量指标。一个包含多个独立断言的大用例应拆为若干原子用例,否则失败无法定位,结果也无法准确统计。
103+
104+
<a id="methodology-environments"></a>
105+
## 6. 环境等级
106+
107+
执行报告必须标记环境等级:
108+
109+
| 等级 | 说明 |
110+
|---|---|
111+
| `UNIT` | 单进程或模块测试 |
112+
| `INTEGRATION` | 多组件集成,但不使用模拟硬件证据代替真实平台 |
113+
| `SIMULATED` | mock attestation、no-TEE、swtpm 等模拟环境 |
114+
| `REAL_SGX` | 真实 SGX enclave |
115+
| `REAL_TDX` | 真实 TDX CVM |
116+
| `REAL_PLATFORM` | 指定 NVIDIA、GCP、AWS、SEV-SNP 等真实平台 |
117+
118+
用例规格必须声明最低环境。若只在较低等级执行,原用例保持 `NOT_RUN``BLOCKED`,模拟结果应记录在单独用例中。
119+
120+
<a id="methodology-status"></a>
121+
## 7. 状态与判定
122+
123+
状态枚举固定为:
124+
125+
- `PASS`:所有步骤的实际结果完全满足预期;
126+
- `FAIL`:至少一步实际结果不完全满足预期;
127+
- `BLOCKED`:外部环境或前置条件阻止被测行为开始;
128+
- `NOT_RUN`:尚未执行;
129+
- `SKIPPED`:预先定义的适用条件不成立。
130+
131+
单个用例不使用 `PARTIAL`。若一部分断言通过、一部分未执行,应拆分用例或将该用例判为非 `PASS`。顶层汇总必须由用例结果计算,不能手工覆盖。
132+
133+
<a id="methodology-execution"></a>
134+
## 8. 标准执行流程
135+
136+
AI或人工执行器应按以下顺序工作:
137+
138+
1. 阅读顶层 `README.md`
139+
2. 读取并校验 `index.json`、schema、路径、锚点和引用;
140+
3. 创建唯一 `run_id`,记录执行器、公共版本和环境;
141+
4. 按索引顺序逐章、逐节、逐用例读取 `case.md`
142+
5. 为每条用例启动独立AI会话,验证前置条件并执行各步骤;
143+
6. runner将Agent原生JSONL事件流直接保存为`session.jsonl`,其中包含实际tool call、命令和原始输出;
144+
7. 将观察结果与预期逐项比较,结束前原子写入浅层`result.json`
145+
8. 执行用例后置条件,记录未能清理的资源;
146+
9. 全部完成后重新校验会话、结果、附件摘要、引用和统计;
147+
10. 生成顶层`run.json``SHA256SUMS`,再打包上传或渲染HTML。
148+
149+
AI执行器必须记录实际提供方、产品和模型名称;无法从运行环境确认模型时填写 `unknown`,不得猜测。
150+
151+
<a id="methodology-evidence"></a>
152+
## 9. 证据原则
153+
154+
每一步至少包含一条实际执行的命令证据。命令和输出由Agent原生
155+
`session.jsonl`保存,不要求AI再次复制或转义。会话应包含:
156+
157+
- 未经改写的命令字符串和工作目录;
158+
- 已脱敏的环境变量;
159+
- UTC开始、结束时间和退出码;
160+
- stdout、stderr原文;
161+
- 从原文提取的结构化 observed 值;
162+
- 截图、日志或二进制捕获附件及 SHA-256。
163+
164+
额外的截图、长日志或二进制捕获写入`artifacts/`并由`result.json`引用;
165+
`result.json`只保存逐步观察总结,不嵌入大段输出。密钥、token、私钥和用户数据
166+
不得进入会话或附件;脱敏必须保留字段存在性和数据形状,且在报告中声明。
167+
168+
<a id="methodology-versioning"></a>
169+
## 10. 版本与环境记录
170+
171+
公共被测版本只在 run 顶层记录一次,包括 Git revision、binary SHA-256、container digest 和 guest image digest。单个用例只在使用旧版或特殊构件时设置 `version_overrides`
172+
173+
环境记录至少包括:主机标识、内核、CPU架构、TEE能力、模拟标志、关键外部服务及配置摘要。路径和主机名如涉及隐私,可使用稳定别名,但必须足以复现拓扑。
174+
175+
<a id="methodology-release-decision"></a>
176+
## 11. 发布判定
177+
178+
发布结论应直接引用未通过的 P0/P1 用例及未覆盖需求。以下情况不得表述为“全量通过”:
179+
180+
- P0 用例为 `FAIL``BLOCKED``NOT_RUN`
181+
- 真实硬件要求仅由模拟测试覆盖;
182+
- 关键附件缺失或摘要不匹配;
183+
- 结果引用失效;
184+
- 执行偏离规格且未记录 deviation;
185+
- 公共版本未固定到可追溯 digest。
186+
187+
<a id="methodology-rendering"></a>
188+
## 12. 打包和展示
189+
190+
规范 Plan目录是平台和本地渲染器的唯一输入。推荐命令:
191+
192+
```bash
193+
dstack-test render \
194+
--plan path/to/plan \
195+
--run-id run-20260723-001 \
196+
--output report.html
197+
```
198+
199+
渲染前必须完成结构、引用、状态、统计和附件摘要校验。生成的 HTML应内联样式、脚本、JSON、文本、图片和可下载附件,不依赖网络资源。

0 commit comments

Comments
 (0)