- B05 열기(GET /route/plan) 미리 셈 예약 걷음 · 체인 쪽(업로드 · B04 재확정 · B01 사용 범위) 그대로 - 추천 창 기본 갈래(기본 다섯 · 저장 제약 · 종단 켬 · 설계 지형) = 저장본만 · 없으면 409 「전처리를 다시 하면 생깁니다」(판 글 · 토스트) - 사용자가 바꾼 제약 · 비중 · 종단 끔 · 다른 분석 지형 · [재계산] = 그 자리 셈 - 화면이 실은 분석 지형이 설계 지형과 같으면 설계 지형으로 봄 - 저장본 꺼내기 path.touch 걷음 · 초기 종단 지문 노선 파일 칸 걷음(셈이 안 읽음) · 초기 종단 지문 함수 캐시 - B04 _prepare 재투영 · 피클 읽기 · followed_pipes 스레드로 - 시험 test_309_3 새로 · 224_3 · 364_4 · 476_1 새 규칙에 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
"""364-4 노선 추천 미리 셈 — B05 열 때 예약 · 겹쳐 셈 막음 · 모달 진행 표시.
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_364_4_precompute_on_open.py -q
|
|
|
|
옛 프로젝트 · 판이 바뀐 저장본은 사용자가 처음 누를 때 기다렸음(요구 239 · 토공 62.9 s).
|
|
`GET /route/plan`(B05 열기)이 미리 셈을 예약 · 도는 동안 또 오면 끝난 뒤 한 번 더 · 진행은
|
|
`GET /route/initial/progress` · 모달 상태줄이 그것을 붙임.
|
|
"""
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
from uuid import uuid4
|
|
|
|
from B05_Profile import B05_Profile_Router_RouteInitial as router
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def test_겹쳐_셈_막음_끝난_뒤_한_번_더(monkeypatch) -> None:
|
|
calls: list[str] = []
|
|
seen: list[dict] = []
|
|
pid = uuid4()
|
|
|
|
async def precompute(project_id):
|
|
calls.append(str(project_id))
|
|
progress = router._RUNNING[str(project_id)]
|
|
progress.update(total=5, done=2, mode="earthwork")
|
|
seen.append(router.precompute_progress(project_id))
|
|
await asyncio.sleep(0.05)
|
|
|
|
monkeypatch.setattr(router, "precompute_defaults", precompute)
|
|
|
|
async def main() -> None:
|
|
first = asyncio.create_task(router.run_precompute(pid))
|
|
await asyncio.sleep(0.01)
|
|
# 도는 중 두 번 더 와도 셈은 한 번 더만
|
|
await router.run_precompute(pid)
|
|
await router.run_precompute(pid)
|
|
await first
|
|
|
|
asyncio.run(main())
|
|
assert calls == [str(pid), str(pid)]
|
|
assert seen[0] == {"running": True, "done": 2, "total": 5, "mode": "earthwork"}
|
|
assert router.precompute_progress(pid) == {
|
|
"running": False,
|
|
"done": 0,
|
|
"total": 0,
|
|
"mode": None,
|
|
}
|
|
|
|
|
|
def test_실패해도_진행_비움(monkeypatch) -> None:
|
|
async def broken(_pid):
|
|
raise RuntimeError("셈 실패")
|
|
|
|
monkeypatch.setattr(router, "precompute_defaults", broken)
|
|
pid = uuid4()
|
|
try:
|
|
asyncio.run(router.run_precompute(pid))
|
|
except RuntimeError:
|
|
pass
|
|
assert not router.precompute_progress(pid)["running"]
|
|
|
|
|
|
def test_b05_열기_예약_모달_진행_배선() -> None:
|
|
replan = (ROOT / "B05_Profile/B05_Profile_Router_Replan.py").read_text(encoding="utf-8")
|
|
plan = replan[replan.index("async def read_route_plan") :]
|
|
# 505-1 — B05 열기는 미리 셈 안 부름(전처리 체인에서만)
|
|
assert "schedule_precompute(" not in plan[: plan.index("\n@router")]
|
|
source = (ROOT / "B05_Profile/B05_Profile_Router_RouteInitial.py").read_text(encoding="utf-8")
|
|
assert '"/{project_id}/route/initial/progress"' in source
|
|
# 체인 · B01 범위도 같은 한 줄(run_precompute)로
|
|
assert "run_precompute(project_id), task_name" in source
|
|
assert "await run_precompute(project_id)" in source
|
|
api = (ROOT / "B05_Profile/B05_Profile_Api_RouteInitial.ts").read_text(encoding="utf-8")
|
|
assert "/route/initial/progress" in api
|
|
initial = (ROOT / "B05_Profile/B05_Profile_UI_RouteEdit_Initial.ts").read_text(encoding="utf-8")
|
|
assert "progress: () => fetchPrecomputeProgress(projectId)" in initial
|
|
modal = (ROOT / "B05_Profile/B05_Profile_UI_RouteEdit_Recommend.ts").read_text(encoding="utf-8")
|
|
assert "미리 셈하는 중 ${p.done}/${p.total}" in modal
|
|
|
|
|
|
def test_모달이_여는_갈래_먼저(monkeypatch) -> None:
|
|
"""저장된 갈래(추적 아님)를 먼저 셈 — 모달이 열자마자 그 갈래를 물음."""
|
|
from B05_Profile.B05_Profile_Engine_RouteInitial_Store import DEFAULT_MODES
|
|
|
|
asked: list[str] = []
|
|
|
|
async def paths(_pid):
|
|
return (ROOT, None)
|
|
|
|
async def compute(_pid, request, precompute=False):
|
|
assert precompute # 체인 셈 = 저장본 없어도 셈(505-1)
|
|
asked.append(request.mode)
|
|
assert request.with_profile # 다섯 갈래 모두 종단 켬(420)
|
|
return {}
|
|
|
|
monkeypatch.setattr(router.replan, "_project_paths", paths)
|
|
monkeypatch.setattr(
|
|
router,
|
|
"read_initial_choice",
|
|
lambda _root: {"logic": "gentle", "weights": None, "criteria": None},
|
|
)
|
|
monkeypatch.setattr(router, "compute_initial", compute)
|
|
asyncio.run(router.precompute_defaults(uuid4()))
|
|
assert asked[0] == "gentle" and asked[-1] == "follow"
|
|
assert sorted(asked) == sorted(DEFAULT_MODES)
|