测试 fixtures¶
tests/fixtures/ 存放测试套件的确定性输入数据:代表性线程的合成原始 API 抓取(raw_entries.json / raw_blocks.json / thread.json),外加作为 golden 快照随仓库提交的渲染产物(conversation.md + turns/)。任何渲染层回归都会破坏与 golden 的逐字节比对。
什么是 fixture¶
每个 fixture 是一个目录,含原始抓取外加一棵 golden/ 树:
| 路径 | 作用 |
|---|---|
raw_entries.json |
原始 API 抓取:线程的 entries |
raw_blocks.json |
原始 API 抓取:workflow blocks(该模式无 workflow 时缺失,如 search_demo、study_demo) |
thread.json |
归档的线程元数据 |
golden/conversation.md + golden/turns/turn_*.md |
随仓库提交的渲染产物,逐字节比对 |
所有 fixtures 均为合成且确定性的数据:
- 账户身份——用户名 / 显示名 / 邮箱 / user_id 均为共享占位符(
alice/bob,Alice Example/Bob Example,alice@example.com/bob@example.com,00000000-0000-4000-8000-0000000000aa/00000000-0000-4000-8000-0000000000bb);BOT 空间为00000000-0000-4000-8000-0000000000b0/bot-EXAMPLE;read_write_token是固定占位符00000000-0000-4000-8000-0000000000ff。 - 标识符映射——thread / entry / asset 的 UUID 为 uuid5 派生(固定 namespace + 原值)的合成值,带
5cbeef00前缀标记,全仓库一致:相同输入恒映射到相同输出,保留交叉引用。toolu_运行 id 同样变为带5crub0标记的定长合成 id。 - 用户文本——查询 / 标题 / 空间名 / 问答负载 / 文件句柄路径均为通用合成文本;CloudFront/S3 签名 URL 的签名查询串已剥离。
以下通用占位字符串是测试语义标记,属有意保留:已推送、All done、Add analysis tool shell wrapper、这是子代理的最终结论段落、Answer skipped.。
命名¶
fixture 目录只使用描述性名称——标识模式或缺陷场景,绝不携带任何线程标识符:
- 完整线程 fixtures:
<mode>_demo(如search_demo、council_demo)。 - 裁剪缺陷场景:
scenario_<defect-scenario>。
清单¶
完整线程快照(golden = 渲染产物,逐字节)¶
| fixture | 覆盖 |
|---|---|
search_demo |
search,单轮;R 代码围栏 / 行内代码 |
deep_research_demo |
deep-research;raw 含 \(,golden 含 26× $$ —— 端到端数学定界符转换 |
computer_demo |
computer,多轮(7 轮)workflow 渲染 |
council_demo |
council 模型委员会渲染(raw 抓取约 1.0 MB) |
study_demo |
study(通用学习问题) |
裁剪场景 fixtures(单 entry 裁剪;golden = 对应 turn 文件,turn 重新编号)¶
特定缺陷场景裁剪为单个 entry(保留 thread_metadata,清空 background_entries——已核实被裁 entry 的 workflow block 均不携带 sub-agent 步骤依赖,因此裁剪不改变渲染路径)。
| fixture | 覆盖 |
|---|---|
scenario_computer_answer_fallback |
computer answer 回退:当普通 FINAL 路径被守卫跳过(仅剩 workflow_snapshots)时,从模式化 workflow_block 的 variant=answer TEXT 中还原 answer(parsers.wf_block_answer) |
scenario_subagent_fallback |
sub-agent 回退:无 background 匹配时,渲染 sub-agent 标题 + 该步骤自身的条目(sub-agent 摘要不会丢失) |
scenario_user_response |
WORKFLOW_ITEM_USER_RESPONSE 问答渲染(4 问 / 4 答);query 为空的 turn |
scenario_subagent_stub |
subagent_result 残桩 turn:无锚点 background sub-agent 的 10 秒时间窗关联 |
scenario_workflow_item_nested |
嵌套 WORKFLOW_ITEM_WORKFLOW 折叠块渲染 |
中断 / 取消场景(多 entry + background_entries 裁剪,关系保持完整)¶
中断语义依赖 entry ↔ background 的归属关系,因此不能清空 background_entries;裁剪采用 uuid 子集(锚定 / 残桩时间窗 / 附录三类载荷各至少保留一个)。
| fixture | 覆盖 |
|---|---|
scenario_limit_interrupted |
额度上限中断(locked_reason=spending_limit_exceeded + AWAITING):workflow 头部 / sub-agent 标题 / 残桩 turn 摘要上的 ⏸ 标注;归属瀑布第 ③ 级 —— 未消费的 38 步载荷落入 conversation.md 附录;锚定 / 残桩时间窗载荷不进入附录,绝不重复渲染 |
scenario_canceled |
WORKFLOW_CANCELED:workflow 头部 ⛔ 标注 |
维护 fixtures¶
tests/scrub_fixtures.py 是确定性维护工具(tests/scrub_fixtures.py:529):位置式文本替换、标识符重映射与 golden 快照重生成。幂等,可安全重复运行。
uv run python tests/scrub_fixtures.py # 应用替换并重生成 golden
uv run python tests/scrub_fixtures.py --check # 只跑门禁,不写文件
- golden 重生成(
tests/scrub_fixtures.py:500-524)——每个 fixture 的原始 JSON 在临时目录中经与生产及测试套件相同的离线rerender路径重渲;golden/逐字节一致地刷新,轮数不一致会直接报错中止。 - 替换来源位于仓库之外——账户身份值运行时读自用户级配置(
~/.config/pplx-export/config.toml,经pplx_export.config;见配置);内容类替换对读自本地覆盖映射tests/scrub_pairs.local.json——不入库;随仓库提交的模板是tests/scrub_pairs.example.json(pairs:按序应用的[旧值, 新值]条目;gate:零容忍子串)。 - 确定性重映射——其余 UUID → 带
5cbeef00标记的 uuid5 合成值,toolu_id → 带5crub0标记的定长合成 id,read_write_token→ 固定占位值;已带标记前缀的值跳过(幂等)。作用域:位置式对只作用于所属 fixture 目录;本地内容对与身份 / token / UUID / toolu_ 映射全局生效。 --check门禁模式——扫描tests/fixtures/下每个文件,查找全部替换来源、门禁子串以及本地绝对路径 / 签名 URL 的残留,命中即以非零码退出,且不写任何文件。重复运行时,新值已存在的映射视为已应用。
改了 fixture 的原始 JSON 或渲染器之后运行它;提交 fixture 变更前运行 --check。在测试套件内部,tests/conftest.py::render_fixture 使用同一条离线重渲路径,因此快照测试始终用渲染器的最新输出对比已提交的 golden。