Files
Aislo/resources/tester/test_156_2_picker_speed.py
T
eomsangdonandClaude Opus 5.5 bd963e383e perf(m02): 구조물 조합 고르기 모달 로딩 — 목록 그 폴더만 · 후보 찾기 기억 · 사본 읽기 · 셈 한 번(156-2)
- 까닭: 복사본 목록이 사본마다 원본 단가 묶음을 다시 모음(자재 후보 찾기 같은 조건 되풀이 · m01.logic 검사)
- 목록 ?folder= = 그 복사본 하나만 원본 대조 · 모달은 고르는 구조물 폴더만
- 재료 후보 찾기 = 마스터 색인 하나에 같은 조건 한 번 · 로직 파일 이름만 찾음
- 모달 한 번 보이는 동안 사본 부분 · 셈 한 번만(카드 · 일위대가 · 상태 줄 공유)
- 사본 7개 모달 열기 13.4초 → 처음 0.43초 · 다시 0.06초 · 원본판 · 단가 묶음 전후 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
2026-10-09 20:51:44 +09:00

129 lines
5.4 KiB
Python

"""구조물 조합 고르기 모달 로딩 속도 (PLAN 156-2 · 임시 저장소 · 임시 마스터 사본).
- 목록 `?folder=` = 그 복사본 하나만(원본 대조도 그 하나만) · 값은 통째 목록의 그 줄과 같음
- 원본 대조(`build_source`)는 재료 후보 찾기를 같은 조건마다 한 번만 ·
`m01.logic`(검사 · 단가 미리보기) 안 부름
- 값은 그대로 — 기억을 비우고 다시 모아도 단가 묶음 · 원본판이 같음
- 모달 쪽 — 목록은 그 폴더만 · 복사본 부분 · 셈은 한 번 보이는 동안 한 번만
"""
from __future__ import annotations
import time
from pathlib import Path
from typing import Any
from fastapi import FastAPI
from fastapi.testclient import TestClient
from common_util.common_util_auth import verify_session
from M01_MasterData import M01_MasterData_Store as m01
from M02_MasterTemplete import M02_Item_Copy as copies
from M02_MasterTemplete import M02_Item_Prices as prices
from M02_MasterTemplete import M02_MasterTemplete_Router_Layers as layer_routes
from M02_MasterTemplete import M02_Project_Items_Router as items_router
from M02_MasterTemplete.M02_Item_Source import build_source, version_of
from resources.tester.test_item_copy_complete import ( # noqa: F401 — 고정물
PIPE,
_save,
master_copy,
world,
)
UI = Path(__file__).resolve().parents[2] / "ui_template"
WALL = {"layer": "system", "owner": None, "key": "SS000022", "name": "돌쌓기"}
def _two(root: Path) -> None:
"""관 지점 둘 — 같은 항목 하나 · 다른 항목 하나."""
_save(
root,
[
{"chainage_m": 40.0, "source": "user", "summary_item": PIPE},
{"chainage_m": 80.0, "source": "user", "summary_item": WALL},
],
)
def test_목록_folder_는_그_하나만_값은_통째와_같음(world, monkeypatch): # noqa: F811
root = world["root"]
_two(root)
whole = {row["폴더"]: row for row in copies.list_items(root)}
assert set(whole) == {"pipe@40.0", "pipe@80.0"}
calls: list[Any] = []
real = copies.source_changed
monkeypatch.setattr(copies, "source_changed", lambda m: calls.append(m) or real(m))
assert copies.list_items(root, "pipe@80.0") == [whole["pipe@80.0"]]
assert len(calls) == 1 # 원본 대조 = 그 하나만
assert copies.list_items(root, "없음") == []
def test_길_folder_거름(world, monkeypatch): # noqa: F811
root = world["root"]
_two(root)
async def fake_row(project_id: str) -> dict[str, Any]:
return {"company_id": 3, "storage_path": str(root)}
monkeypatch.setattr(layer_routes, "_project_row", fake_row)
monkeypatch.setattr(layer_routes, "resolve_stored_project_path", lambda path: path)
app = FastAPI()
app.include_router(items_router.router)
app.dependency_overrides[verify_session] = lambda: {"role": "USER", "company_id": 3}
client = TestClient(app)
base = "/api/projects/p1/items"
assert len(client.get(base).json()["항목"]) == 2
got = client.get(base, params={"folder": "pipe@40.0"}).json()["항목"]
assert [row["폴더"] for row in got] == ["pipe@40.0"]
def test_원본_대조는_같은_후보_찾기를_한_번만(world, monkeypatch): # noqa: F811
found: list[str] = []
real = prices.mf.candidates
monkeypatch.setattr(
prices.mf, "candidates", lambda w, c, *a: found.append(repr(c)) or real(w, c, *a)
)
monkeypatch.setattr(prices, "_FOUND", (None, {}))
def no_logic(key: str) -> dict:
raise AssertionError("m01.logic 은 검사 · 단가 미리보기까지 돌아 느림 — 파일 이름만 찾음")
monkeypatch.setattr(m01, "logic", no_logic)
first = build_source(PIPE)
once = len(found)
assert once and len(set(found)) == once # 같은 조건은 한 번만
again = build_source(PIPE)
assert len(found) == once # 두 번째 대조 = 후보 찾기 안 함
assert version_of(again) == version_of(first)
def test_기억을_비워도_단가_묶음_원본판_같음(world, monkeypatch): # noqa: F811
root = world["root"]
_two(root)
before = {row["폴더"]: row["원본판"] for row in copies.list_items(root)}
monkeypatch.setattr(prices, "_FOUND", (None, {}))
for folder, item in (("pipe@40.0", PIPE), ("pipe@80.0", WALL)):
assert version_of(build_source(item)) == before[folder]
assert not any(row["마스터바뀜"] for row in copies.list_items(root))
def test_목록_시간_상한(world): # noqa: F811
"""복사본 둘 · 두 번째 목록(기억 있음)은 0.5초 안 — 옛 길은 항목마다 2~5초."""
root = world["root"]
_two(root)
copies.list_items(root)
start = time.perf_counter()
copies.list_items(root)
assert time.perf_counter() - start < 0.5
def test_모달은_그_폴더만_읽고_부분_셈은_한_번():
detail = (UI / "ui_template_item_picker_detail.ts").read_text(encoding="utf-8")
assert "infos ??= await items.list(folder);" in detail
assert "copyReads.set(part" in detail and "(copyCalc ??= " in detail
assert "items.read(" not in detail and "items?.calc(" not in detail # 다 한 번 부름 길로
show = detail[detail.index("function show(") :]
assert "copyReads = new Map();" in show and "copyCalc = null;" in show # 보일 때마다 새로
project = (UI / "ui_template_item_picker_project.ts").read_text(encoding="utf-8")
assert "folder ? `${base}?folder=${enc(folder)}` : base" in project