import json from datetime import timedelta import pytest from app.infra.db.timescaledb.repositories.scheme import SchemeRepository from app.services.time_api import parse_utc_time def _node_result(periods: int) -> list[dict]: return [ { "node": "J1", "result": [ {"demand": index, "head": index, "pressure": index, "quality": index} for index in range(periods) ], } ] def _link_result(periods: int) -> list[dict]: return [ { "link": "P1", "result": [ { "flow": index, "friction": index, "headloss": index, "quality": index, "reaction": index, "setting": index, "status": index, "velocity": index, } for index in range(periods) ], } ] def test_store_scheme_simulation_uses_15_minute_report_step(monkeypatch): inserted: dict[str, list[dict]] = {} monkeypatch.setattr( SchemeRepository, "insert_nodes_batch_sync", staticmethod(lambda conn, data: inserted.setdefault("nodes", data)), ) monkeypatch.setattr( SchemeRepository, "insert_links_batch_sync", staticmethod(lambda conn, data: inserted.setdefault("links", data)), ) SchemeRepository.store_scheme_simulation_result_sync( conn=object(), scheme_type="burst_analysis", scheme_name="five_hour_case", node_result_list=_node_result(21), link_result_list=_link_result(21), result_start_time="2026-07-16T00:00:00Z", num_periods=21, result_timestep_seconds=900, ) start_time = parse_utc_time("2026-07-16T00:00:00Z") assert len(inserted["nodes"]) == 21 assert inserted["nodes"][0]["time"] == start_time assert inserted["nodes"][-1]["time"] == start_time + timedelta(hours=5) assert inserted["links"][-1]["time"] == start_time + timedelta(hours=5) def test_store_scheme_simulation_uses_hourly_report_step(monkeypatch): inserted: dict[str, list[dict]] = {} monkeypatch.setattr( SchemeRepository, "insert_nodes_batch_sync", staticmethod(lambda conn, data: inserted.setdefault("nodes", data)), ) monkeypatch.setattr( SchemeRepository, "insert_links_batch_sync", staticmethod(lambda conn, data: inserted.setdefault("links", data)), ) SchemeRepository.store_scheme_simulation_result_sync( conn=object(), scheme_type="burst_analysis", scheme_name="hourly_case", node_result_list=_node_result(6), link_result_list=_link_result(6), result_start_time="2026-07-16T00:00:00Z", num_periods=6, result_timestep_seconds=3600, ) start_time = parse_utc_time("2026-07-16T00:00:00Z") assert [item["time"] for item in inserted["nodes"]] == [ start_time + timedelta(hours=index) for index in range(6) ] def test_run_simulation_passes_report_step_for_extended_scheme(monkeypatch): import app.services.simulation as simulation time_updates: list[dict] = [] storage_calls: list[tuple] = [] monkeypatch.setattr(simulation, "open_project", lambda name: None) monkeypatch.setattr( simulation, "get_time", lambda name: { "HYDRAULIC TIMESTEP": "00:15:00", "REPORT TIMESTEP": "1:00", "DURATION": "0:00", "PATTERN START": "0:00", }, ) monkeypatch.setattr( simulation, "set_time", lambda name, changeset: time_updates.append(changeset.operations[0]), ) monkeypatch.setattr(simulation, "run_project", lambda name: json.dumps({ "simulation_result": "successful", "output": { "times": {"num_periods": 21, "report_step": 900}, "node_results": _node_result(21), "link_results": _link_result(21), }, })) monkeypatch.setattr( simulation.TimescaleInternalStorage, "store_scheme_simulation", staticmethod(lambda *args, **kwargs: storage_calls.append((args, kwargs))), ) simulation.run_simulation( name="fengyang", simulation_type="extended", modify_pattern_start_time="2026-07-16T00:00:00+08:00", modify_total_duration=18000, scheme_type="burst_analysis", scheme_name="five_hour_case", ) assert time_updates[0]["DURATION"] == "05:00:00" assert time_updates[0]["REPORT TIMESTEP"] == "1:00" assert storage_calls[0][0][5] == 21 assert storage_calls[0][0][6] == 900