feat(provenance): govern source snapshots and data inputs
This commit is contained in:
@@ -18,7 +18,7 @@ from app.core.config import Settings
|
||||
from app.core.errors import AppError
|
||||
from app.db.session import get_db
|
||||
from app.main import app
|
||||
from app.models import Area, Dataset, DatasetVersion, Job, Project
|
||||
from app.models import Area, Dataset, DatasetVersion, Job, Project, SourceRegistry, SourceSnapshot
|
||||
from app.schemas.orthophoto import OrthophotoAcquireRequest
|
||||
from app.services.orthophoto_acquisition_service import OrthophotoAcquisitionService
|
||||
|
||||
@@ -41,6 +41,15 @@ class FakeSession:
|
||||
def add(self, row):
|
||||
self.added.append(row)
|
||||
|
||||
def flush(self):
|
||||
# The governed importer persists source identities and immutable
|
||||
# snapshots before the Dataset. Mirror the database-generated UUIDs
|
||||
# so this harness exercises that Phase 2 path rather than the legacy
|
||||
# no-registry fallback.
|
||||
for row in self.added:
|
||||
if getattr(row, "id", None) is None:
|
||||
row.id = uuid4()
|
||||
|
||||
def commit(self):
|
||||
return None
|
||||
|
||||
@@ -50,13 +59,23 @@ class FakeSession:
|
||||
def refresh(self, row):
|
||||
return row
|
||||
|
||||
def query(self, _model):
|
||||
return FakeQuery(self.query_result)
|
||||
def query(self, model):
|
||||
rows = [
|
||||
row
|
||||
for (row_model, _row_id), row in self.rows.items()
|
||||
if row_model is model and isinstance(row, model)
|
||||
]
|
||||
rows.extend(row for row in self.added if isinstance(row, model))
|
||||
if isinstance(self.query_result, model):
|
||||
rows.append(self.query_result)
|
||||
elif isinstance(self.query_result, list):
|
||||
rows.extend(row for row in self.query_result if isinstance(row, model))
|
||||
return FakeQuery(rows)
|
||||
|
||||
|
||||
class FakeQuery:
|
||||
def __init__(self, result):
|
||||
self.result = result
|
||||
def __init__(self, results):
|
||||
self.results = list(results)
|
||||
|
||||
def filter(self, *_args):
|
||||
return self
|
||||
@@ -65,7 +84,10 @@ class FakeQuery:
|
||||
return self
|
||||
|
||||
def first(self):
|
||||
return self.result
|
||||
return self.results[0] if self.results else None
|
||||
|
||||
def one_or_none(self):
|
||||
return self.first()
|
||||
|
||||
|
||||
class FakeImageResponse:
|
||||
@@ -222,12 +244,23 @@ def test_regional_orthophoto_products_bind_provider_and_governed_scope(
|
||||
)
|
||||
|
||||
dataset = next(row for row in db.added if isinstance(row, Dataset))
|
||||
source = next(row for row in db.added if isinstance(row, SourceRegistry))
|
||||
snapshot = next(row for row in db.added if isinstance(row, SourceSnapshot))
|
||||
assert result["provider"] == provider
|
||||
assert result["layer"] == layer
|
||||
assert dataset.source_name == provider
|
||||
assert dataset.source_metadata["coverage_zone"] == coverage_zone
|
||||
assert dataset.source_metadata["license_note"]
|
||||
assert dataset.provenance_metadata["request_url"].startswith(prepared["product"].wms_url)
|
||||
assert dataset.source_registry_id == source.id
|
||||
assert dataset.source_snapshot_id == snapshot.id
|
||||
assert dataset.validation_status == "passed"
|
||||
assert dataset.provenance_status == "complete"
|
||||
assert dataset.quarantine_status == "not_quarantined"
|
||||
assert snapshot.source_registry_id == source.id
|
||||
assert snapshot.checksum_sha256 == dataset.checksum_sha256
|
||||
assert snapshot.ingest_status == "ingested"
|
||||
assert snapshot.freshness_status == "current"
|
||||
|
||||
prepared = OrthophotoAcquisitionService._prepared_request(_selection_payload(product_key="1971"), settings)
|
||||
assert prepared["params"]["LAYERS"] == "OKZPAN71VL"
|
||||
@@ -291,6 +324,8 @@ def test_orthophoto_acquisition_persists_georeferenced_raster_and_provenance(tmp
|
||||
assert len(datasets) == 1
|
||||
assert len(versions) == 1
|
||||
dataset = datasets[0]
|
||||
source = next(row for row in db.added if isinstance(row, SourceRegistry))
|
||||
snapshot = next(row for row in db.added if isinstance(row, SourceSnapshot))
|
||||
assert result["output_dataset_id"] == str(dataset.id)
|
||||
assert result["reused"] is False
|
||||
assert dataset.project_id == project_id
|
||||
@@ -301,6 +336,15 @@ def test_orthophoto_acquisition_persists_georeferenced_raster_and_provenance(tmp
|
||||
assert dataset.crs == "EPSG:31370"
|
||||
assert dataset.provenance_metadata["acquisition"] == "explicit_bounded_map_selection"
|
||||
assert dataset.provenance_metadata["request_hash"] == prepared["request_hash"]
|
||||
assert dataset.source_registry_id == source.id
|
||||
assert dataset.source_snapshot_id == snapshot.id
|
||||
assert dataset.validation_status == "passed"
|
||||
assert dataset.provenance_status == "complete"
|
||||
assert dataset.lineage_status == "not_applicable"
|
||||
assert dataset.quarantine_status == "not_quarantined"
|
||||
assert snapshot.source_registry_id == source.id
|
||||
assert snapshot.checksum_sha256 == dataset.checksum_sha256
|
||||
assert snapshot.freshness_status == "current"
|
||||
assert dataset.source_metadata["attribution"].startswith("Bron: Orthofotomozaiek Vlaanderen")
|
||||
assert dataset.storage_path is not None
|
||||
with rasterio.open(dataset.storage_path) as stored:
|
||||
|
||||
Reference in New Issue
Block a user