from __future__ import annotations import json import sys import zipfile from pathlib import Path import pytest from shapely.geometry import box, mapping, shape ROOT = Path(__file__).parents[2] SCRIPTS = ROOT / "scripts" if str(SCRIPTS) not in sys.path: sys.path.insert(0, str(SCRIPTS)) import provision_belgium_north_sea_scope as operator # noqa: E402 from app.utils.geometry import normalize_to_multipolygon # noqa: E402 def marine_feature(identifier: str, geometry): return { "type": "Feature", "id": identifier, "geometry": mapping(geometry), "properties": {"MarineReportingUnitId": identifier}, } def test_marine_legal_scopes_are_derived_from_official_reporting_units() -> None: reporting_units = { "type": "FeatureCollection", "features": [ marine_feature("ANS-BE-MS-1", box(0, 0, 10, 10)), marine_feature("ANS-BE-AA-CW", box(0, 0, 2, 2)), marine_feature("ANS-BE-AA-TEW", box(0, 2, 2, 4)), marine_feature("ANS-BE-AA-OFFSHORE", box(2, 0, 10, 10)), ], } payload = operator.derive_marine_scope_payload(reporting_units) by_zone = { feature["properties"]["coverage_zone"]: feature for feature in payload["features"] } assert set(by_zone) == { "belgian_north_sea", "territorial_sea", "exclusive_economic_zone", "continental_shelf", } assert shape(by_zone["territorial_sea"]["geometry"]).area == pytest.approx(8.0) assert shape(by_zone["exclusive_economic_zone"]["geometry"]).equals( shape(by_zone["continental_shelf"]["geometry"]) ) assert ( by_zone["exclusive_economic_zone"]["properties"]["legal_domain"] != by_zone["continental_shelf"]["properties"]["legal_domain"] ) assert by_zone["territorial_sea"]["properties"]["derived_from_reporting_unit_ids"] == [ "ANS-BE-AA-CW", "ANS-BE-AA-TEW", ] def test_marine_scope_derivation_fails_when_a_required_unit_is_missing() -> None: with pytest.raises(RuntimeError, match="ANS-BE-AA-CW"): operator.derive_marine_scope_payload( { "type": "FeatureCollection", "features": [ marine_feature("ANS-BE-MS-1", box(0, 0, 10, 10)), marine_feature("ANS-BE-AA-TEW", box(0, 2, 2, 4)), marine_feature("ANS-BE-AA-OFFSHORE", box(2, 0, 10, 10)), ], } ) def test_area_geometry_normalization_drops_source_z_dimension() -> None: geometry = normalize_to_multipolygon( { "type": "Polygon", "coordinates": [ [ [2.5, 49.5, 0], [6.4, 49.5, 0], [6.4, 51.5, 0], [2.5, 51.5, 0], [2.5, 49.5, 0], ] ], } ) assert geometry.has_z is False assert geometry.geom_type == "MultiPolygon" def test_archive_extraction_accepts_one_safe_geopackage_and_rejects_traversal(tmp_path: Path) -> None: archive = tmp_path / "adminvector.zip" with zipfile.ZipFile(archive, "w") as handle: handle.writestr("release/adminvector.gpkg", b"sqlite-bytes") result = operator.extract_single_geopackage(archive, tmp_path / "output") assert result.read_bytes() == b"sqlite-bytes" unsafe = tmp_path / "unsafe.zip" with zipfile.ZipFile(unsafe, "w") as handle: handle.writestr("../adminvector.gpkg", b"unsafe") with pytest.raises(RuntimeError, match="unsafe"): operator.extract_single_geopackage(unsafe, tmp_path / "unsafe-output") class FakeResponse: def __init__(self, payload): self.payload = payload self.content = json.dumps(payload).encode("utf-8") def raise_for_status(self): return None def json(self): return self.payload class FakeSession: def __init__(self, pages): self.pages = list(pages) self.calls = [] def get(self, url, params, timeout): self.calls.append({"url": url, "params": params, "timeout": timeout}) return FakeResponse(self.pages.pop(0)) def test_wfs_fetch_is_allowlisted_paginated_and_complete() -> None: pages = [ { "type": "FeatureCollection", "numberMatched": 2, "features": [{"type": "Feature", "id": "unit.1", "geometry": None, "properties": {}}], }, { "type": "FeatureCollection", "numberMatched": 2, "features": [{"type": "Feature", "id": "unit.2", "geometry": None, "properties": {}}], }, ] session = FakeSession(pages) payload = operator.fetch_wfs_layer( session, service_url=operator.RBINS_MRU_WFS_URL, layer_name=operator.RBINS_MRU_LAYER, timeout=30, page_size=1, ) assert [feature["id"] for feature in payload["features"]] == ["unit.1", "unit.2"] assert [call["params"]["startIndex"] for call in session.calls] == [0, 1] assert all(call["params"]["srsName"] == "EPSG:4326" for call in session.calls) with pytest.raises(RuntimeError, match="allowlist"): operator.fetch_wfs_layer( FakeSession([]), service_url=operator.RBINS_MSP_WFS_URL, layer_name="untrusted:layer", timeout=30, ) def test_operator_is_packaged_and_guarded_by_readiness() -> None: dockerfile = (ROOT / "deploy" / "unraid" / "Dockerfile.all-in-one").read_text(encoding="utf-8") readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text(encoding="utf-8") source = (ROOT / "scripts" / "provision_belgium_north_sea_scope.py").read_text(encoding="utf-8") assert "COPY scripts/provision_belgium_north_sea_scope.py /app/scripts/" in dockerfile assert "py_compile scripts/provision_belgium_north_sea_scope.py" in readiness assert "/datasets/upload" in source assert "frame.to_json(drop_id=False, default=str)" in source assert "from app.models" not in source assert "INSERT INTO vector_features" not in source