test_data_rule_schema.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. from __future__ import annotations
  2. from pathlib import Path
  3. ROOT = Path(__file__).resolve().parents[1]
  4. MIGRATION = (
  5. ROOT
  6. / "migrations"
  7. / "versions"
  8. / "20260723_110_ai_data_rules.py"
  9. )
  10. RUNTIME_MIGRATION = (
  11. ROOT
  12. / "migrations"
  13. / "versions"
  14. / "20260723_120_rule_execution_runtime.py"
  15. )
  16. EXPECTED_TABLES = {
  17. "data_rules",
  18. "data_rule_versions",
  19. "rule_generation_runs",
  20. "data_standards",
  21. "data_standard_versions",
  22. "standard_rule_bindings",
  23. "dataflow_versions",
  24. "dataflow_component_bindings",
  25. "rule_execution_plans",
  26. "rule_artifacts",
  27. "dataflow_deployments",
  28. "rule_runs",
  29. "rule_violation_samples",
  30. }
  31. def test_ai_data_rule_migration_defines_all_three_domain_layers():
  32. source = MIGRATION.read_text(encoding="utf-8")
  33. assert 'revision = "20260723_110"' in source
  34. assert 'down_revision = "20260722_110"' in source
  35. for table in EXPECTED_TABLES:
  36. assert f"CREATE TABLE public.{table}" in source
  37. def test_ai_data_rule_migration_enforces_immutable_versions_and_fixed_bindings():
  38. source = MIGRATION.read_text(encoding="utf-8")
  39. for expected in (
  40. "UNIQUE (rule_uid, version_no)",
  41. "UNIQUE (standard_uid, version_no)",
  42. "UNIQUE (dataflow_uid, version_no)",
  43. "standard_version_id UUID NOT NULL",
  44. "rule_version_id UUID NOT NULL",
  45. "dataflow_version_id UUID NOT NULL",
  46. "component_kind VARCHAR(30) NOT NULL",
  47. "package_hash CHAR(64)",
  48. "plan_hash CHAR(64)",
  49. "artifact_digest CHAR(64)",
  50. "context_hash CHAR(64)",
  51. "candidate_hash CHAR(64)",
  52. "workflow_version_id UUID",
  53. ):
  54. assert expected in source
  55. def test_ai_data_rule_migration_is_forward_preserving():
  56. source = MIGRATION.read_text(encoding="utf-8")
  57. downgrade = source.split("def downgrade()", 1)[1]
  58. assert "DROP TABLE" not in downgrade.upper()
  59. assert "pass" in downgrade
  60. def test_rule_execution_runtime_migration_adds_pinned_runtime_evidence():
  61. source = RUNTIME_MIGRATION.read_text(encoding="utf-8")
  62. assert 'revision = "20260723_120"' in source
  63. assert 'down_revision = "20260723_110"' in source
  64. for table in (
  65. "data_schema_snapshots",
  66. "dataflow_dataset_bindings",
  67. "rule_compile_evidence",
  68. "rule_test_evidence",
  69. ):
  70. assert f"CREATE TABLE public.{table}" in source
  71. for expected in (
  72. "rule_execution_plan_id UUID NOT NULL",
  73. "created_by UUID REFERENCES public.users(id)",
  74. "candidate JSONB",
  75. "UNIQUE (schema_ref, schema_hash)",
  76. "UNIQUE (dataflow_deployment_id, logical_ref)",
  77. ):
  78. assert expected in source
  79. def test_rule_execution_runtime_migration_is_forward_preserving():
  80. source = RUNTIME_MIGRATION.read_text(encoding="utf-8")
  81. downgrade = source.split("def downgrade()", 1)[1]
  82. assert "DROP TABLE" not in downgrade.upper()
  83. assert "pass" in downgrade