Files
TJWaterServerBinary/tests/api/test_sensor_placement_endpoints.py
T
jiang fa188af0b1 refactor(db)!: adopt project-routed pooled databases
Reorganize WNDB by responsibility and remove legacy scheme endpoints.\n\nRoute analysis and time-series access through project pools, preserve transactional realtime replacement, and refresh GIS materialized views after writes.\n\nAdd database architecture documentation, live pooling coverage, API contract updates, and executable container verification.\n\nBREAKING CHANGE: legacy scheme APIs and flat app.native.wndb module imports are removed.
2026-08-25 18:35:05 +08:00

129 lines
3.6 KiB
Python

from datetime import datetime, timezone
from io import BytesIO
from types import SimpleNamespace
from uuid import uuid4
from fastapi.testclient import TestClient
from app.api.v1.endpoints import sensor_placement as endpoint
from tests.conftest import build_test_app
RUN_ID = uuid4()
def _run(**overrides):
value = {
"run_id": RUN_ID,
"name": "北区测压点",
"sensor_count": 1,
"min_diameter": 300,
"created_by": "alice",
"created_at": datetime(2026, 8, 24, tzinfo=timezone.utc),
"status": "completed",
"sensor_locations": ["J1"],
"sensor_points": [
{
"node_id": "J1",
"max_pipe_diameter": 400.0,
"project_x": 1.0,
"project_y": 2.0,
"map_x": 3.0,
"map_y": 4.0,
"longitude": 121.0,
"latitude": 31.0,
"elevation": 5.0,
}
],
}
value.update(overrides)
return value
def _client(project_role="member", username="alice", role="user"):
app = build_test_app(endpoint.router, "/api/v1")
app.dependency_overrides[endpoint.get_project_context] = lambda: SimpleNamespace(
project_code="tjwater", project_role=project_role
)
app.dependency_overrides[endpoint.get_current_metadata_user] = lambda: SimpleNamespace(
username=username, role=role, is_superuser=False
)
return TestClient(app)
def test_optimize_returns_analysis_run(monkeypatch):
captured = {}
monkeypatch.setattr(
endpoint,
"pressure_sensor_placement_kmeans",
lambda **kwargs: captured.update(kwargs) or {"run_id": RUN_ID},
)
monkeypatch.setattr(endpoint, "get_sensor_placement_run", lambda *_: _run())
response = _client().post(
"/api/v1/sensor-placement-runs",
json={
"network": "tjwater",
"run_name": "北区测压点",
"sensor_type": "pressure",
"method": "kmeans",
"sensor_count": 1,
"min_diameter": 300,
},
)
assert response.status_code == 200
assert response.json()["run_id"] == str(RUN_ID)
assert captured["username"] == "alice"
def test_optimize_rejects_project_mismatch(monkeypatch):
response = _client().post(
"/api/v1/sensor-placement-runs",
json={
"network": "other",
"run_name": "越权运行",
"sensor_type": "pressure",
"method": "kmeans",
"sensor_count": 1,
},
)
assert response.status_code == 403
def test_viewer_cannot_update_run(monkeypatch):
monkeypatch.setattr(endpoint, "get_sensor_placement_run", lambda *_: _run())
response = _client(project_role="viewer").put(
f"/api/v1/sensor-placement-runs/{RUN_ID}",
params={"network": "tjwater"},
json={
"expected_sensor_locations": ["J1"],
"sensor_locations": ["J2"],
},
)
assert response.status_code == 403
def test_export_returns_xlsx(monkeypatch):
monkeypatch.setattr(endpoint, "get_sensor_placement_run", lambda *_: _run())
monkeypatch.setattr(
endpoint,
"build_sensor_placement_workbook",
lambda **kwargs: BytesIO(b"xlsx"),
)
response = _client().post(
f"/api/v1/sensor-placement-runs/{RUN_ID}/exports/excel",
params={"network": "tjwater"},
json={"sensor_locations": ["J1"], "adjustment_status": {}},
)
assert response.status_code == 200
assert response.content == b"xlsx"
assert response.headers["content-type"].startswith(
"application/vnd.openxmlformats-officedocument"
)