from types import SimpleNamespace from unittest.mock import AsyncMock from uuid import uuid4 from fastapi.testclient import TestClient from tests.conftest import build_test_app, install_stub, load_module_from_path class DummyChangeSet: def __init__(self, operations=None): if operations is None: self.operations = [] elif isinstance(operations, dict): self.operations = [operations] else: self.operations = operations def _load_project_module(monkeypatch): install_stub(monkeypatch, "app.services", package=True) install_stub( monkeypatch, "app.services.project_info", {}, ) install_stub( monkeypatch, "app.services.tjnetwork", { "ChangeSet": DummyChangeSet, "list_project": lambda: ["demo"], "have_project": lambda network: network == "demo", "create_project": lambda network: None, "delete_project": lambda network: None, "is_project_open": lambda network: False, "open_project": lambda network: None, "close_project": lambda network: None, "copy_project": lambda source, target: None, "import_inp": lambda network, cs: {"ok": True}, "export_inp": lambda network, version: DummyChangeSet({"kind": "export"}), "read_inp": lambda network, inp: True, "dump_inp": lambda network, inp: True, "get_all_vertices": lambda network: [], "get_all_scada_elements": lambda network: [], "get_all_district_metering_areas": lambda network: [], "get_all_service_areas": lambda network: [], "get_all_virtual_districts": lambda network: [], "get_extension_data": lambda network, key: None, "convert_inp_v3_to_v2": lambda inp: DummyChangeSet({"inp": inp}), }, ) install_stub( monkeypatch, "app.auth.project_dependencies", {"get_metadata_repository": lambda: None}, ) install_stub( monkeypatch, "app.infra.db.postgresql.database", {"get_database_instance": lambda network: None}, ) install_stub( monkeypatch, "app.infra.db.timescaledb.database", {"get_database_instance": lambda network: None}, ) return load_module_from_path( "tests_project_endpoints_module", "app/api/v1/endpoints/project.py", ) def test_project_info_returns_404_when_missing(monkeypatch): module = _load_project_module(monkeypatch) repo = SimpleNamespace(get_project_detail_by_code=AsyncMock(return_value=None)) app = build_test_app(module.router, "/api/v1") app.dependency_overrides[module.get_metadata_repository] = lambda: repo client = TestClient(app) response = client.get("/api/v1/project_info/", params={"network": "missing"}) assert response.status_code == 404 assert response.json()["detail"] == "Project missing not found" def test_project_info_returns_geoserver_payload(monkeypatch): module = _load_project_module(monkeypatch) detail = SimpleNamespace( project_id=uuid4(), name="Demo Project", code="demo", description="desc", gs_workspace="ws", map_extent={"xmin": 1, "ymin": 2, "xmax": 3, "ymax": 4}, status="active", geoserver=SimpleNamespace( gs_base_url="http://gs", gs_admin_user="admin", gs_datastore_name="store", default_extent={"xmin": 1, "ymin": 2, "xmax": 3, "ymax": 4}, srid=4326, ), ) repo = SimpleNamespace(get_project_detail_by_code=AsyncMock(return_value=detail)) app = build_test_app(module.router, "/api/v1") app.dependency_overrides[module.get_metadata_repository] = lambda: repo client = TestClient(app) response = client.get("/api/v1/project_info/", params={"network": "demo"}) assert response.status_code == 200 payload = response.json() assert payload["code"] == "demo" assert payload["geoserver"]["gs_base_url"] == "http://gs" def test_open_project_returns_network_even_when_db_connection_fails(monkeypatch): module = _load_project_module(monkeypatch) called = [] monkeypatch.setattr(module, "open_project", lambda network: called.append(network)) async def failing_get_pg_db(network): raise RuntimeError("db down") monkeypatch.setattr(module, "get_pg_db", failing_get_pg_db) client = TestClient(build_test_app(module.router, "/api/v1")) response = client.post("/api/v1/openproject/", params={"network": "demo"}) assert response.status_code == 200 assert response.json() == "demo" assert called == ["demo"] def test_project_lock_lifecycle(monkeypatch): module = _load_project_module(monkeypatch) module.lockedPrjs.clear() client = TestClient(build_test_app(module.router, "/api/v1")) first_lock = client.post("/api/v1/lockproject/", params={"network": "demo"}) second_lock = client.post("/api/v1/lockproject/", params={"network": "demo"}) locked_by_me = client.get("/api/v1/isprojectlockedbyme/", params={"network": "demo"}) unlock = client.post("/api/v1/unlockproject/", params={"network": "demo"}) locked = client.get("/api/v1/isprojectlocked/", params={"network": "demo"}) assert first_lock.json() == 0 assert second_lock.json() == 1 assert locked_by_me.json() is True assert unlock.json() is True assert locked.json() is False