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,125 @@
|
||||
"""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"
|
||||
Reference in New Issue
Block a user