D · 测试与演进
测试目录不只是质量工具,也是架构证据:它告诉我们哪些边界被认为需要独立验证、哪些行为跨平台、哪些历史漏洞必须永久回归。
快照中的测试规模
pytest.ini 把 tests 与 tests-unit 都设为 testpaths,并定义:
inferencemarker:需要真实推理条件的测试;executionmarker:完整执行引擎测试;- 默认
-s保留输出。
两个测试世界
tests-unit/
强调小范围、可替换依赖和边界逻辑:
- app managers 与 migrations;
- Assets query/service/API;
- V3 input/video 类型;
- folder paths;
- schema type validation;
- server cache control、WebSocket flags;
- 用户目录;
- 安全回归;
- feature flags 与工具函数。
tests/
强调系统行为:
- execution graph;
- async nodes;
- jobs/cancel;
- preview method;
- progress isolation;
- public API;
- inference;
- output quality comparison;
- asset seeder。
Execution 测试使用专门节点包
tests/execution/testing_nodes/testing-pack/ 内有:
stubs.py 可预测基础节点
conditions.py 条件与 lazy 行为
flow_control.py expand / blocker / 图控制
async_test_nodes.py 异步节点
api_test_nodes.py public API 边界
specific_tests.py 针对回归的节点
tools.py / util.py 测试辅助这是一种很好的 runtime 测试策略:不要用巨大真实模型才能验证 scheduler;构造“行为可控的微型节点”,让 cache hit、列表映射、PENDING、环和错误都可确定重现。
执行器需要覆盖的不变量
| 能力 | 最重要的断言 |
|---|---|
| output-driven | 孤立节点不执行,目标闭包执行 |
| cache | 输入/祖先未变命中,任一语义依赖变更失效 |
| list mapping | 短列表重复最后值,OUTPUT_IS_LIST 正确展平 |
| lazy | 未选分支不执行,请求输入后节点能恢复 |
| async | 只提交一次,完成/异常能解除 external block |
| expand | 临时 ID 唯一、父节点恢复、subcache 隔离 |
| blocker | 不当异常处理,消息与静默传播区分 |
| error | node ID、display/real ID、inputs 和 traceback 准确 |
| progress | 并发/连续 Prompt 上下文不串线 |
| cancel | waiting 原子删除、running 协作中断 |
安全回归测试是一张威胁地图
tests-unit/security_test/ 的文件名直接记录 GHSA 修复面:
| 测试 | 保护什么 |
|---|---|
...preview_traversal.py | preview/view 路径逃逸 |
...annotated_traversal.py | [input]/[output] annotation 穿越与 symlink |
...userdata_xss.py | 用户文件同源脚本执行 |
...dangerous_content_types.py | MIME 变体、参数、XML 家族 |
...inline_svg_image_dest.py | SVG <img> 特例与导航/缓存边界 |
这类测试不应在重构时合并成一个“危险文件被拒绝”的泛化用例。每个变体代表不同绕过手法,细粒度名字本身是安全知识。
Assets 测试为何很多
Assets 需要同时维护数据库与真实文件系统事实:
- 内容 hash 去重;
- reference owner/name/path;
- cursor/keyset pagination;
- metadata filter 与 tag refine;
- missing / prune / resync;
- upload/download;
- seeder pause/cancel;
- output prompt/job ID 关联;
- loader path 映射。
这是一类典型“双写/索引”系统,最危险的是中断中间态和重复操作。测试数量反映的不是 UI 复杂,而是一致性状态多。
模型测试分层
model detection unit
用 key/shape 或最小 state dict 验证模型配置选择,不必跑完整采样。
dtype / quant unit
验证 mixed precision、设备条件和转换规则,避免用“能出图”掩盖隐式高精度 fallback。
inference marker
真实构造与 forward,成本高、环境依赖强,应与普通 PR 单元测试区分。
quality comparison
输出数值/图像质量回归与功能正确性不同:一次重构可能不 crash,却改变结果分布。比较测试承接这一层。
CI 划分
Execution Tests
Ubuntu、Windows、macOS,Python 3.12,安装 CPU torch 与项目/测试依赖,执行:
python -m pytest tests/execution -v --skip-timing-checks跳过 timing check 避免共享 CI 机器的调度噪声导致功能测试不稳定。
Unit Tests
同样三平台,执行全部 tests-unit。跨平台矩阵对 folder paths、MIME、设备 fallback 和文件 locking 特别重要。
本快照两个 workflow job 都标记 continue-on-error: true。这意味着它们提供可见信号,但单独看 workflow 不能假设是强制合并门禁;还要查看聚合 CI / 仓库保护规则。
其他工作流
- Ruff;
- launch/build 测试;
- OpenAPI lint;
- line endings;
- release/package 的多平台工作流;
- API stubs 更新。
从测试反推模块边界
一个改动应落在最低足够层:改链接类型验证先写 unit;改 async PENDING 写 execution;改 attention 数值再加 inference/quality。所有问题都用完整 GPU workflow 测,会慢且难定位。
读源码时怎样用测试
- 先找到目标函数的直接 unit test,确认显式契约。
- 再搜测试节点,观察运行时如何驱动该能力。
- 搜 bug/GHSA 命名回归,理解代码中看似多余的 guard。
- 看跨平台 workflow,区分 POSIX 假设与公开行为。
- 找不到测试时,把源码注释和调用点视为较弱证据,不擅自补成稳定承诺。
扩展作者的最小测试组合
schema registration test
pure execute unit test
list/batch shape test
cache fingerprint test
external error/redaction test
path traversal test (if files)
async cancel/idempotency test (if async)
expand graph + cache test (if dynamic)
one small end-to-end Prompt test可迁移的设计方法
- 为复杂运行时建立专用微型测试插件,不让模型成本绑架调度测试。
- 安全漏洞按攻击变体保留命名回归,代码 guard 才不容易被“简化”掉。
- 数值正确、系统正确与输出质量分层测试。
- 跨平台文件/设备策略必须在 CI 矩阵出现,而不是靠条件分支自证。
- CI 的“运行了”与“阻止合并”是两件事,审核时同时看 workflow 和 branch protection。