Files
geointel/backend/tests/test_sprint181_mol_municipality_workspace.py
T
Codex e8a35b96ad
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s
fix: retry transient official source failures
2026-07-14 05:47:06 +02:00

162 lines
6.5 KiB
Python

from __future__ import annotations
import importlib.util
from pathlib import Path
import sys
from uuid import uuid4
import pytest
from shapely.geometry import Polygon, shape
from app.models import VectorFeature
from app.services.vector_feature_service import VectorFeatureService
ROOT = Path(__file__).resolve().parents[2]
def load_provisioner():
script_path = ROOT / "scripts" / "provision_mol_municipality_workspace.py"
spec = importlib.util.spec_from_file_location("mol_municipality_provisioner", script_path)
assert spec is not None
assert spec.loader is not None
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
def feature(feature_id: str, coordinates: list[list[list[float]]]):
return {
"type": "Feature",
"id": feature_id,
"geometry": {"type": "Polygon", "coordinates": coordinates},
"properties": {"UIDN": feature_id},
}
def test_mol_provisioner_uses_official_identity_and_exact_boundary_clipping() -> None:
module = load_provisioner()
boundary = Polygon([(5.0, 51.0), (5.2, 51.0), (5.2, 51.2), (5.0, 51.2), (5.0, 51.0)])
inside = feature("GBG.inside", [[[5.05, 51.05], [5.1, 51.05], [5.1, 51.1], [5.05, 51.1], [5.05, 51.05]]])
crossing = feature("GBG.crossing", [[[5.18, 51.08], [5.22, 51.08], [5.22, 51.12], [5.18, 51.12], [5.18, 51.08]]])
outside = feature("GBG.outside", [[[5.3, 51.3], [5.31, 51.3], [5.31, 51.31], [5.3, 51.31], [5.3, 51.3]]])
pages = [
(
{"type": "FeatureCollection", "features": [inside, crossing, outside, inside]},
"https://geo.api.vlaanderen.be/GRB/page-1",
)
]
buildings, summary = module.build_municipality_buildings(pages, boundary, max_features=10)
assert module.MUNICIPALITY_NIS_CODE == "13025"
assert module.PROJECT_NAME == "Mol Municipality Workbench"
assert module.GEOJSON_CRS == {"type": "name", "properties": {"name": "EPSG:4326"}}
assert len(buildings) == 2
assert summary["bbox_feature_count"] == 3
assert summary["outside_boundary_count"] == 1
assert summary["clipped_at_boundary_count"] == 1
assert summary["reference_truncated"] is False
assert all(shape(item["geometry"]).within(boundary) for item in buildings)
assert buildings[0]["properties"]["coverage_scope"] == "municipality"
assert buildings[0]["properties"]["source_name"] == "grb"
assert buildings[0]["properties"]["reference_layer_name"] == "buildings"
assert buildings[1]["properties"]["clipped_to_municipality"] is True
def test_mol_provisioner_refuses_a_truncated_municipality_dataset() -> None:
module = load_provisioner()
boundary = Polygon([(5.0, 51.0), (5.2, 51.0), (5.2, 51.2), (5.0, 51.2), (5.0, 51.0)])
pages = [
(
{
"type": "FeatureCollection",
"features": [
feature("GBG.1", [[[5.01, 51.01], [5.02, 51.01], [5.02, 51.02], [5.01, 51.02], [5.01, 51.01]]]),
feature("GBG.2", [[[5.03, 51.03], [5.04, 51.03], [5.04, 51.04], [5.03, 51.04], [5.03, 51.03]]]),
],
},
"https://geo.api.vlaanderen.be/GRB/page-1",
)
]
with pytest.raises(RuntimeError, match="refusing a truncated municipality dataset"):
module.build_municipality_buildings(pages, boundary, max_features=1)
def test_mol_source_session_retries_only_safe_get_requests() -> None:
module = load_provisioner()
with module.build_source_session() as session:
retry = session.get_adapter("https://").max_retries
assert retry.total == 5
assert retry.allowed_methods == frozenset({"GET"})
assert set(retry.status_forcelist) == {429, 500, 502, 503, 504}
def test_large_vector_persistence_flushes_once_without_per_feature_refresh() -> None:
class FakeSession:
def __init__(self) -> None:
self.added = []
self.flushes = 0
self.commits = 0
self.refreshes = 0
def add(self, item) -> None:
self.added.append(item)
def flush(self) -> None:
self.flushes += 1
def commit(self) -> None:
self.commits += 1
def refresh(self, _item) -> None:
self.refreshes += 1
payload = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": f"GBG.{index}",
"properties": {"layer_type": "building"},
"geometry": {
"type": "Polygon",
"coordinates": [[[5.0, 51.0], [5.001, 51.0], [5.001, 51.001], [5.0, 51.001], [5.0, 51.0]]],
},
}
for index in range(250)
],
}
db = FakeSession()
persisted = VectorFeatureService.persist_geojson_features(db, uuid4(), payload, feature_class="buildings")
assert len(persisted) == 250
assert all(isinstance(item, VectorFeature) for item in persisted)
assert db.flushes == 1
assert db.commits == 1
assert db.refreshes == 0
def test_municipality_workspace_is_wired_into_runtime_and_frontend_priority() -> None:
readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8")
dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8")
focus = (ROOT / "frontend" / "src" / "config" / "primaryFocus.ts").read_text(encoding="utf-8")
project_hook = (ROOT / "frontend" / "src" / "hooks" / "useProjectWorkspace.ts").read_text(encoding="utf-8")
dataset_hook = (ROOT / "frontend" / "src" / "hooks" / "useDatasetWorkflow.ts").read_text(encoding="utf-8")
map_source = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
map_workspace = (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
assert "py_compile scripts/provision_mol_municipality_workspace.py" in readiness
assert "COPY scripts/provision_mol_municipality_workspace.py" in dockerfile
assert "PRIMARY_FOCUS_MUNICIPALITY_PROJECT_NAME = 'Mol Municipality Workbench'" in focus
assert "items.find(isPrimaryFocusMunicipalityProject)" in project_hook
assert "datasets.find(isPrimaryFocusMunicipalityBoundaryDataset)" in dataset_hook
assert "featureCollectionBounds(featureCollection)" in map_source
assert "useMemo(() => getFeatureCollectionBBox(mapFeatureCollection)" in map_workspace
assert "Math.min(...xs)" not in map_source