From b62679dc18d09af93e9b0aba4e08af8014224a86 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sun, 17 May 2026 05:42:52 +0800 Subject: [PATCH] auto-sync: 2026-05-17 05:42:52 --- docs/design/test-plan-v2.6.md | 305 ++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 docs/design/test-plan-v2.6.md diff --git a/docs/design/test-plan-v2.6.md b/docs/design/test-plan-v2.6.md new file mode 100644 index 0000000..7e7cb26 --- /dev/null +++ b/docs/design/test-plan-v2.6.md @@ -0,0 +1,305 @@ +# v2.6 测试计划 + +**版本**: v2.6.0-test-plan +**作者**: 司马懿(质量总监)🗡️ +**日期**: 2026-05-17 +**状态**: F1-F5 已评审,F6-F18 待编码 + +--- + +## 一、测试基础设施 + +### 1.1 当前配置 + +- **框架**: pytest(已有 `tests/` 目录,97 个用例全部通过) +- **Fixture**: `tmp_path`(SQLite 临时数据库)、`TestClient`(FastAPI) +- **Mock 策略**: 目前无 mock,全部用真实 SQLite 内存/临时文件 +- **运行方式**: `python3 -m pytest tests/ -q` + +### 1.2 测试分层 + +| 层级 | 覆盖范围 | 何时执行 | +|------|---------|---------| +| **单元测试** | 每个 F 的内部逻辑 | 每写完一个 F | +| **集成测试** | F1-F14 端到端链路 | F14 完成后 | +| **E2E 验收** | 完整系统含前端 | F18 完成后 | + +### 1.3 测试规范 + +- 每个 F 必须有对应的 `test_*.py`,测试文件与模块同名 +- 测试类按功能分组:`class TestTaskCRUD`、`class TestTransitions` 等 +- P0 测试必须有,P1 测试建议有但不强阻塞 +- 测试必须可重复运行(不依赖外部状态、不依赖时序) +- 新增测试必须在 `tests/` 目录下,不放在 `src/` 内 + +--- + +## 二、F1-F5 单元测试评审(已完成) + +### 现有覆盖情况 + +| F | 测试文件 | 用例数 | P0 覆盖 | 评审 | +|---|---------|--------|---------|------| +| F1 骨架 | `test_main.py` | 10/10 | ✅ 启动、健康端点、配置、Swagger | 通过 | +| F2 黑板 | `test_blackboard.py` | 39/39 | ✅ CRUD、状态机、并发、WAL、事件 | 通过(附 2 条意见) | +| F3 多项目 | `test_registry.py` | 11/11 | ✅ 创建/删除/归档/持久化/黑板的联动 | 通过 | +| F4 CLI | `test_cli.py` | 14/14 | ✅ 8 子命令 + admin + 错误处理 | 通过 | +| F5 API | `test_api.py` | 23/23 | ✅ 全端点 CRUD + 状态码 + SSE 连接 | 通过(附 1 条意见) | + +**总计**: 97/97 通过,质量合格。 + +### 评审意见(F1-F5) + +#### BUG-1 [P1] `/api/daemon/status` 端点重复注册 +- **位置**: `main.py` 第 99-111 行直接定义了 `daemon_status` 端点,同时 `daemon_routes.py` 也定义了同名路由 +- **现象**: pytest 输出 `Duplicate Operation ID daemon_status` warning +- **修复**: 删除 `main.py` 中的 `/api/daemon/status` 端点定义,统一由 `daemon_routes.py` 提供 +- **影响**: 不影响功能,但 Swagger 文档会混乱 + +#### OBS-1 [P2] `operations.py` 的 `_conn()` 每次操作都新建连接 +- **位置**: `operations.py` 全文,每次方法调用 `self._conn()` → `sqlite3.connect()` +- **现状**: 单次操作用完即关,连接不池化 +- **评估**: v2.6 阶段可接受(SQLite WAL + busy_timeout 足够),但如果后续 F6 ticker 30s 轮询 + 多项目并发,建议 F6 阶段引入连接池或 `per-thread` 连接复用 +- **行动**: 不阻塞当前进度,F6 编码时再评估性能 + +#### OBS-2 [P2] `queries.py` 的 `blocked_tasks_with_deps()` 和 `pending_dispatchable()` 存在 SQL 注入风险 +- **位置**: `queries.py` 第 52 行和第 71 行,使用 `f-string` 拼接 SQL +- **现象**: `f"SELECT ... WHERE id IN ({','.join('?' * len(deps))})"` — 虽然 `deps` 来自数据库的 `depends_on` 字段(不是用户输入),且用了参数化占位符,但 `f-string` 拼接 SQL 是坏习惯 +- **评估**: 当前实际安全(因为值都来自参数化 `?`),但风格不好 +- **行动**: 不阻塞,但后续统一改为纯参数化写法 + +--- + +## 三、F6-F18 测试计划(逐模块) + +### F6 Daemon Ticker — `test_ticker.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | tick 循环正常运行 | ✅ | 30s 间隔(测试中加速),不阻塞 event loop | +| T2 | scan_tasks 检测 pending | ✅ | pending → 触发调度 | +| T3 | 依赖推进 | ✅ | blocked → pending(依赖 done 后) | +| T4 | events 写入 | ✅ | 每次 tick 写 `daemon_tick` 事件 | +| T5 | 多项目轮询 | ✅ | tick 遍历所有 active 项目 | +| T6 | tick 异常不中断 | P1 | 单次 tick 抛异常 → 下次 tick 继续 | +| T7 | 手动 tick 端点 | P1 | POST /api/daemon/tick 触发即时 tick | + +### F7 Inbox JSONL Watcher — `test_inbox.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 写入+消费 | ✅ | Agent 写 JSONL → 1s 内 Daemon 读取并处理 | +| T2 | truncate | ✅ | 消费后清空文件 | +| T3 | 并发写入 | ✅ | 多 Agent 同时写不同行 | +| T4 | 损坏行恢复 | P1 | 非法 JSON 行跳过不崩溃 | +| T5 | 空文件处理 | P1 | 空文件不触发处理 | + +### F8 健康检查 — `test_health.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 正常场景 | ✅ | 有变更 → 无告警 | +| T2 | 僵尸检测 | ✅ | 连续 N tick 无变更 → observation 写入 | +| T3 | 恢复场景 | ✅ | 僵尸后有变更 → 告警解除 | +| T4 | 多项目独立检测 | P1 | 项目 A 僵尸不影响项目 B | + +### F9 Agent 调度器 — `test_dispatcher.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 三级决策树 | ✅ | Daemon task → Full task → Sub task 正确分流 | +| T2 | 调度不阻塞 | ✅ | spawn 用 `asyncio.create_subprocess_exec` | +| T3 | 队列满拒绝 | ✅ | active agent 数达上限 → 不调度 | +| T4 | 任务优先级排序 | P1 | 高优先级先调度 | + +### F9 Agent Spawner — `test_spawner.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | spawn 成功 | ✅ | 子进程启动 + session 注册 | +| T2 | 超时处理 | ✅ | 超时后 kill + task_attempt 记录 | +| T3 | spawn 失败 | ✅ | 命令不存在 → task_attempt 记录 spawn_failed | +| T4 | session 清理 | P1 | 子进程结束后 session 归档 | + +### F10 ActiveAgentCounter — `test_counter.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 全局上限 | ✅ | max_global=5 时第 6 个 acquire 失败 | +| T2 | per-agent 串行 | ✅ | 同一 agent 第二个 acquire 排队 | +| T3 | release 恢复 | ✅ | release 后等待中的 acquire 成功 | +| T4 | 并发竞争 | P1 | 多 agent 同时 acquire 不超限 | + +### F11 Bootstrap 拼装 — `test_bootstrap.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 各 role 拼装 | ✅ | 不同 role 得到不同 L0-L3 四层 | +| T2 | token 估算 | ✅ | 拼装结果 < 4096 tokens | +| T3 | 缺失组件降级 | P1 | 某层文件不存在 → 跳过不崩溃 | +| T4 | 模板变量替换 | P1 | `{{task_id}}` 等占位符正确替换 | + +### F12 审查流水线 — `test_review_flow.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 4 级分流 | ✅ | high/standard/low/research 正确路由 | +| T2 | confidence 计算 | ✅ | 分值在 0-1 区间,阈值逻辑正确 | +| T3 | 升级到庞统 | ✅ | confidence < 阈值 → 升级 | +| T4 | 审查通过 → done | ✅ | verdict=approved → 状态变 done | +| T5 | 审查拒绝 → 重新执行 | P1 | verdict=rejected → 回到 working | + +### F13 Guardrail — `test_guardrail.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | L1 assert 通过 | ✅ | 合规产出 → 放行 | +| T2 | L1 assert 失败 | ✅ | 不合规产出 → 拦截 | +| T3 | L2 subagent 触发 | ✅ | 高风险 → 二次确认 | +| T4 | 配置加载 | P1 | `guardrails.yaml` 正确解析 | +| T5 | 误杀恢复 | P1 | L2 确认通过 → 放行 | + +### F14 反驳权 — `test_rebuttal.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 反驳触发 | ✅ | review rejected → 反驳协商开始 | +| T2 | 轮次计数 | ✅ | round 递增正确 | +| T3 | 超轮次升级 | ✅ | 超过 max_rounds → 庞统裁决 | +| T4 | 结果写入 | ✅ | 最终裁决写入 reviews 表 | + +### F15 经验沉淀 — `test_experience.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 一级蒸馏 | ✅ | 任务完成 → experiences 表写入 | +| T2 | tag 匹配 | ✅ | 相似 tag 的经验可被查询到 | +| T3 | 二级触发 | P1 | N 条同类经验 → Skill 草稿生成 | +| T4 | 过期清理 | P1 | deprecated 经验不被查询 | + +### F16 Skill 体系 — `test_skill_loader.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 加载 + 验证 | ✅ | 四要素完整才加载 | +| T2 | per-project 覆盖 | ✅ | 项目级 Skill 覆盖全局 Skill | +| T3 | 缺要素拒绝 | P1 | 缺少 name/description/triggers/actions → 拒绝 | +| T4 | 版本管理 | P1 | 同名 Skill 版本号正确比较 | + +### F17 SSE + Hook — `test_sse.py` / `test_hooks.py` + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | SSE 连接 | ✅ | 客户端连接 → 收到初始事件 | +| T2 | SSE 4 级推送 | ✅ | task/agent/daemon/system 四级 | +| T3 | 断线重连 | P1 | 断线后重连 → 收到后续事件 | +| T4 | 降级轮询 | P1 | SSE 不可用 → 轮询兜底 | +| T5 | Hook 触发 | ✅ | 3 个触发点正确执行 | +| T6 | Hook 过滤 | P1 | 条件不满足 → 不触发 | + +### F18 前端 Dashboard — `test_frontend.py`(E2E) + +| # | 测试用例 | P0 | 验证点 | +|---|---------|-----|-------| +| T1 | 页面渲染 | ✅ | 5 个页面均可加载 | +| T2 | API 集成 | ✅ | 页面操作 → API 调用正确 | +| T3 | SSE 实时更新 | ✅ | 后端事件 → 前端 UI 更新 | +| T4 | 项目切换 | ✅ | 切换项目 → 数据刷新 | + +--- + +## 四、集成测试计划(F14 完成后) + +### 端到端链路测试 + +``` +用户提需求 → 庞统规划 → 任务写入黑板 → Agent 执行 → +Guardrail 检查 → 审查流水线 → 反驳协商 → 完成 → 经验沉淀 +``` + +| # | 场景 | 关键验证 | +|---|------|---------| +| I1 | 正常流程(happy path) | 全链路无阻断,最终 done | +| I2 | 依赖链 | A→B→C,A done 后 B 自动 pending,B done 后 C 自动 pending | +| I3 | 审查拒绝 → 反驳 → 通过 | review rejected → rebuttal → verdict 翻转 | +| I4 | 审查拒绝 → 反驳 → 超轮次 → 庞统裁决 | max_rounds 后升级 | +| I5 | Guardrail 拦截 → L2 确认 → 放行 | L1 fail → L2 confirm → proceed | +| I6 | Agent 僵尸检测 | 无 heartbeat → observation → reclaim | +| I7 | 多项目并行 | 项目 A/B 同时运行,互不干扰 | +| I8 | 失败重试 | failed → pending(retry_count +1)→ 再次执行 | + +### 集成测试基础设施 + +```python +# conftest.py 需要的 fixture +@pytest.fixture +def full_stack(tmp_path): + """完整系统:FastAPI + Ticker + Dispatcher + Spawner(mock)""" + ... + +@pytest.fixture +def mock_spawner(): + """Mock spawner,模拟 Agent 执行""" + ... +``` + +--- + +## 五、E2E 验收场景(F18 完成后) + +| # | 场景 | 验收标准 | +|---|------|---------| +| E1 | 创建项目 → 提交任务 → 查看任务板 | Dashboard 实时更新 | +| E2 | 全局监控页 | 所有项目状态汇总、活跃 Agent 数、最近事件 | +| E3 | 产物仓库页 | 任务产出物可浏览、可下载 | +| E4 | 系统配置页 | 运行时配置可查看、Skill 列表可管理 | +| E5 | AI 简报页 | 项目级 AI 总结可生成 | +| E6 | SSE 实时 | 所有页面操作后 SSE 实时反映 | + +--- + +## 六、测试通过标准 + +### 每个 F 的单元测试通过标准 + +1. **全部 P0 用例通过**(硬性要求) +2. **P1 用例通过率 ≥ 80%**(可协商) +3. **无 crash / 无未捕获异常** +4. **测试可重复运行**(跑 3 次结果一致) + +### 集成测试通过标准 + +1. **I1-I8 全部场景通过** +2. **无死锁、无资源泄漏** +3. **并发测试无数据竞争** + +### E2E 验收标准 + +1. **E1-E6 全部场景通过** +2. **前端无 console error** +3. **SSE 延迟 < 2s** + +--- + +## 七、进度追踪 + +| F | 测试计划 | 用例设计 | 编码 | 执行 | 评审 | +|---|---------|---------|------|------|------| +| F1 | ✅ | ✅ 10 | ✅ | ✅ 10/10 | ✅ 通过 | +| F2 | ✅ | ✅ 39 | ✅ | ✅ 39/39 | ✅ 通过(附 2 条意见) | +| F3 | ✅ | ✅ 11 | ✅ | ✅ 11/11 | ✅ 通过 | +| F4 | ✅ | ✅ 14 | ✅ | ✅ 14/14 | ✅ 通过 | +| F5 | ✅ | ✅ 23 | ✅ | ✅ 23/23 | ✅ 通过(附 1 条意见) | +| F6 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F7 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F8 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F9 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F10 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F11 | ✅ 本文档 | ⬜ 本文档 | ⬜ | — | — | +| F12 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F13 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F14 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F15 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F16 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F17 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — | +| F18 | ✅ 本文档 | ⬜ 待设计 | ⬜ | — | — |