test_wp14_delivery_contract.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. from __future__ import annotations
  2. import json
  3. import re
  4. from pathlib import Path
  5. ROOT = Path(__file__).resolve().parents[1]
  6. UAT_CASES = ROOT / "docs/acceptance/WP14_UAT_CASES.json"
  7. UAT_REPORT = ROOT / "docs/acceptance/WP14_UAT_PLAN_AND_REPORT.md"
  8. DEFECT_REGISTER = ROOT / "docs/acceptance/WP14_DEFECT_REGISTER.md"
  9. USER_GUIDE = ROOT / "docs/guides/DATAOPS_PHASE1_USER_OPERATION_GUIDE.md"
  10. OPERATIONS_HANDOVER = ROOT / "docs/runbooks/DATAOPS_PHASE1_OPERATIONS_HANDOVER.md"
  11. PHASE2_BACKLOG = ROOT / "docs/roadmap/DATAOPS_PHASE2_BACKLOG.md"
  12. EVIDENCE = ROOT / "docs/validation/WP14_UAT_HANDOVER_EVIDENCE.md"
  13. REQUEST_CLIENT = ROOT / "frontend/src/utils/request.js"
  14. DEVELOPMENT_CENTER = (
  15. ROOT / "frontend/src/views/dataGovernance/development/index.vue"
  16. )
  17. DELIVERABLES = (
  18. UAT_CASES,
  19. UAT_REPORT,
  20. DEFECT_REGISTER,
  21. USER_GUIDE,
  22. OPERATIONS_HANDOVER,
  23. PHASE2_BACKLOG,
  24. EVIDENCE,
  25. )
  26. def _read(path: Path) -> str:
  27. return path.read_text(encoding="utf-8")
  28. def _cases() -> list[dict]:
  29. payload = json.loads(_read(UAT_CASES))
  30. assert payload["work_package"] == "WP-14"
  31. assert payload["schema_version"] == "1.0"
  32. return payload["cases"]
  33. def test_wp14_deliverables_exist() -> None:
  34. missing = [str(path.relative_to(ROOT)) for path in DELIVERABLES if not path.is_file()]
  35. assert not missing, f"WP14 交付物缺失: {missing}"
  36. def test_wp14_uat_cases_cover_roles_modules_and_acceptance_boundaries() -> None:
  37. cases = _cases()
  38. assert len(cases) >= 16
  39. required_fields = {
  40. "id",
  41. "module_ids",
  42. "title",
  43. "actor",
  44. "acceptance_level",
  45. "preconditions",
  46. "steps",
  47. "expected",
  48. "evidence",
  49. "result",
  50. "notes",
  51. }
  52. for case in cases:
  53. assert required_fields <= case.keys(), case.get("id")
  54. assert case["id"].startswith("WP14-UAT-")
  55. assert case["actor"] in {"admin", "editor", "viewer", "enterprise_acceptance"}
  56. assert case["acceptance_level"] in {"LOCAL_ENGINEERING", "ENTERPRISE_FORMAL"}
  57. assert case["result"] in {"PASS_LOCAL", "FAIL", "BLOCKED_EXTERNAL", "NOT_RUN"}
  58. assert case["module_ids"]
  59. assert case["preconditions"]
  60. assert len(case["steps"]) >= 2
  61. assert case["expected"]
  62. assert case["evidence"]
  63. if case["acceptance_level"] == "ENTERPRISE_FORMAL":
  64. assert case["result"] != "PASS_LOCAL"
  65. covered_modules = {module for case in cases for module in case["module_ids"]}
  66. assert {f"WP-{number:02d}" for number in range(2, 14)} <= covered_modules
  67. assert {"admin", "editor", "viewer"} <= {case["actor"] for case in cases}
  68. assert any(case["acceptance_level"] == "ENTERPRISE_FORMAL" for case in cases)
  69. assert any(case["result"] == "BLOCKED_EXTERNAL" for case in cases)
  70. def test_wp14_docs_state_real_uat_boundary_and_have_no_placeholders() -> None:
  71. report = _read(UAT_REPORT)
  72. assert "本地工程预验收" in report
  73. assert "企业正式验收" in report
  74. assert "不能替代企业真实数据 UAT" in report
  75. assert "P0" in report
  76. assert "签字" in report
  77. for path in DELIVERABLES[1:]:
  78. content = _read(path)
  79. assert not re.search(r"\b(?:TBD|TODO)\b|\{\{[^}]+\}\}", content), path.name
  80. def test_wp14_defect_register_is_actionable() -> None:
  81. register = _read(DEFECT_REGISTER)
  82. for field in ("缺陷编号", "严重度", "状态", "复现与证据", "处置决定"):
  83. assert field in register
  84. for severity in ("P0", "P1", "P2", "P3"):
  85. assert severity in register
  86. assert "未发现" in register or "已关闭" in register
  87. def test_wp14_user_and_operations_guides_cover_handover_tasks() -> None:
  88. user_guide = _read(USER_GUIDE)
  89. for role in ("管理员", "编辑者", "查看者"):
  90. assert role in user_guide
  91. for task in ("设备资产", "实体匹配", "质量问题", "根因", "知识问答", "治理指标"):
  92. assert task in user_guide
  93. operations = _read(OPERATIONS_HANDOVER)
  94. for topic in ("每日巡检", "每周巡检", "备份", "恢复", "回滚", "升级", "异常升级", "责任"):
  95. assert topic in operations
  96. assert "培训" in operations
  97. assert "移交清单" in operations
  98. def test_wp14_phase2_backlog_preserves_scope_and_sso_gate() -> None:
  99. backlog = _read(PHASE2_BACKLOG)
  100. for field in ("待办编号", "来源模块", "优先级", "启动条件", "验收标准", "依赖", "目标阶段"):
  101. assert field in backlog
  102. for scope in (
  103. "主动元数据",
  104. "通用术语",
  105. "通用质量运营",
  106. "平台可观测",
  107. "统一责任",
  108. "统一任务",
  109. "数据产品治理",
  110. "Agent 治理",
  111. "安全底座",
  112. "产品工程",
  113. ):
  114. assert scope in backlog
  115. assert "单点登录" in backlog
  116. assert "第三阶段" in backlog
  117. assert "IdP" in backlog
  118. def test_wp14_evidence_links_results_to_commands_and_pages() -> None:
  119. evidence = _read(EVIDENCE)
  120. for section in ("文档契约", "角色与权限", "业务场景", "缺陷结论", "外部门禁"):
  121. assert section in evidence
  122. assert "tests/test_wp14_delivery_contract.py" in evidence
  123. assert "PASS_LOCAL" in evidence
  124. assert "BLOCKED_EXTERNAL" in evidence
  125. def test_frontend_accepts_standard_success_envelopes_across_http_2xx() -> None:
  126. request_client = _read(REQUEST_CLIENT)
  127. assert "res.code < 200 || res.code >= 300" in request_client
  128. assert "res.code !== 200" not in request_client
  129. def test_viewer_development_center_hides_write_only_entries_and_explains_mode() -> None:
  130. development_center = _read(DEVELOPMENT_CENTER)
  131. assert 'v-for="entry in visibleEntries"' in development_center
  132. assert "writeOnly: true" in development_center
  133. assert "isViewerOnly" in development_center
  134. assert "当前为 viewer 只读模式" in development_center