from __future__ import annotations import json import re from pathlib import Path ROOT = Path(__file__).resolve().parents[1] UAT_CASES = ROOT / "docs/acceptance/WP14_UAT_CASES.json" UAT_REPORT = ROOT / "docs/acceptance/WP14_UAT_PLAN_AND_REPORT.md" DEFECT_REGISTER = ROOT / "docs/acceptance/WP14_DEFECT_REGISTER.md" USER_GUIDE = ROOT / "docs/guides/DATAOPS_PHASE1_USER_OPERATION_GUIDE.md" OPERATIONS_HANDOVER = ROOT / "docs/runbooks/DATAOPS_PHASE1_OPERATIONS_HANDOVER.md" PHASE2_BACKLOG = ROOT / "docs/roadmap/DATAOPS_PHASE2_BACKLOG.md" EVIDENCE = ROOT / "docs/validation/WP14_UAT_HANDOVER_EVIDENCE.md" REQUEST_CLIENT = ROOT / "frontend/src/utils/request.js" DEVELOPMENT_CENTER = ( ROOT / "frontend/src/views/dataGovernance/development/index.vue" ) DELIVERABLES = ( UAT_CASES, UAT_REPORT, DEFECT_REGISTER, USER_GUIDE, OPERATIONS_HANDOVER, PHASE2_BACKLOG, EVIDENCE, ) def _read(path: Path) -> str: return path.read_text(encoding="utf-8") def _cases() -> list[dict]: payload = json.loads(_read(UAT_CASES)) assert payload["work_package"] == "WP-14" assert payload["schema_version"] == "1.0" return payload["cases"] def test_wp14_deliverables_exist() -> None: missing = [str(path.relative_to(ROOT)) for path in DELIVERABLES if not path.is_file()] assert not missing, f"WP14 交付物缺失: {missing}" def test_wp14_uat_cases_cover_roles_modules_and_acceptance_boundaries() -> None: cases = _cases() assert len(cases) >= 16 required_fields = { "id", "module_ids", "title", "actor", "acceptance_level", "preconditions", "steps", "expected", "evidence", "result", "notes", } for case in cases: assert required_fields <= case.keys(), case.get("id") assert case["id"].startswith("WP14-UAT-") assert case["actor"] in {"admin", "editor", "viewer", "enterprise_acceptance"} assert case["acceptance_level"] in {"LOCAL_ENGINEERING", "ENTERPRISE_FORMAL"} assert case["result"] in {"PASS_LOCAL", "FAIL", "BLOCKED_EXTERNAL", "NOT_RUN"} assert case["module_ids"] assert case["preconditions"] assert len(case["steps"]) >= 2 assert case["expected"] assert case["evidence"] if case["acceptance_level"] == "ENTERPRISE_FORMAL": assert case["result"] != "PASS_LOCAL" covered_modules = {module for case in cases for module in case["module_ids"]} assert {f"WP-{number:02d}" for number in range(2, 14)} <= covered_modules assert {"admin", "editor", "viewer"} <= {case["actor"] for case in cases} assert any(case["acceptance_level"] == "ENTERPRISE_FORMAL" for case in cases) assert any(case["result"] == "BLOCKED_EXTERNAL" for case in cases) def test_wp14_docs_state_real_uat_boundary_and_have_no_placeholders() -> None: report = _read(UAT_REPORT) assert "本地工程预验收" in report assert "企业正式验收" in report assert "不能替代企业真实数据 UAT" in report assert "P0" in report assert "签字" in report for path in DELIVERABLES[1:]: content = _read(path) assert not re.search(r"\b(?:TBD|TODO)\b|\{\{[^}]+\}\}", content), path.name def test_wp14_defect_register_is_actionable() -> None: register = _read(DEFECT_REGISTER) for field in ("缺陷编号", "严重度", "状态", "复现与证据", "处置决定"): assert field in register for severity in ("P0", "P1", "P2", "P3"): assert severity in register assert "未发现" in register or "已关闭" in register def test_wp14_user_and_operations_guides_cover_handover_tasks() -> None: user_guide = _read(USER_GUIDE) for role in ("管理员", "编辑者", "查看者"): assert role in user_guide for task in ("设备资产", "实体匹配", "质量问题", "根因", "知识问答", "治理指标"): assert task in user_guide operations = _read(OPERATIONS_HANDOVER) for topic in ("每日巡检", "每周巡检", "备份", "恢复", "回滚", "升级", "异常升级", "责任"): assert topic in operations assert "培训" in operations assert "移交清单" in operations def test_wp14_phase2_backlog_preserves_scope_and_sso_gate() -> None: backlog = _read(PHASE2_BACKLOG) for field in ("待办编号", "来源模块", "优先级", "启动条件", "验收标准", "依赖", "目标阶段"): assert field in backlog for scope in ( "主动元数据", "通用术语", "通用质量运营", "平台可观测", "统一责任", "统一任务", "数据产品治理", "Agent 治理", "安全底座", "产品工程", ): assert scope in backlog assert "单点登录" in backlog assert "第三阶段" in backlog assert "IdP" in backlog def test_wp14_evidence_links_results_to_commands_and_pages() -> None: evidence = _read(EVIDENCE) for section in ("文档契约", "角色与权限", "业务场景", "缺陷结论", "外部门禁"): assert section in evidence assert "tests/test_wp14_delivery_contract.py" in evidence assert "PASS_LOCAL" in evidence assert "BLOCKED_EXTERNAL" in evidence def test_frontend_accepts_standard_success_envelopes_across_http_2xx() -> None: request_client = _read(REQUEST_CLIENT) assert "res.code < 200 || res.code >= 300" in request_client assert "res.code !== 200" not in request_client def test_viewer_development_center_hides_write_only_entries_and_explains_mode() -> None: development_center = _read(DEVELOPMENT_CENTER) assert 'v-for="entry in visibleEntries"' in development_center assert "writeOnly: true" in development_center assert "isViewerOnly" in development_center assert "当前为 viewer 只读模式" in development_center