"""GET /api/infrastructure — Overpass nuclear markers.""" import asyncio import httpx from live_layers import ( normalize_infra_element, overlay_catalog, overpass_nuclear_to_markers, _cache, ) from main import app BASE = "http://test" OVERPASS = { "version": 0.6, "generator": "Overpass API", "elements": [ { "type": "node", "id": 12345, "lat": 44.0, "lon": -1.5, "tags": {"name": "Test NPP", "operator": "EDF", "plant:source": "nuclear"}, }, { "type": "way", "id": 67890, "center": {"lat": 43.5, "lon": -1.25}, "tags": {"name": "Test Plant Way", "plant:source": "nuclear"}, }, { "type": "relation", "id": 999, "center": {"lat": 43.0, "lon": -1.0}, "tags": {}, }, ], } async def _get(path: str) -> httpx.Response: transport = httpx.ASGITransport(app=app) async with httpx.AsyncClient(transport=transport, base_url=BASE) as client: return await client.get(path) def test_normalize_node_to_marker(): m = normalize_infra_element(OVERPASS["elements"][0], "nuclear") assert m["id"] == "node/12345" assert m["name"] == "Test NPP" assert m["lat"] == 44.0 assert m["lon"] == -1.5 assert m["type"] == "nuclear" assert m["extra"]["operator"] == "EDF" assert "name" not in m["extra"] def test_way_center_and_unnamed_fallback(): way = normalize_infra_element(OVERPASS["elements"][1], "nuclear") assert way["lat"] == 43.5 assert way["lon"] == -1.25 rel = normalize_infra_element(OVERPASS["elements"][2], "nuclear") assert rel["name"] == "relation/999" def test_overpass_json_to_markers(): markers = overpass_nuclear_to_markers(OVERPASS) assert len(markers) == 3 assert markers[0]["id"] == "node/12345" def test_missing_bbox_400(): resp = asyncio.run(_get("/api/infrastructure?types=nuclear")) assert resp.status_code == 400 def test_unknown_type_422(): resp = asyncio.run(_get("/api/infrastructure?types=military&bbox=-2,43,-1,44")) assert resp.status_code == 422 def test_map_infrastructure_returns_markers(monkeypatch): async def fake_fetch(types, bbox): return [ {"id": "node/1", "name": "X", "lat": 1.0, "lon": 2.0, "type": "nuclear", "extra": {}} ] monkeypatch.setattr("main.fetch_infrastructure", fake_fetch) resp = asyncio.run(_get("/api/infrastructure?types=nuclear&bbox=-2,43,-1,44")) assert resp.status_code == 200 body = resp.json() assert body[0]["name"] == "X" assert body[0]["type"] == "nuclear" assert "max-age" in (resp.headers.get("cache-control") or "").lower() def test_overlay_catalog_has_infra_nuclear(): entry = overlay_catalog()["infra_nuclear"] assert entry["kind"] == "points" assert "nuclear" in entry["endpoint"] def test_fetch_infrastructure_cache_hit_no_refetch(monkeypatch): _cache.clear() hits = {"n": 0} class FakeResp: def raise_for_status(self): pass def json(self): return OVERPASS class FakeClient: def __init__(self, **kw): pass async def __aenter__(self): return self async def __aexit__(self, *exc): return False async def post(self, url, data=None, timeout=None): hits["n"] += 1 assert "overpass-api.de" in url assert "plant:source" in data["data"] assert "nuclear" in data["data"] return FakeResp() monkeypatch.setattr("live_layers.httpx.AsyncClient", FakeClient) monkeypatch.setattr("live_layers._http", None) from live_layers import fetch_infrastructure m1 = asyncio.run(fetch_infrastructure("nuclear", "-2,43,-1,44")) m2 = asyncio.run(fetch_infrastructure("nuclear", "-2,43,-1,44")) assert len(m1) == 3 assert m2 == m1 assert hits["n"] == 1 _cache.clear()