test_phase3_wp06_subscription_postgres.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. from __future__ import annotations
  2. import os
  3. import subprocess
  4. import uuid
  5. from pathlib import Path
  6. import pytest
  7. from sqlalchemy import create_engine, text
  8. pytestmark = pytest.mark.integration
  9. ROOT = Path(__file__).resolve().parents[2]
  10. def _url():
  11. value = os.environ.get("TEST_DATABASE_URL")
  12. if not value:
  13. pytest.skip("TEST_DATABASE_URL is required")
  14. return value
  15. def _upgrade_head():
  16. environment = dict(os.environ)
  17. environment["MIGRATION_DATABASE_URL"] = os.environ.get("TEST_MIGRATION_DATABASE_URL", _url())
  18. subprocess.run(
  19. [str(ROOT / ".venv/bin/alembic"), "-c", str(ROOT / "alembic.ini"), "upgrade", "head"],
  20. cwd=ROOT, env=environment, check=True, capture_output=True, text=True,
  21. )
  22. def test_subscription_postgres_uses_db_time_fencing_and_bounded_dead_letter():
  23. from app.core.system.trusted_delivery_subscription_repository import (
  24. SqlAlchemyTrustedDeliverySubscriptionRepository,
  25. )
  26. _upgrade_head()
  27. engine = create_engine(_url(), pool_pre_ping=True)
  28. actor, policy, grant, subscription, asset = (str(uuid.uuid4()) for _ in range(5))
  29. key = f"wp06-test-sub-{actor[:8]}"
  30. try:
  31. with engine.begin() as connection:
  32. connection.execute(text("INSERT INTO public.users(id,username,display_name,password_hash,status) VALUES(CAST(:id AS uuid),:name,:name,'test','active')"), {"id": actor, "name": key})
  33. connection.execute(text("INSERT INTO public.trusted_delivery_policy_versions(uid,code,version,status,selector,resource_rules,created_by) VALUES(CAST(:uid AS uuid),:code,'1','active','{}','{}',CAST(:actor AS uuid))"), {"uid": policy, "code": f"WP06_SUB_{actor[:8]}", "actor": actor})
  34. connection.execute(text("""INSERT INTO public.trusted_delivery_policy_transitions(uid,policy_uid,operation,idempotency_key,request_digest,approval_ref,approval_digest,actor_uid)
  35. VALUES(CAST(:uid AS uuid),CAST(:policy AS uuid),'activate',:key,:digest,'approval:fixture',:digest,CAST(:actor AS uuid))"""), {"uid": str(uuid.uuid4()), "policy": policy, "key": f"{key}-policy", "digest": "a" * 64, "actor": actor})
  36. connection.execute(text("""INSERT INTO public.trusted_delivery_grants(uid,policy_uid,subject_uid,asset_uid,provider,idempotency_key,request_digest,expires_at,status,reason_code,current_version,created_by,approval_ref,approval_digest,purpose,environment,target_capability)
  37. VALUES(CAST(:uid AS uuid),CAST(:policy AS uuid),CAST(:actor AS uuid),CAST(:asset AS uuid),'database',:key,:digest,'2026-12-31T00:00:00+00:00','active','test',1,CAST(:actor AS uuid),'approval:fixture',:digest,'quality_review','test','{}')"""), {"uid": grant, "policy": policy, "actor": actor, "asset": asset, "key": f"{key}-grant", "digest": "a" * 64})
  38. repository = SqlAlchemyTrustedDeliverySubscriptionRepository(connection)
  39. created = repository.create_subscription({"uid": subscription, "grant_uid": grant, "asset_uid": asset, "trigger": {"kind": "schedule", "schedule_ref": "wp06-test-schedule"}, "purpose": "quality_review", "expires_at": "2026-12-30T00:00:00+00:00", "idempotency_key": key, "request_digest": "b" * 64, "status": "draft", "current_version": 1, "created_by": actor})
  40. active = repository.transition_subscription(created["uid"], {"draft"}, "active")
  41. delivery = repository.enqueue_subscription_delivery({"uid": str(uuid.uuid4()), "subscription_uid": active["uid"], "trigger_ref": "wp06-test-trigger", "event_digest": "c" * 64, "idempotency_key": f"{key}-delivery", "request_digest": "d" * 64, "status": "pending", "attempt_count": 0, "lease_owner": None, "lease_fence": 0})
  42. with engine.begin() as first:
  43. claimed = SqlAlchemyTrustedDeliverySubscriptionRepository(first).claim_subscription_delivery(delivery["uid"], "worker-one")
  44. assert claimed["lease_fence"] == 1
  45. with engine.begin() as second:
  46. assert SqlAlchemyTrustedDeliverySubscriptionRepository(second).claim_subscription_delivery(delivery["uid"], "worker-two") is None
  47. for attempt in range(3):
  48. with engine.begin() as connection:
  49. repository = SqlAlchemyTrustedDeliverySubscriptionRepository(connection)
  50. current = claimed if attempt == 0 else repository.claim_subscription_delivery(delivery["uid"], "worker-one")
  51. if current is None:
  52. connection.execute(text("UPDATE public.trusted_delivery_subscription_deliveries SET next_attempt_at=clock_timestamp()-interval '1 second' WHERE uid=CAST(:uid AS uuid)"), {"uid": delivery["uid"]})
  53. current = repository.claim_subscription_delivery(delivery["uid"], "worker-one")
  54. result = repository.record_subscription_attempt(delivery["uid"], "worker-one", current["lease_fence"], False)
  55. assert result["status"] == "dead_letter"
  56. with engine.begin() as connection:
  57. repository = SqlAlchemyTrustedDeliverySubscriptionRepository(connection)
  58. compensated = repository.compensate_subscription_delivery(delivery["uid"], "operator_review", "COMPENSATED")
  59. assert compensated["status"] == "compensated"
  60. finally:
  61. with engine.begin() as connection:
  62. connection.execute(text("DELETE FROM public.trusted_delivery_subscription_deliveries WHERE idempotency_key LIKE 'wp06-test-sub-%'"))
  63. connection.execute(text("DELETE FROM public.trusted_delivery_subscriptions WHERE idempotency_key LIKE 'wp06-test-sub-%'"))
  64. connection.execute(text("DELETE FROM public.trusted_delivery_grants WHERE idempotency_key LIKE 'wp06-test-sub-%'"))
  65. connection.execute(text("DELETE FROM public.trusted_delivery_policy_transitions WHERE idempotency_key LIKE 'wp06-test-sub-%'"))
  66. connection.execute(text("DELETE FROM public.trusted_delivery_policy_versions WHERE code LIKE 'WP06_SUB_%'"))
  67. connection.execute(text("DELETE FROM public.users WHERE username LIKE 'wp06-test-sub-%'"))
  68. engine.dispose()