A05: Add server-side idempotency for catch report creation via Idempotency-Key header
This commit is contained in:
@@ -12,7 +12,7 @@ from app.database import Base, get_session
|
||||
from app.community_importer import stage_observations
|
||||
from app.importer import ImportAlreadyRunning
|
||||
from app.main import app
|
||||
from app.models import Bait, BaitKind, CatchReport, DataSource, ExternalEntityAlias, ExternalObservation, Fish, ImportStatus, ModerationEvent, ModerationStatus, OfficialRecordImport, SourceType, Spot, Waterbody
|
||||
from app.models import Bait, BaitKind, CatchReport, DataSource, ExternalEntityAlias, ExternalObservation, Fish, ImportStatus, ModerationEvent, ModerationStatus, OfficialRecordImport, SourceType, Spot, SubmissionAttempt, Waterbody
|
||||
|
||||
|
||||
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
|
||||
@@ -421,3 +421,21 @@ def test_admin_delete_anonymizes_report_removes_screenshot_and_keeps_audit(monke
|
||||
assert event is not None
|
||||
assert event.reason == "user report deleted and anonymized"
|
||||
assert client.delete(f"/api/v1/admin/catch-reports/{created['id']}", headers=headers).status_code == 404
|
||||
|
||||
|
||||
def test_catch_report_idempotency_key_prevents_duplicates(monkeypatch) -> None:
|
||||
"""A05: Server-side idempotency — same key within 5 min returns 200 with idempotent=True."""
|
||||
import uuid
|
||||
# Use UUID-based key to avoid collisions with any previous test
|
||||
idem_key = f"idem-test-{uuid.uuid4().hex[:16]}"
|
||||
headers = {"Idempotency-Key": idem_key}
|
||||
payload = {"fish_slug": "pike", "waterbody_slug": "test-lake", "x": 99, "y": 100, "weight_g": 7700}
|
||||
# First request — creates report
|
||||
first = client.post("/api/v1/catch-reports", json=payload, headers=headers)
|
||||
assert first.status_code == 201
|
||||
assert first.json()["idempotent"] is False
|
||||
report_id = first.json()["id"]
|
||||
# Second request with same key — returns 200 with idempotent flag
|
||||
second = client.post("/api/v1/catch-reports", json=payload, headers=headers)
|
||||
assert second.status_code == 200, f"Expected 200, got {second.status_code}. Response: {second.json()}"
|
||||
assert second.json()["idempotent"] is True
|
||||
|
||||
Reference in New Issue
Block a user