from unittest.mock import MagicMock from uuid import uuid4 from app.services import scheme_management from app.infra.db.project_routing import ActiveProjectRouting, activate_project_routing def _mock_connection(monkeypatch): cursor = MagicMock() cursor.rowcount = 1 connection = MagicMock() connection.cursor.return_value.__enter__.return_value = cursor context = MagicMock() context.__enter__.return_value = connection monkeypatch.setattr(scheme_management, "project_connection", lambda _name: context) return cursor def test_repeated_analysis_names_create_distinct_run_ids(monkeypatch) -> None: cursor = _mock_connection(monkeypatch) arguments = { "name": "tjwater_next", "scheme_name": "same-window", "scheme_type": "burst_analysis", "username": "alice", "scheme_start_time": "2026-08-24T00:00:00Z", "scheme_detail": {}, } first = scheme_management.create_analysis_run(**arguments) second = scheme_management.create_analysis_run(**arguments) assert first != second assert cursor.execute.call_count == 2 assert all( "insert into analysis.runs" in call.args[0].lower() for call in cursor.execute.call_args_list ) def test_update_analysis_run_targets_execution_id(monkeypatch) -> None: cursor = _mock_connection(monkeypatch) run_id = scheme_management.create_analysis_run( name="tjwater_next", scheme_name="run", scheme_type="burst_analysis", username="alice", scheme_start_time="2026-08-24T00:00:00Z", scheme_detail={}, ) cursor.reset_mock() scheme_management.update_analysis_run( "tjwater_next", run_id, status="completed", username="alice", scheme_detail={"window": "24h"}, ) statement, params = cursor.execute.call_args.args assert "where run_id = %s" in statement.lower() assert params[-1] == run_id assert params[1] == "completed" def test_run_and_business_result_share_one_transaction(monkeypatch) -> None: connection = object() context = MagicMock() context.__enter__.return_value = connection monkeypatch.setattr( scheme_management, "project_transaction", lambda _name: context, ) created_ids = [] result_ids = [] monkeypatch.setattr( scheme_management.AnalysisRepository, "create_run_sync", lambda conn, **kwargs: created_ids.append((conn, kwargs["run_id"])), ) monkeypatch.setattr( scheme_management.AnalysisRepository, "insert_result_sync", lambda conn, run_id, **_kwargs: result_ids.append((conn, run_id)), ) run_id = scheme_management.store_analysis_run_with_result( name="tjwater_v2", scheme_name="leak-run", scheme_type="dma_leak_identification", username="alice", scheme_start_time="2026-08-24T00:00:00Z", scheme_detail={}, result_type="leakage_identification", result_payload={"rows": []}, ) assert created_ids == [(connection, run_id)] assert result_ids == [(connection, run_id)] def test_completed_business_result_emits_one_event_after_result(monkeypatch) -> None: connection = object() context = MagicMock() context.__enter__.return_value = connection monkeypatch.setattr(scheme_management, "project_transaction", lambda _name: context) calls = [] monkeypatch.setattr( scheme_management.AnalysisRepository, "create_run_sync", lambda _conn, **_kwargs: calls.append("run"), ) monkeypatch.setattr( scheme_management.AnalysisRepository, "insert_result_sync", lambda _conn, _run_id, **_kwargs: calls.append("result"), ) monkeypatch.setattr( scheme_management.AnalysisRepository, "append_run_changed_event_sync", lambda _conn, **event: calls.append(("event", event)), ) project_id = uuid4() routing = ActiveProjectRouting( project_code="test", business_dsn="postgresql://test/db", project_id=project_id ) with activate_project_routing(routing): run_id = scheme_management.store_analysis_run_with_result( name="test", scheme_name="analysis", scheme_type="dma", username="alice", scheme_start_time="2026-09-23T00:00:00Z", scheme_detail={}, result_type="summary", result_payload={"rows": []}, ) assert calls[:2] == ["run", "result"] assert calls[2][0] == "event" assert calls[2][1] == { "project_id": project_id, "run_id": run_id, "revision": 1, "status": "completed", "occurred_at": calls[2][1]["occurred_at"], "results_committed": True, }