Initial public release
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
from pyproj import Transformer
|
||||
import rasterio
|
||||
from rasterio.transform import from_origin
|
||||
from shapely.geometry import Polygon, shape
|
||||
from shapely.ops import transform
|
||||
from tests.frontend_contract import read_map_workspace
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def load_provisioner():
|
||||
script_path = ROOT / "scripts" / "provision_official_landuse_timeseries.py"
|
||||
spec = importlib.util.spec_from_file_location("official_landuse_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 test_official_landuse_wcs_contract_is_categorical_and_deterministic() -> None:
|
||||
module = load_provisioner()
|
||||
|
||||
params = module.build_wcs_params(2025, (196594.1, 205064.2, 210910.7, 223974.9))
|
||||
|
||||
assert module.SUPPORTED_YEARS == (2013, 2016, 2019, 2022, 2025)
|
||||
assert module.LAND_USE_CLASSES[12] == "Bos"
|
||||
assert params == {
|
||||
"SERVICE": "WCS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetCoverage",
|
||||
"COVERAGE": "lu:lu_landgebruik_vlaa_2025_v3",
|
||||
"CRS": "EPSG:31370",
|
||||
"BBOX": "196590.000,205060.000,210920.000,223980.000",
|
||||
"RESX": "10",
|
||||
"RESY": "10",
|
||||
"FORMAT": "image/tiff",
|
||||
"RESPONSE_CRS": "EPSG:31370",
|
||||
}
|
||||
assert module.series_key(module.THEMES[0], "Mol") == "department-omgeving:land-use:forest:mol"
|
||||
|
||||
|
||||
def test_official_landuse_polygonization_clips_and_preserves_provenance(tmp_path: Path) -> None:
|
||||
module = load_provisioner()
|
||||
raster_path = tmp_path / "landuse.tif"
|
||||
values = np.array(
|
||||
[
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 12, 12, 1, 1, 1],
|
||||
[1, 12, 12, 1, 12, 1],
|
||||
[1, 1, 1, 1, 12, 1],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1, 1],
|
||||
],
|
||||
dtype="int32",
|
||||
)
|
||||
with rasterio.open(
|
||||
raster_path,
|
||||
"w",
|
||||
driver="GTiff",
|
||||
width=6,
|
||||
height=6,
|
||||
count=1,
|
||||
dtype="int32",
|
||||
crs="EPSG:31370",
|
||||
transform=from_origin(200000, 210000, 10, 10),
|
||||
nodata=-9999,
|
||||
) as destination:
|
||||
destination.write(values, 1)
|
||||
|
||||
to_wgs84 = Transformer.from_crs(31370, 4326, always_xy=True)
|
||||
boundary_metric = Polygon(
|
||||
[(200005, 209945), (200055, 209945), (200055, 209995), (200005, 209995), (200005, 209945)]
|
||||
)
|
||||
boundary = transform(to_wgs84.transform, boundary_metric)
|
||||
|
||||
payload, stats = module.polygonize_snapshot(
|
||||
raster_path=raster_path,
|
||||
boundary=boundary,
|
||||
year=2025,
|
||||
theme=module.THEMES[0],
|
||||
municipality_name="Mol",
|
||||
nis_code="13025",
|
||||
scope_key="mol",
|
||||
max_features=100,
|
||||
)
|
||||
|
||||
assert payload["type"] == "FeatureCollection"
|
||||
assert payload["crs"]["properties"]["name"] == "EPSG:4326"
|
||||
assert payload["source_coverage_id"] == "lu:lu_landgebruik_vlaa_2025_v3"
|
||||
assert stats["source_pixel_count"] == 6
|
||||
assert stats["source_pixel_area_m2"] == 600
|
||||
assert stats["feature_count"] == 2
|
||||
assert 0 < stats["polygon_area_m2"] <= 600
|
||||
assert stats["class_histogram"] == {"1": 30, "12": 6}
|
||||
for feature in payload["features"]:
|
||||
geometry = shape(feature["geometry"])
|
||||
properties = feature["properties"]
|
||||
assert geometry.is_valid
|
||||
assert geometry.within(boundary.buffer(1e-9))
|
||||
assert properties["source_name"] == "department_omgeving_land_use"
|
||||
assert properties["land_use_class_ids"] == [12]
|
||||
assert properties["source_resolution_m"] == 10.0
|
||||
assert properties["source_raster_sha256"] == stats["raster_sha256"]
|
||||
|
||||
|
||||
def test_official_landuse_metadata_keeps_modern_series_separate(tmp_path: Path) -> None:
|
||||
module = load_provisioner()
|
||||
theme = module.THEMES[0]
|
||||
snapshot = module.PreparedSnapshot(
|
||||
year=2022,
|
||||
theme=theme,
|
||||
raster_path=tmp_path / "source.tif",
|
||||
vector_path=tmp_path / "forest.geojson",
|
||||
manifest_path=tmp_path / "forest.manifest.json",
|
||||
feature_count=42,
|
||||
raster_sha256="a" * 64,
|
||||
vector_sha256="b" * 64,
|
||||
)
|
||||
args = SimpleNamespace(scope_key="mol", municipality_name="Mol", nis_code="13025")
|
||||
|
||||
source = module.build_source_metadata(args, snapshot)
|
||||
provenance = module.build_provenance_metadata(args, snapshot)
|
||||
|
||||
assert source["temporal_series_label"] == "Moderne landgebruikskaart (10 m)"
|
||||
assert source["selection_aggregation"]["method"] == "intersection_area"
|
||||
assert source["identity_stable"] is False
|
||||
assert source["land_use_class_names"] == ["Bos"]
|
||||
assert "10 m" in source["selection_aggregation"]["warning"]
|
||||
assert provenance["operator_explicit_fetch"] is True
|
||||
assert provenance["coverage_id"] == "lu:lu_landgebruik_vlaa_2022_v3"
|
||||
assert "historical-landuse" not in module.series_key(theme, "mol")
|
||||
|
||||
|
||||
def test_official_landuse_operator_paginates_within_api_limit() -> None:
|
||||
module = load_provisioner()
|
||||
|
||||
class Response:
|
||||
ok = True
|
||||
status_code = 200
|
||||
text = ""
|
||||
|
||||
def __init__(self, payload):
|
||||
self.payload = payload
|
||||
|
||||
def json(self):
|
||||
return {"data": self.payload}
|
||||
|
||||
class Session:
|
||||
def __init__(self) -> None:
|
||||
self.calls = []
|
||||
|
||||
def get(self, url, *, params, timeout):
|
||||
self.calls.append((url, params, timeout))
|
||||
offset = params["offset"]
|
||||
page_items = [{"id": index} for index in range(offset, min(offset + 200, 405))]
|
||||
return Response({"items": page_items, "total": 405, "limit": 200, "offset": offset})
|
||||
|
||||
session = Session()
|
||||
items = module.list_paginated_items(session, "http://backend/api/v1/projects", timeout=30)
|
||||
|
||||
assert len(items) == 405
|
||||
assert [call[1] for call in session.calls] == [
|
||||
{"limit": 200, "offset": 0},
|
||||
{"limit": 200, "offset": 200},
|
||||
{"limit": 200, "offset": 400},
|
||||
]
|
||||
|
||||
|
||||
def test_official_landuse_operator_is_packaged_and_readiness_checked() -> 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")
|
||||
workspace = read_map_workspace()
|
||||
geo_map = (ROOT / "frontend/src/components/GeoMap.tsx").read_text(encoding="utf-8")
|
||||
premium_css = (ROOT / "frontend/src/styles/premium.css").read_text(encoding="utf-8")
|
||||
|
||||
assert "py_compile scripts/provision_official_landuse_timeseries.py" in readiness
|
||||
assert "COPY scripts/provision_official_landuse_timeseries.py" in dockerfile
|
||||
assert "department_omgeving_land_use' ? 90_000" in workspace
|
||||
assert "activeTemporalSeriesGroups.length > 1" in workspace
|
||||
assert "dataFillColor={activeThemeMapStyle.fill}" in workspace
|
||||
assert "forest: { fill: '#347950', line: '#225f3b' }" in workspace
|
||||
assert "datasetFillColor(dataFillColor)" in geo_map
|
||||
assert ".workbench-main > .geo-explorer" in premium_css
|
||||
assert "Moderne landgebruikskaart (10 m)" in (ROOT / "scripts/provision_official_landuse_timeseries.py").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
Reference in New Issue
Block a user