"""tjwater_v2 source/event atomicity checks; every write is rolled back.""" from contextlib import contextmanager import os from uuid import uuid4 import pytest from samples.peripheral.auth import Identity from samples.peripheral.config import SampleSettings from samples.peripheral.errors import SampleFailure from samples.peripheral.schemas import CreateWorkOrder, DeleteResource, UpdateWorkOrder from samples.peripheral.store import PostgresStore pytestmark = pytest.mark.skipif( os.getenv("PERIPHERAL_SAMPLE_LIVE_TEST") != "1", reason="explicit live sample opt-in required", ) def test_work_order_mutations_and_events_are_atomic_idempotent_and_rollback_cleanly(monkeypatch): settings = SampleSettings() assert settings.db_name == "tjwater_v2", "event verification is restricted to tjwater_v2" store = PostgresStore(settings) who = Identity(str(uuid4()), str(uuid4()), True) with store.connection() as conn: @contextmanager def connection(*, readonly=False, timeseries=False): assert timeseries is False with conn.transaction(): yield conn monkeypatch.setattr(store, "connection", connection) with conn.transaction(force_rollback=True): command = CreateWorkOrder( request_id=uuid4(), title="AUTOTEST push work order", summary="isolated transaction", ) created = store.create_work_order(who, command) assert store.create_work_order(who, command) == created order_id = created["work_order_id"] store.update_work_order(who, order_id, UpdateWorkOrder( request_id=uuid4(), expected_revision=1, status="in_progress", )) store.update_work_order(who, order_id, UpdateWorkOrder( request_id=uuid4(), expected_revision=2, progress_note="AUTOTEST field feedback", )) with pytest.raises(SampleFailure) as stale: store.update_work_order(who, order_id, UpdateWorkOrder( request_id=uuid4(), expected_revision=1, status="completed", )) assert stale.value.code == "REVISION_CONFLICT" store.delete_work_order(who, order_id, DeleteResource( request_id=uuid4(), expected_revision=3, )) rows = conn.execute( """SELECT project_id,topic,aggregate_type,aggregate_id,aggregate_revision,metadata FROM workbench.domain_event_log WHERE project_id=%s ORDER BY event_seq""", (who.project_id,), ).fetchall() assert len(rows) == 4 assert [row["aggregate_revision"] for row in rows] == [1, 2, 3, 4] assert [row["metadata"]["change"] for row in rows] == ["created", "updated", "updated", "deleted"] assert all(row["topic"] == "workbench.work_order.changed" and row["aggregate_type"] == "peripheral_work_order" and row["aggregate_id"] == order_id for row in rows) assert store.list_work_orders(who, 20)["items"] == [] original = store._work_order_event def fail_after_event(*args, **kwargs): original(*args, **kwargs) raise RuntimeError("AUTOTEST transaction failure") monkeypatch.setattr(store, "_work_order_event", fail_after_event) with pytest.raises(RuntimeError, match="transaction failure"): store.create_work_order(who, command.model_copy(update={"request_id": uuid4()})) assert store.list_work_orders(who, 20)["items"] == [] assert conn.execute( "SELECT count(*) AS n FROM workbench.domain_event_log WHERE project_id=%s", (who.project_id,), ).fetchone()["n"] == 4 for table in ("workbench.domain_event_log", "peripheral_sample.work_orders", "peripheral_sample.work_order_revisions", "peripheral_sample.requests"): assert conn.execute(f"SELECT count(*) AS n FROM {table} WHERE project_id=%s", (who.project_id,)).fetchone()["n"] == 0