Files
geointel/backend/tests/test_sprint181_mol_municipality_workspace.py
T
JensandClaude Opus 5 6572e4ad5f scope frontend contracts to the feature, not to one file
93 test files read a single frontend source and asserted identifiers in it. The
MapWorkspace split showed what that costs: 24 tests went red for a move that
changed no behaviour at all. A contract belongs to the feature — a container,
its hooks, its domain layer — not to whichever file currently holds it.

232 read sites now resolve through read_feature(). The distinction that makes
this safe is direction: a *positive* contract ("this is wired") may widen,
because the identifier must still exist somewhere in the feature; a *negative*
one ("this component performs no transport") is a statement about one file, and
widening it would quietly weaken the check. The 73 single-file reads that
remain are exactly those, and a guard now enforces the rule for new tests.

Verified rather than assumed: of the 732 migrated positive assertions, 644 still
match exactly one module — as specific as before — and the other 86 already
spanned a container and its hook by nature. Two apparent misses are an artefact
of the checking regex reading an escaped newline literally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 22:05:43 +02:00

164 lines
6.4 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
from tests.frontend_contract import read_feature
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_remains_a_regression_fixture_without_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 = read_feature("datasets")
map_source = (ROOT / "frontend" / "src" / "components" / "GeoMap.tsx").read_text(encoding="utf-8")
map_workspace = read_feature("map_workspace")
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)" not in project_hook
assert "return nationalProject.id" 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