import asyncio from datetime import datetime, timezone from uuid import uuid4 import pytest from app.infra.db.timescaledb.repositories.analysis import AnalysisResultsRepository class _FakeCursor: def __init__(self): self.calls = [] async def __aenter__(self): return self async def __aexit__(self, exc_type, exc, tb): return False async def execute(self, query, params): self.calls.append((str(query), params)) async def fetchall(self): return [] class _FakeConnection: def __init__(self): self.cursor_instance = _FakeCursor() def cursor(self): return self.cursor_instance def test_prepare_simulation_rows_uses_run_timestep(): nodes, links = AnalysisResultsRepository.prepare_simulation_rows( [{"node": "J1", "result": [{"pressure": 1.0}, {"pressure": 2.0}]}], [{"link": "P1", "result": [{"flow": 3.0}, {"flow": 4.0}]}], "2026-08-24T08:00:00+08:00", num_periods=2, result_timestep_seconds=900, ) assert [row["time"] for row in nodes] == [ datetime(2026, 8, 24, 0, 0, tzinfo=timezone.utc), datetime(2026, 8, 24, 0, 15, tzinfo=timezone.utc), ] assert nodes[0]["node_id"] == "J1" assert links[1]["link_id"] == "P1" def test_node_series_rejects_unknown_field(): with pytest.raises(ValueError, match="invalid node result field"): asyncio.run( AnalysisResultsRepository.get_node_series( _FakeConnection(), uuid4(), "J1", datetime.now(timezone.utc), datetime.now(timezone.utc), "unknown", ) ) def test_node_series_filters_by_run_and_node(): conn = _FakeConnection() run_id = uuid4() start = datetime(2026, 8, 24, tzinfo=timezone.utc) end = datetime(2026, 8, 25, tzinfo=timezone.utc) asyncio.run( AnalysisResultsRepository.get_node_series( conn, run_id, "J1", start, end, "pressure" ) ) query, params = conn.cursor_instance.calls[0] assert "analysis.node_results" in query assert params == (run_id, "J1", start, end) def test_analysis_store_locks_run_before_empty_check(): cursor = _FakeCursor() run_id = uuid4() asyncio.run(AnalysisResultsRepository._lock_run(cursor, run_id)) query, params = cursor.calls[0] assert "pg_advisory_xact_lock" in query assert params == (run_id,)