test_p2_wp12_replication_package_contract.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. from __future__ import annotations
  2. import hashlib
  3. import json
  4. import subprocess
  5. from pathlib import Path
  6. ROOT = Path(__file__).resolve().parents[1]
  7. PACKAGE_DIR = ROOT / "docs/phase2/p2-wp12-spare-parts-package"
  8. BASE_COMMIT = "8ec8caa"
  9. def _sha256(path: Path) -> str:
  10. return hashlib.sha256(path.read_bytes()).hexdigest()
  11. def test_replication_package_is_self_contained_and_hash_bound():
  12. manifest = json.loads((PACKAGE_DIR / "manifest.json").read_text(encoding="utf-8"))
  13. for key in ("template", "evidence", "snapshot", "delta", "acceptance_report"):
  14. binding = manifest["files"][key]
  15. path = PACKAGE_DIR / binding["path"]
  16. assert path.is_file()
  17. assert _sha256(path) == binding["sha256"]
  18. assert (PACKAGE_DIR / "domain-template.json").read_bytes() == (
  19. ROOT / "docs/phase2/P2_WP01_SPARE_PARTS_DOMAIN_TEMPLATE.json"
  20. ).read_bytes()
  21. def test_cli_report_is_reproducible_and_contains_no_source_rows(tmp_path: Path):
  22. outputs = [tmp_path / "first.json", tmp_path / "second.json"]
  23. for output in outputs:
  24. completed = subprocess.run(
  25. [
  26. str(ROOT / ".venv/bin/python"),
  27. str(ROOT / "scripts/validate_domain_replication.py"),
  28. "--package-dir",
  29. str(PACKAGE_DIR),
  30. "--output",
  31. str(output),
  32. ],
  33. cwd=ROOT,
  34. capture_output=True,
  35. text=True,
  36. )
  37. assert completed.returncode == 0, completed.stderr
  38. assert outputs[0].read_bytes() == outputs[1].read_bytes()
  39. assert outputs[0].read_bytes() == (PACKAGE_DIR / "acceptance-report.json").read_bytes()
  40. report = json.loads(outputs[0].read_text(encoding="utf-8"))
  41. assert report["status"] == "passed"
  42. assert report["report_sha256"]
  43. serialized = outputs[0].read_text(encoding="utf-8")
  44. assert "MAT-0001" not in serialized
  45. assert "轴承" not in serialized
  46. def test_package_uses_generic_platform_apis_and_documents_external_gates():
  47. evidence = json.loads((PACKAGE_DIR / "evidence.json").read_text(encoding="utf-8"))
  48. api_refs = {
  49. ref
  50. for receipt in evidence["receipts"]
  51. for ref in receipt["api_refs"]
  52. }
  53. required_prefixes = {
  54. "/api/meta/domain-templates",
  55. "/api/meta/active-metadata",
  56. "/api/development/v1/semantic-assets",
  57. "/api/rules/quality-operations",
  58. "/api/system/work-center",
  59. "/api/datafactory/observability",
  60. "/api/dataservice/governance/products",
  61. "/api/knowledge/agents",
  62. }
  63. assert required_prefixes <= api_refs
  64. assert all("/device-" not in ref for ref in api_refs)
  65. readme = (PACKAGE_DIR / "README.md").read_text(encoding="utf-8")
  66. for phrase in (
  67. "企业真实负责人",
  68. "企业只读数据源",
  69. "真实用户 UAT",
  70. "不能替代生产验收",
  71. "第三业务域",
  72. ):
  73. assert phrase in readme
  74. def test_wp12_changes_do_not_modify_device_specific_services():
  75. completed = subprocess.run(
  76. ["git", "diff", "--name-only", BASE_COMMIT, "--"],
  77. cwd=ROOT,
  78. check=True,
  79. capture_output=True,
  80. text=True,
  81. )
  82. changed = set(completed.stdout.splitlines())
  83. status = subprocess.run(
  84. ["git", "status", "--porcelain"],
  85. cwd=ROOT,
  86. check=True,
  87. capture_output=True,
  88. text=True,
  89. )
  90. changed.update(
  91. line[3:]
  92. for line in status.stdout.splitlines()
  93. if line.startswith("?? ")
  94. )
  95. forbidden_prefixes = (
  96. "app/core/data_research/device_",
  97. "app/api/data_development/device_",
  98. "frontend/src/views/dataResearch/device",
  99. )
  100. assert not any(path.startswith(forbidden_prefixes) for path in changed)
  101. assert "app/core/governance/domain_replication.py" in changed
  102. def test_replication_validator_has_no_domain_specific_imports():
  103. source = (ROOT / "app/core/governance/domain_replication.py").read_text(
  104. encoding="utf-8"
  105. )
  106. cli = (ROOT / "scripts/validate_domain_replication.py").read_text(
  107. encoding="utf-8"
  108. )
  109. assert "app.core.data_research.device" not in source + cli
  110. assert "spare_parts" not in source
  111. assert "material_code" not in source