Files
Aislo/resources/tester/test_505_2_terrain_sheet.py
T
eomsangdonandClaude Opus 5.5 acc09b0410 fix(B05·B06): 지형 격자 자리 = 서버 표본기와 같은 params DTM 행 · 격자 없는 지형 안 닫힌 측점 「지형 범위 밖」 배지 (PLAN 578-1 · 요구 438 · 439)
- 까닭: 확정 모델 행이 stage 1 params 와 어긋나면(검증_sub1 확정 = sheet · params = classification) terrain-sources 의 grid = null → 브라우저는 미교차 넓힘을 못 하고 ±20 m 에서 멈춤 · 서버 표본기 · Node /calc 는 params 를 따라 넓힘 → 소단 밀린 측점 화면 ≠ 저장
- 고침: `_confirmed_model` → `_design_model` — params 의 `dtm_{filter}.npz` DTM 행(확정 행 먼저) · 표본 폭 상수는 그대로(통째 격자가 이미 최대)
- 횡단 카드: 격자 없는(DTM 아닌) 지형에서 사면 미교차 = 부품 배지 「지형 범위 밖」(값은 [저장] 때 서버)
- 시험: test_344_1_terrain_grid_route 에 어긋난 확정 행 지킴 · test_133_1 · test_505_2 바뀐 이름

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 13:32:24 +09:00

102 lines
3.7 KiB
Python

"""PLAN 505-2 5d — 수치지형도 sheet 고르기 = DB 모델 있을 때만 · 없으면 [확인] 409 사유 한 줄.
./venv/Scripts/python.exe -m pytest resources/tester/test_505_2_terrain_sheet.py -q
고르기 목록(`/route/terrain-sources`)은 npz 파일 + DB 완료 모델을 함께 봄 — 모델 없는 sheet 는 숨김
(화면은 고르기가 숨으면 분석 지형을 안 실음). 바꿈(`switch_design_terrain`)이 모델을 못 찾으면
`_recompute` 가 `{error}` → 노선 되돌리고 409(전엔 LookupError 가 저장 통째 되돌림).
"""
from __future__ import annotations
import asyncio
import sys
from contextlib import asynccontextmanager
from pathlib import Path
from uuid import uuid4
import pytest
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import B04_PreProcess.B04_PreProcess_Service as service # noqa: E402
import B05_Profile.B05_Profile_Router_Replan as replan # noqa: E402
import B05_Profile.B05_Profile_Router_Terrain as terrain # noqa: E402
from common_util.common_util_surface_confirmation import SHEET_ANALYSIS_FILTER # noqa: E402
LAS = {"source_filter": "classification", "method": "dtm", "smooth": True}
class _Pool:
@asynccontextmanager
async def acquire(self):
yield _Connection()
class _Connection:
async def begin(self):
pass
async def rollback(self):
_Connection.rolled = True
async def commit(self):
raise AssertionError("모델 없으면 확정하지 않음")
def _async(value):
async def inner(*args, **kwargs):
return value
return inner
def _model(source_filter: str) -> dict:
return {
"id": 7,
"status": "COMPLETE",
"model_type": "DTM",
"generation_params": {"source_filter": source_filter},
}
@pytest.fixture
def sources(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
models = tmp_path / terrain._MODELS_SUBDIR
models.mkdir(parents=True)
(models / f"dtm_{SHEET_ANALYSIS_FILTER}.npz").write_bytes(b"") # sheet 파일은 있음
monkeypatch.setattr(terrain, "get_db_pool", lambda: _Pool())
monkeypatch.setattr(terrain, "get_project_storage_relative_path", _async("p"))
monkeypatch.setattr(terrain, "get_surface_confirmation_params", _async(dict(LAS)))
monkeypatch.setattr(terrain, "_design_model", _async(None))
monkeypatch.setattr(terrain, "resolve_stored_project_path", lambda stored: tmp_path)
monkeypatch.setattr(terrain, "_design_grid", lambda *args: None)
def run(models_in_db: list[dict]) -> list[str]:
monkeypatch.setattr(service, "list_surface_models", _async(models_in_db))
return asyncio.run(terrain.read_terrain_sources(uuid4()))["sources"]
return run
def test_모델_없는_sheet_고르기_숨김(sources) -> None:
assert sources([_model("classification")]) == ["las"]
def test_모델_있는_sheet_고르기_보임(sources) -> None:
assert sources([_model(SHEET_ANALYSIS_FILTER)]) == ["las", "sheet"]
def test_모델_없으면_재계산_409_사유(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
import common_util.common_util_surface_confirmation as surface
_Connection.rolled = False
monkeypatch.setattr(replan, "get_db_pool", lambda: _Pool())
monkeypatch.setattr(service, "get_surface_confirmation_params", _async(dict(LAS)))
monkeypatch.setattr(service, "list_surface_models", _async([_model("classification")]))
monkeypatch.setattr(surface, "get_surface_confirmation_params", _async(dict(LAS)))
got = asyncio.run(replan._recompute(uuid4(), tmp_path, "p", terrain="sheet"))
assert got == {"error": replan.TERRAIN_MODEL_MISSING} and _Connection.rolled