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
126 lines
4.7 KiB
Python
126 lines
4.7 KiB
Python
"""A downloaded export must carry its own provenance and its own limits.
|
|
|
|
Counterpart to ``test_export_provenance_member``: this reads the file the
|
|
service actually writes, so it proves the member survives serialisation rather
|
|
than only that the helper builds it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from uuid import uuid4
|
|
|
|
from app.models import Dataset, Export
|
|
from app.services.export_service import ExportService
|
|
from app.services.storage_service import StorageService
|
|
from app.services.vector_feature_service import VectorFeatureService
|
|
|
|
from tests.test_sprint107_map_selection_export import FakeSession, _govern_fixture_dataset
|
|
|
|
|
|
BBOX = {"min_x": 4.9, "min_y": 50.9, "max_x": 5.2, "max_y": 51.2, "crs": "EPSG:4326"}
|
|
|
|
|
|
def _dataset(dataset_id):
|
|
dataset = _govern_fixture_dataset(
|
|
Dataset(
|
|
id=dataset_id,
|
|
project_id=uuid4(),
|
|
name="grb-buildings.geojson",
|
|
dataset_type="vector",
|
|
source="grb",
|
|
source_name="grb",
|
|
source_version="2024-06",
|
|
observed_at=datetime(2024, 6, 1, tzinfo=timezone.utc),
|
|
status="ready",
|
|
)
|
|
)
|
|
return dataset
|
|
|
|
|
|
def _selection(*, feature_count: int, total: int, truncated: bool, warning: str | None = None):
|
|
return {
|
|
"selection_bbox": BBOX,
|
|
"feature_count": feature_count,
|
|
"total_feature_count": total,
|
|
"limit": 250,
|
|
"truncated": truncated,
|
|
"summary": {"selection_edge_warning": warning} if warning else {},
|
|
"geojson": {
|
|
"type": "FeatureCollection",
|
|
"features": [
|
|
{
|
|
"type": "Feature",
|
|
"geometry": {"type": "Point", "coordinates": [5.0, 51.0]},
|
|
"properties": {"vector_feature_id": f"vf-{index}"},
|
|
}
|
|
for index in range(feature_count)
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def _export(monkeypatch, tmp_path: Path, selection) -> dict:
|
|
dataset_id = uuid4()
|
|
dataset = _dataset(dataset_id)
|
|
db = FakeSession({(Dataset, dataset_id): dataset})
|
|
export_path = tmp_path / "selection.geojson"
|
|
monkeypatch.setattr(StorageService, "dataset_export_path", lambda *_args: str(export_path))
|
|
monkeypatch.setattr(VectorFeatureService, "select_features_by_bbox", lambda *_args, **_kwargs: selection)
|
|
|
|
ExportService.export_vector_selection_geojson(db, dataset_id, BBOX, limit=250, name="selection")
|
|
|
|
assert [item for item in db.added if isinstance(item, Export)]
|
|
return json.loads(export_path.read_text(encoding="utf-8"))
|
|
|
|
|
|
def test_a_truncated_export_file_states_that_it_is_partial(monkeypatch, tmp_path: Path) -> None:
|
|
written = _export(monkeypatch, tmp_path, _selection(feature_count=2, total=1_400, truncated=True))
|
|
|
|
provenance = written["geointel_provenance"]
|
|
assert provenance["complete"] is False
|
|
assert "1400" in provenance["completeness_note"].replace(".", "")
|
|
# The features are still there; the file simply no longer implies it holds
|
|
# everything the selection contains.
|
|
assert len(written["features"]) == 2
|
|
|
|
|
|
def test_a_complete_export_file_says_so(monkeypatch, tmp_path: Path) -> None:
|
|
written = _export(monkeypatch, tmp_path, _selection(feature_count=2, total=2, truncated=False))
|
|
|
|
provenance = written["geointel_provenance"]
|
|
assert provenance["complete"] is True
|
|
assert provenance["completeness_note"] is None
|
|
|
|
|
|
def test_the_file_identifies_its_source_edition(monkeypatch, tmp_path: Path) -> None:
|
|
written = _export(monkeypatch, tmp_path, _selection(feature_count=1, total=1, truncated=False))
|
|
|
|
provenance = written["geointel_provenance"]
|
|
assert provenance["source_name"] == "grb"
|
|
assert provenance["source_version"] == "2024-06"
|
|
assert provenance["observed_at"].startswith("2024-06-01")
|
|
assert provenance["selection_bbox"] == BBOX
|
|
|
|
|
|
def test_selection_caveats_travel_into_the_file(monkeypatch, tmp_path: Path) -> None:
|
|
written = _export(
|
|
monkeypatch,
|
|
tmp_path,
|
|
_selection(feature_count=1, total=1, truncated=False, warning="22 objecten liggen deels buiten de selectie."),
|
|
)
|
|
|
|
assert written["geointel_provenance"]["warnings"] == ["22 objecten liggen deels buiten de selectie."]
|
|
|
|
|
|
def test_the_file_remains_a_valid_feature_collection(monkeypatch, tmp_path: Path) -> None:
|
|
"""The provenance is a foreign member, not a change to the GeoJSON shape."""
|
|
|
|
written = _export(monkeypatch, tmp_path, _selection(feature_count=1, total=1, truncated=False))
|
|
|
|
assert written["type"] == "FeatureCollection"
|
|
assert isinstance(written["features"], list)
|
|
assert written["features"][0]["type"] == "Feature"
|