153 lines
5.4 KiB
Python
153 lines
5.4 KiB
Python
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
|