94 lines
3.1 KiB
Python
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()
|