from __future__ import annotations from pathlib import Path import pytest from shapely.geometry import box from app.core.errors import AppError from app.services.aoi_operation_executor import AoiOperationExecutor from app.services.aoi_operation_service import AoiOperationService ROOT = Path(__file__).resolve().parents[2] def test_partition_plan_covers_aoi_without_overlapping_area() -> None: aoi = box(0, 0, 25_000, 18_000) partitions = AoiOperationService._partition(aoi, 10_000) assert len(partitions) == 6 assert sum(partition.area for partition in partitions) == pytest.approx(aoi.area) assert all(partition.within(aoi) for partition in partitions) for index, partition in enumerate(partitions): for other in partitions[index + 1 :]: assert partition.intersection(other).area == pytest.approx(0.0) def test_partition_plan_intersects_irregular_aoi_exactly() -> None: aoi = box(0, 0, 20_000, 20_000).difference(box(5_000, 5_000, 15_000, 15_000)) partitions = AoiOperationService._partition(aoi, 8_000) assert sum(partition.area for partition in partitions) == pytest.approx(aoi.area) assert all(not partition.intersects(box(5_001, 5_001, 14_999, 14_999)) for partition in partitions) def test_partition_plan_fails_before_unbounded_fanout(monkeypatch) -> None: monkeypatch.setattr(AoiOperationService, "MAX_PARTITIONS", 4) with pytest.raises(AppError) as exc_info: AoiOperationService._partition(box(0, 0, 30_000, 30_000), 10_000) assert exc_info.value.code == "AOI_PARTITION_LIMIT_EXCEEDED" assert exc_info.value.details["candidate_count"] == 9 def test_executor_retries_only_transient_provider_failures() -> None: assert AoiOperationExecutor._retryable(AppError(code="UPSTREAM_UNAVAILABLE", message="down", status_code=503)) is True assert AoiOperationExecutor._retryable(AppError(code="INVALID_SCOPE", message="bad", status_code=422)) is False def test_provider_budget_is_automatic_and_override_can_only_be_stricter() -> None: governed = AoiOperationService._partition_side("grb", None) assert governed > 0 assert AoiOperationService._partition_side("grb", governed * 2) == governed assert AoiOperationService._partition_side("grb", governed / 2) == governed / 2 @pytest.mark.parametrize( ("provider_key", "max_pixels", "resolution_m"), [ ("dhmv", 12_000_000, 5.0), ("flood_hazard", 12_000_000, 5.0), ("spw_terrain", 12_000_000, 5.0), ("thematic_raster", 30_000_000, 10.0), ("walous", 36_000_000, 10.0), ], ) def test_raster_provider_budget_never_exceeds_decoded_pixel_limit( provider_key: str, max_pixels: int, resolution_m: float ) -> None: side_m = AoiOperationService._partition_side(provider_key, None) assert (side_m / resolution_m) ** 2 < max_pixels def test_migration_and_api_are_registered() -> None: migration = (ROOT / "backend/alembic/versions/202607260001_aoi_operations.py").read_text(encoding="utf-8") main = (ROOT / "backend/app/main.py").read_text(encoding="utf-8") route = (ROOT / "backend/app/api/routes/aoi_operations.py").read_text(encoding="utf-8") assert 'down_revision = "202607160001"' in migration assert '"aoi_operations"' in migration assert '"aoi_operation_partitions"' in migration assert "app.include_router(aoi_operations.router" in main assert '"/{operation_id}/execute-next"' in route assert '"/{operation_id}/partitions/{partition_id}/checkpoint"' in route