Files
geointel/backend/tests/test_rc4_national_scope_operator.py
T
Codex 1e527bf810
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s
Add Belgium and North Sea coverage foundation
2026-07-18 01:45:00 +02:00

162 lines
5.4 KiB
Python

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
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_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 "from app.models" not in source
assert "INSERT INTO vector_features" not in source