Files
Aislo/resources/tester/test_342_3_detail_cache.py
T
eomsangdonandClaude Opus 5.5 fba1eb8a5d perf(배수유역): 342-3 세부 유역 저장본 — 열쇠가 같으면 다시 나누지 않음(부록 4 R15)
- 열쇠 = 관 목록 · 노선(평면 · 종단 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
2026-10-16 11:13:24 +09:00

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]