Upgrade async GPU analysis and workbench UX

This commit is contained in:
Jens
2026-08-23 21:50:11 +02:00
parent 4040cbca7b
commit b996986d20
59 changed files with 3999 additions and 274 deletions
@@ -0,0 +1,151 @@
"""Regression coverage for bounded, stable segmentation result listings."""
from __future__ import annotations
from datetime import UTC, datetime
from types import SimpleNamespace
from uuid import UUID
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from app.api.routes import segmentation as segmentation_routes
from app.db.session import get_db
from app.schemas.segmentation import SegmentationListResponse
from app.services.segmentation_service import SegmentationService
RUN_ID = UUID("00000000-0000-0000-0000-000000000101")
DATASET_ID = UUID("00000000-0000-0000-0000-000000000102")
PROJECT_ID = UUID("00000000-0000-0000-0000-000000000103")
def _segmentation(index: int) -> SimpleNamespace:
return SimpleNamespace(
id=UUID(int=index + 1),
project_id=PROJECT_ID,
dataset_id=DATASET_ID,
analysis_run_id=RUN_ID,
job_id=None,
model_name="segmentation-test-model",
model_version="1",
class_name="building",
confidence=0.99 - index / 100,
bbox_json=None,
area_m2=float(index + 1),
mask_path=None,
source_tile_path=None,
tile_index=index,
properties_json={},
provenance_json={},
created_at=datetime(2026, 8, 23, tzinfo=UTC),
)
class _Session:
def get(self, _model, identifier):
if identifier == RUN_ID:
return SimpleNamespace(analysis_type="segmentation")
return None
def test_service_returns_one_stable_page_with_complete_metadata(monkeypatch) -> None:
rows = [_segmentation(index) for index in range(5)]
monkeypatch.setattr(
SegmentationService,
"_query_segmentation_rows",
staticmethod(lambda _db, **_filters: rows),
)
result = SegmentationService.list_segmentations(
_Session(),
analysis_run_id=RUN_ID,
dataset_id=DATASET_ID,
limit=2,
offset=1,
)
assert [item.id for item in result.items] == [rows[1].id, rows[2].id]
assert result.total == 5
assert result.limit == 2
assert result.offset == 1
assert result.truncated is True
def test_service_pages_cover_the_stably_ordered_population_once(monkeypatch) -> None:
rows = [_segmentation(index) for index in range(5)]
monkeypatch.setattr(
SegmentationService,
"_query_segmentation_rows",
staticmethod(lambda _db, **_filters: rows),
)
seen = []
for offset in (0, 2, 4):
result = SegmentationService.list_segmentations(
_Session(),
dataset_id=DATASET_ID,
limit=2,
offset=offset,
)
seen.extend(item.id for item in result.items)
assert result.total == len(rows)
assert result.offset == offset
assert seen == [row.id for row in rows]
@pytest.mark.parametrize(
("path", "expected_run_id", "expected_dataset_id"),
[
(f"/api/v1/segmentation/runs/{RUN_ID}/segmentations", RUN_ID, None),
(f"/api/v1/segmentation/datasets/{DATASET_ID}/segmentations", None, DATASET_ID),
],
)
def test_both_listing_routes_forward_the_page_window_and_return_it(
monkeypatch,
path: str,
expected_run_id: UUID | None,
expected_dataset_id: UUID | None,
) -> None:
calls: list[dict] = []
def _list(_db, analysis_run_id=None, **parameters):
calls.append({"analysis_run_id": analysis_run_id, **parameters})
return SegmentationListResponse(
items=[],
total=9,
limit=2,
offset=4,
truncated=True,
)
monkeypatch.setattr(SegmentationService, "list_segmentations", staticmethod(_list))
app = FastAPI()
app.include_router(segmentation_routes.router, prefix="/api/v1")
app.dependency_overrides[get_db] = lambda: object()
response = TestClient(app).get(
path,
params={"limit": 2, "offset": 4, "class_name": "building", "min_confidence": 0.5},
)
assert response.status_code == 200
assert response.json()["data"] == {
"items": [],
"total": 9,
"limit": 2,
"offset": 4,
"truncated": True,
}
assert calls == [
{
"analysis_run_id": expected_run_id,
"limit": 2,
"offset": 4,
"dataset_id": expected_dataset_id,
"class_name": "building",
"min_confidence": 0.5,
}
]