Files
next-tjwater-server/tests/integration/test_task_alerts_live.py
T

94 lines
3.1 KiB
Python

"""Opt-in PostgreSQL checks for the task alert event state machine."""
from __future__ import annotations
import os
from datetime import datetime, timezone
from types import SimpleNamespace
from uuid import uuid4
import pytest
from psycopg import AsyncConnection
from psycopg.rows import dict_row
from app.core.config import settings
from app.domain.schemas.task_alert import TaskAlertEvent
from app.infra.db.postgresql.task_alerts import TaskAlertRepository
from app.services.task_alerts import TaskAlertService
pytestmark = [
pytest.mark.skipif(
os.getenv("TASK_ALERT_LIVE_TEST") != "1",
reason="set TASK_ALERT_LIVE_TEST=1 to use provisioned workbench alert tables",
),
pytest.mark.anyio,
]
@pytest.fixture
def anyio_backend():
return "asyncio"
@pytest.mark.anyio
async def test_alert_event_round_trip_and_idempotency():
project_id = uuid4()
now = datetime(2026, 9, 18, 3, tzinfo=timezone.utc)
conn = await AsyncConnection.connect(
host=settings.DB_HOST,
port=settings.DB_PORT,
user=settings.DB_USER,
password=settings.DB_PASSWORD,
dbname="tjwater_v2",
connect_timeout=3,
options="-c statement_timeout=10000",
row_factory=dict_row,
)
try:
service = TaskAlertService(
TaskAlertRepository(conn, project_id),
None,
clock=lambda: now,
internal_producer_id="AUTOTEST-scheduler",
)
event = TaskAlertEvent(
event_id=uuid4(),
producer_id="AUTOTEST-scheduler",
alert_id=f"AUTOTEST-{uuid4()}",
event_type="raised",
occurred_at=now,
condition_id=None,
source={
"task_type": "scheduled_task",
"task_id": "AUTOTEST-schedule",
"run_id": "AUTOTEST-occurrence",
},
title="AUTOTEST alert",
description="Synthetic integration record",
severity="warning",
)
first = await service.push(event)
repeated = await service.push(event)
assert first == repeated
row = await conn.execute(
"""SELECT revision,status,document FROM workbench.alerts
WHERE project_id=%s AND alert_id=%s""",
(project_id, event.alert_id),
)
stored = await row.fetchone()
assert stored["revision"] == 1 and stored["status"] == "active"
assert stored["document"]["producer_id"] == "AUTOTEST-scheduler"
finally:
# Assertion reads open an implicit transaction. End it before starting the
# cleanup transaction, otherwise closing the connection rolls the nested
# cleanup savepoint back together with that read transaction.
await conn.rollback()
async with conn.transaction():
await conn.execute(
"DELETE FROM workbench.alert_events WHERE project_id=%s", (project_id,)
)
await conn.execute(
"DELETE FROM workbench.alerts WHERE project_id=%s", (project_id,)
)
await conn.close()