- 열쇠 = 관 목록 · 노선(평면 · 종단 Z) · 분석 산출물(03 road_routing · 01 primary_region) · 강우표 · 구조물 정의 자국 - GET · POST · DELETE pipe-points = 메모리 최근 4벌 + 파일 한 벌(drainage/04_detail_cache.pkl · [저장] 때 GET 열쇠로 씀) - [저장](PUT)은 늘 정본으로 다시 셈 · 관 목록은 사본으로 돌려줌 - 시험 test_342_3_detail_cache(같은 열쇠 재사용 · 입력 바뀌면 다시 셈 · 다시 켜도 파일로 읽힘) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
76 lines
3.0 KiB
Python
76 lines
3.0 KiB
Python
"""342-3 세부 유역 저장본(부록 4 R15) — 열쇠가 같으면 다시 나누지 않음.
|
|
|
|
- 열쇠 = 관 목록 · 노선(평면 · 종단 Z) · 분석 산출물 · 강우표 · 구조물 정의 자국.
|
|
- 같은 열쇠 = _build 안 부름 · 관 목록은 사본 · 무엇이든 바뀌면 다시 셈.
|
|
- [저장] 뒤 파일 한 벌 — 서버를 다시 켜도(메모리 비움) GET 열쇠로 읽힘.
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from B04_PreProcess import B04_PreProcess_Router_Basins as basins
|
|
from common_util.common_util_drainage_context import DrainageContext
|
|
from common_util.common_util_drainage_detail import DrainageDetail
|
|
from common_util.common_util_drainage_pipes import PipePoint
|
|
from common_util.common_util_route_geometry import RouteVertex
|
|
|
|
|
|
@pytest.fixture
|
|
def setup(tmp_path, monkeypatch):
|
|
monkeypatch.setattr(basins, "drainage_dir", lambda stored: tmp_path)
|
|
basins._DETAIL_CACHE.clear()
|
|
calls = SimpleNamespace(count=0)
|
|
|
|
def build(stored_path, context, points):
|
|
calls.count += 1
|
|
chainages = [p.chainage_m for p in points] if points else [50.0]
|
|
return DrainageDetail(), [PipePoint(chainage_m=c, source="stream") for c in chainages]
|
|
|
|
monkeypatch.setattr(basins, "_build", build)
|
|
(tmp_path / "03_road_routing.npz").write_bytes(b"grid")
|
|
context = DrainageContext(
|
|
stored_path="x",
|
|
project_root=Path("."),
|
|
vertices=[RouteVertex(0.0, 0.0, 100.0, 0.0), RouteVertex(300.0, 0.0, 90.0, 300.0)],
|
|
)
|
|
return tmp_path, context, calls
|
|
|
|
|
|
def test_same_key_reuses_and_copies(setup):
|
|
_, context, calls = setup
|
|
points = [PipePoint(chainage_m=120.0, source="user")]
|
|
_, first = basins._build_cached(context, points)
|
|
first[0].x = 999.0 # 저장이 좌표를 채워도 저장본은 그대로
|
|
_, second = basins._build_cached(context, points)
|
|
assert calls.count == 1
|
|
assert second[0].x is None
|
|
|
|
|
|
def test_any_input_change_recomputes(setup):
|
|
tmp_path, context, calls = setup
|
|
points = [PipePoint(chainage_m=120.0, source="user")]
|
|
basins._build_cached(context, points)
|
|
basins._build_cached(context, [PipePoint(chainage_m=121.0, source="user")]) # 관 자리
|
|
context.vertices[1].z = 91.0 # 계획고(종단 Z) → 관 깊이
|
|
basins._build_cached(context, points)
|
|
routing = tmp_path / "03_road_routing.npz"
|
|
routing.write_bytes(b"grid-2") # 분석 다시 돎
|
|
os.utime(routing, ns=(1, 1))
|
|
basins._build_cached(context, points)
|
|
assert calls.count == 4
|
|
|
|
|
|
def test_saved_file_survives_restart(setup):
|
|
tmp_path, context, calls = setup
|
|
stored = [PipePoint(chainage_m=120.0, source="stream")]
|
|
detail, carried = basins._build(context.stored_path, context, stored)
|
|
basins._save_detail_cache(context, stored, detail, carried)
|
|
assert (tmp_path / basins.DETAIL_CACHE_FILENAME).exists()
|
|
basins._DETAIL_CACHE.clear() # 서버 다시 켬
|
|
_, again = basins._build_cached(context, stored)
|
|
assert calls.count == 1
|
|
assert [p.chainage_m for p in again] == [120.0]
|