Retry interrupted thematic WCS tiles
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from http.client import IncompleteRead
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from uuid import uuid4
|
||||
@@ -89,6 +90,11 @@ class FakeResponse:
|
||||
return self.content[:limit]
|
||||
|
||||
|
||||
class IncompleteResponse(FakeResponse):
|
||||
def read(self, limit: int):
|
||||
raise IncompleteRead(self.content[:limit])
|
||||
|
||||
|
||||
def payload(product_key: str = "space_occupation_2025", *, side_m: float = 1000.0) -> ThematicRasterAcquireRequest:
|
||||
transformer = Transformer.from_crs("EPSG:31370", "EPSG:4326", always_xy=True)
|
||||
min_x, min_y = transformer.transform(200_000, 210_000)
|
||||
@@ -171,6 +177,52 @@ def test_complete_kempen_scope_fits_the_tiled_thematic_guardrails() -> None:
|
||||
assert exc_info.value.code == "THEMATIC_RASTER_SELECTION_TOO_LARGE"
|
||||
|
||||
|
||||
def test_wcs_fetch_retries_an_incomplete_tile_without_accepting_partial_bytes(monkeypatch) -> None:
|
||||
content = b"II*\x00complete-geotiff"
|
||||
responses = [IncompleteResponse(content), FakeResponse(content)]
|
||||
attempts = 0
|
||||
|
||||
def opener(*_args, **_kwargs):
|
||||
nonlocal attempts
|
||||
response = responses[attempts]
|
||||
attempts += 1
|
||||
return response
|
||||
|
||||
monkeypatch.setattr("app.services.thematic_raster_acquisition_service.time.sleep", lambda _seconds: None)
|
||||
|
||||
result, content_type = ThematicRasterAcquisitionService._fetch(
|
||||
"https://example.invalid/wcs",
|
||||
Settings(_env_file=None),
|
||||
opener,
|
||||
)
|
||||
|
||||
assert attempts == 2
|
||||
assert result == content
|
||||
assert content_type == "image/tiff"
|
||||
|
||||
|
||||
def test_wcs_fetch_fails_closed_after_bounded_incomplete_tile_retries(monkeypatch) -> None:
|
||||
attempts = 0
|
||||
|
||||
def opener(*_args, **_kwargs):
|
||||
nonlocal attempts
|
||||
attempts += 1
|
||||
return IncompleteResponse(b"II*\x00partial")
|
||||
|
||||
monkeypatch.setattr("app.services.thematic_raster_acquisition_service.time.sleep", lambda _seconds: None)
|
||||
|
||||
with pytest.raises(AppError) as exc_info:
|
||||
ThematicRasterAcquisitionService._fetch(
|
||||
"https://example.invalid/wcs",
|
||||
Settings(_env_file=None),
|
||||
opener,
|
||||
)
|
||||
|
||||
assert attempts == ThematicRasterAcquisitionService.WCS_FETCH_ATTEMPTS
|
||||
assert exc_info.value.code == "THEMATIC_RASTER_PROVIDER_UNAVAILABLE"
|
||||
assert exc_info.value.details["attempts"] == 3
|
||||
|
||||
|
||||
def test_binary_and_normalized_products_fail_closed_on_invalid_values() -> None:
|
||||
binary = ThematicRasterAcquisitionService._product("space_occupation_2025")
|
||||
score = ThematicRasterAcquisitionService._product("service_level_2022")
|
||||
|
||||
Reference in New Issue
Block a user