Files
Aislo/resources/tester/test_530_2_plan_router.py
T
eomsangdonandClaude Opus 5.5 29512c001b feat(D 예정노선): D02 기준 지정 걷음 · 지점 마킹 = D03 노선분석 · 기준점 둘레 1 km 처음 받기 · 조용히 이어 받기 (PLAN 591-2 · 요구 452 · 453)
- D02 걷음 — 길 · 단계(PLAN 단계 둘 = 노선 분석 · 확정) · [>] · 대시보드 단계 점 · 서버 길 · 폴더 만들기 · 캐시 등록 · 글 · 가이드 폴더
- 등록 [등록] · 받은 예정노선 [보기] = D03 으로 곧바로
- D03 지점 = 긋기에 붙는 점 · 목록 칸(여섯 색 · 「지점 N」 · 🗑) · 핀 끌기 = 그 자리 노선 노드 같이 · [저장] 몸에 실음 · [초기화] = 선만 지우고 지점 남김
- 지도 우클릭 메뉴(부품 상자) — 여기서 긋기 시작(빈 땅 = 새 본선) · 갈래 시작 · 이어 긋기 · 지점 놓기 · 지점 지우기 · 긋기 끝
- 받기 — 처음 = 등록 기준점 둘레 ± 1 km(지점 · 선 없을 때) · 지점 · 선 · 지도 보기 가운데가 받은 범위 밖이면 조용히 이어 받음(단추 · 막는 창 걷음 · 실패만 [다시 받기])
- 좌표계 = 파일 머리 · 없으면 기준점 경도 TM 띠
- 시험: 529_3(D02 지점 API) 지움 → 591_2 로 갈음 · 280_2 · 528 · 530_2 · 547_1 · 548 · 553_4 · 556_2 · 560_4 · 401 · 54_2 = D02 단계 · 페이지 걷음에 맞춤 · 590_1 · 530_2_analyze = 사업연도 · 기준점 한 번에 읽음 · 591_1 D04 씨앗 시험 = 590-1 이 씨앗 줄 걷음에 맞춤

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:19:34 +09:00

119 lines
4.4 KiB
Python

"""D 지형 API(PLAN 530-1 · 561-2 · 591-2) — 범위 = 지점(설계 내용 파일) 상자 + 여유 · 지점 · 선이
없으면 등록 기준점 둘레 ± 1 km · 받기 = 한 벌.
옛 분석 API 시험(GET · PUT analysis · 꺾임점 고침)은 옛 추천 엔진과 함께 걷음(PLAN 562-2) ·
노선 정본 시험 = `test_530_2_plan_analyze.py` · 지형 셈 시험 = `test_530_1_plan_terrain.py`.
./venv/Scripts/python.exe -m pytest resources/tester/test_530_2_plan_router.py -q
"""
import asyncio
import json
from contextlib import asynccontextmanager
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from D03_PlanAnalysis import D03_PlanAnalysis_Router as router_mod
PID = "12953f5a-5ba1-42ad-a427-8ac857a58bc2"
P0, P2 = (0.0, 0.0), (900.0, 400.0)
URL = f"/api/projects/{PID}/plan/terrain"
class _Pool:
@asynccontextmanager
async def acquire(self):
yield None
@pytest.fixture
def client(tmp_path, monkeypatch):
plan = {
"epsg": 5186,
"points": [{"x": P0[0], "y": P0[1]}, {"x": P2[0], "y": P2[1]}],
"lines": [],
}
info = {"year_start": 2026, "site": None}
async def load_plan(project_id):
return tmp_path, plan
async def project_info(project_id):
return info
monkeypatch.setattr(router_mod.store, "load_plan", load_plan)
monkeypatch.setattr(router_mod.network, "project_info", project_info)
monkeypatch.setattr(router_mod, "get_db_pool", lambda: _Pool())
app = FastAPI()
app.include_router(router_mod.router)
test = TestClient(app)
test.plan = plan
test.info = info
return test
def test_extent_uses_whole_ends(client) -> None:
got = client.get(f"{URL}/extent?margin_m=400").json()
m = 400.0
assert got["margin_m"] == m and got["have"] is None and got["covered"] is False
# 지점 모두(D02 정본) — 연도 구간 아님
assert got["box_m"] == [P0[0] - m, P0[1] - m, P2[0] + m, P2[1] + m]
extra = client.get(f"{URL}/extent", params={"extra": json.dumps([[2000, 0]])}).json()
assert extra["box_m"][2] == 2000 + extra["margin_m"]
assert client.get(f"{URL}/extent", params={"extra": "[1]"}).status_code == 400
client.plan["points"] = [] # 지점 · 기준점 빔
assert client.get(f"{URL}/extent").status_code == 400
def test_extent_site_first(client) -> None:
"""591-2 — 지점 · 선 없음 = 기준점 둘레 ± 1 km(처음 여유 포함) ·
좌표계 = 파일 머리 없으면 기준점 띠."""
from common_util.common_util_crs import lonlat_to_tm
client.plan.update(epsg=None, points=[])
client.info["site"] = {"lon": 127.8, "lat": 36.3, "address": None}
got = client.get(f"{URL}/extent").json()
x, y = lonlat_to_tm(127.8, 36.3, 5186)
r = router_mod.terrain.SITE_RADIUS_M
assert got["epsg"] == 5186
assert got["box_m"] == pytest.approx([x - r, y - r, x + r, y + r])
# 지점이 있으면 기준점은 안 넣음(받은 범위가 이미 덮음 · 옛 프로젝트 그대로)
client.plan.update(epsg=5186, points=[{"x": P0[0], "y": P0[1]}])
got = client.get(f"{URL}/extent?margin_m=400").json()
assert got["box_m"] == [P0[0] - 400, P0[1] - 400, P0[0] + 400, P0[1] + 400]
def test_post_runs_one_set(client, monkeypatch) -> None:
calls: list = []
saved: list = []
works: list = []
def ensure(root, points, epsg, margin_m, report):
calls.append((points, epsg, margin_m))
return {"sheets": {"downloaded": ["1"]}, "models": [{"model_file_path": "m"}]}
async def save(project_id, models, epsg):
saved.append((models, epsg))
def start(project_id, kind, work):
works.append(work)
return {"status": "accepted", "kind": kind}
def post(body):
res = client.post(URL, json=body)
asyncio.run(works.pop()(lambda percent, message: None))
return res
monkeypatch.setattr(router_mod.terrain, "ensure_plan_terrain", ensure)
monkeypatch.setattr(router_mod, "_save_models", save)
monkeypatch.setattr(router_mod, "_start_job", start)
res = post({"margin_m": 500, "extra": [[5, 6]]})
assert res.json() == {"status": "accepted", "kind": "terrain"}
assert calls == [([P0, P2, (5.0, 6.0)], 5186, 500.0)]
assert saved == [([{"model_file_path": "m"}], 5186)]
# 옛 화면 꼴(points 몸) — 여유 처음 값 · 전체 시점 · 종점
post({"points": []})
assert calls[-1] == ([P0, P2], 5186, None)