diff --git a/docs/audit/changes/2026-05-04__wave1_day4_test_coverage.md b/docs/audit/changes/2026-05-04__wave1_day4_test_coverage.md new file mode 100644 index 0000000..62c8141 --- /dev/null +++ b/docs/audit/changes/2026-05-04__wave1_day4_test_coverage.md @@ -0,0 +1,109 @@ +# Wave 1 Day 4 — 测试补齐 + 现状盘点 + +| 字段 | 值 | +|---|---| +| 日期 | 2026-05-04 | +| Wave | 1 / Day 4 | +| 范围 | 对 Day 1-3 改动跑测试 + 修受影响的现有测试 + 补 W1-T4 audience 单测 | +| 测试结果 | jwt 15/15 + db_viewer_properties 2/2 + ETL 4 视图 smoke PASS ✅ | + +## 一、测试现状盘点 + +### 1.1 受 Wave 1 改动影响的测试 + +| 测试文件 | 通过/总数 | 状态 | +|---|---|---| +| `tests/test_auth_jwt.py` | **15/15** | ✅(加 7 个 W1-T4 audience 用例) | +| `tests/test_db_viewer_properties.py` | **2/2** | ✅(修 `_WRITE_KEYWORDS` → `_DENY_KEYWORDS`) | +| `tests/test_db_viewer_router.py` | 0/26 | ❌ **pre-existing fail**(W1-T5 改动前就 fail) | + +### 1.2 ETL smoke 测试(本次新增,验证 W1-T2) + +测试库 4 视图查询字段结构与 base_dws_task / base_index_task 期望一致: + +``` +v_cfg_index_parameters : 27 rows cols=['param_name', 'param_value'] +v_cfg_performance_tier : 5 rows cols=['tier_id', 'tier_code', 'tier_name', ...] +v_cfg_assistant_level_price : 5 rows cols=['price_id', 'level_code', ...] +v_cfg_bonus_rules : 3 rows cols=['rule_id', 'rule_type', ...] +``` + +## 二、Day 4 测试改动 + +### 2.1 修复 `test_db_viewer_properties.py` + +W1-T5 把 `_WRITE_KEYWORDS` 重命名为 `_DENY_KEYWORDS`(更准确反映黑名单语义), +导致 property test import 失败。修复:全文替换。 + +### 2.2 新增 `TestAudienceClaim`(7 用例) + +W1-T4 改造 jwt.py 加 `audience` 参数,补单测覆盖: + +| 用例 | 验证点 | +|---|---| +| `test_admin_token_includes_aud` | sign 端写入 aud="admin" | +| `test_miniapp_token_includes_aud` | sign 端写入 aud="miniapp" | +| `test_no_audience_token_compatible` | 旧 token(无 aud)不强制校验时仍通过 | +| `test_audience_mismatch_rejected` | aud 不匹配时 raise(jose 行为) | +| `test_audience_match_accepted` | aud 匹配时正常 | +| `test_token_pair_propagates_audience` | create_token_pair 透传 audience 到 access + refresh | +| `test_no_aud_token_silent_pass_with_audience` | jose 实际行为:无 aud + 传 audience → silent pass(灰度兼容) | + +### 2.3 jose 行为发现(灰度有利) + +`python-jose` 的 `jwt.decode(audience='X')`: +- ✅ 校验 token 中**已有**的 aud(不匹配抛 JWTClaimsError) +- ✅ token **不含** aud 时 **silent pass**(不抛) + +这是 W1-T4 灰度的有利特性 — 旧 token 不破。Wave 2 切强制校验时改用 +`options={'require_aud': True}` 或自行判断 `payload.get('aud')`。 + +## 三、Pre-existing 测试问题(Wave 5 范围,不在本 Wave 修) + +`tests/test_db_viewer_router.py` 26 个 fail 与 W1-T5 改动无关: + +```bash +# 验证: 切到 W1-T5 改动前(commit caf179a)同样 fail +git stash +pytest tests/test_db_viewer_router.py::TestExecuteQuery::test_blocks_write_operations +# → 15 failed +git stash pop +``` + +**原因(从 KeyError 'detail' 推测)**: +- 测试期望 FastAPI HTTPException 标准结构 `resp.json()["detail"]` +- 实际 response 不含 `detail` 字段 → ResponseWrapperMiddleware 可能也包装了 4xx 响应 +- 或 client fixture 与中间件链路不一致 + +**处理建议**:留 Wave 5 文档收尾时统一修(超出 Wave 1 范围)。 + +## 四、未跑的测试(W1-T8 走查覆盖) + +| 改动 | 工程层验证 | 成果层验证(W1-T8 §14)| +|---|---|---| +| W1-T3 fdw_etl 4 处残留 | ✅ grep 0 处 + 视图存在 | tenant-admin 用户审核 / Excel 上传 / 维客线索实际数据返回 | +| W1-T4 JWT aud sign | ✅ 7 单测 | admin token 与 miniapp token 跨端调用拒绝 | +| W1-T5 DBViewer 白名单 | ✅ 内联 15/15 + property 2/2 | admin-web /logs/db-viewer 实测 ALTER/CREATE 拒绝 | +| W1-T1 board-finance | ✅ tsc 编译 | sandbox 切到 2026-03-01 / 03-15 看预估提示是否正确 | +| W1-T2 cfg_* 视图 | ✅ 测试库 SQL 4 视图 PASS + smoke | sandbox 切日期后 SPI 算法实跑参数符合切片 | + +成果层走查留 W1-T8。 + +## 五、commit 建议 + +``` +test(backend): Day 4 修受影响测试 + 补 W1-T4 audience 7 用例 + +- 修 test_db_viewer_properties.py: _WRITE_KEYWORDS → _DENY_KEYWORDS (W1-T5 重命名) +- 新增 TestAudienceClaim 7 用例覆盖 W1-T4 audience 参数: + · admin/miniapp token 写入 aud + · 旧 token (无 aud) 兼容 + · aud 匹配/不匹配/silent pass(灰度) + · token_pair 透传 audience +- 跑通 jwt 15/15 + db_viewer_properties 2/2 + ETL 4 视图 smoke + +pre-existing fail (test_db_viewer_router.py 26 个) 与 W1-T5 无关, +留 Wave 5 文档收尾时统一修。 + +参考: docs/audit/changes/2026-05-04__wave1_day4_test_coverage.md +```