Files
Aislo/resources/tester/test_272_detail_memory.py
T
2026-10-19 09:56:17 +09:00

122 lines
5.1 KiB
Python

"""PLAN 466 (요구 272 · 분석 4장 (A)) — 상세 가게 메모리 = 페이지 수명.
못박는 것
- 관 초안으로 갈아끼운 상세(메모리) → [폐기] → 페이지를 떠남 = 메모리 비움 → 다시 열기(B05 · B06 · B07) =
세션 정본(새로고침 길 · 뒤에서 판 확인 한 번) · 초안 측점이 남지 않음. 다른 프로젝트 메모리는 그대로.
- 페이지 dispose 가 비움(`design_page`) · 묶음 열 때 관 · 구조물 · 추가 측점 초안이 있으면 측점을 냄
(초안 남긴 채 떠남 · 새로고침 = 초안 측점 · 갈아끼움).
- 화면 선만 바뀜(비정규 측점 도착) = 상세가 그 선 대비 낡았으면 cross 한 번 더(`recrossIfStale`).
짝: `helper_272_detail_memory_entry.ts` + `helper_272_detail_memory.mjs`(진짜 상세 가게 · vite ssr).
./venv/Scripts/python.exe -m pytest resources/tester/test_272_detail_memory.py -q
"""
from __future__ import annotations
import json
import shutil
import subprocess
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
pytestmark = pytest.mark.skipif(
not (ROOT / "config" / "node_modules" / "vite").is_dir(),
reason="프론트엔드 의존성 미설치",
)
def run_helper(work: Path) -> dict:
"""vite ssr 로 진짜 모듈을 묶어 헬퍼를 돌림 — 466 두 시험이 같이 씀."""
build = subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(ROOT / "config" / "node_modules" / "vite" / "bin" / "vite.js"),
"build",
"--configLoader",
"runner",
"--ssr",
"../resources/tester/helper_272_detail_memory_entry.ts",
"--outDir",
str(work),
"--logLevel",
"error",
],
cwd=ROOT,
capture_output=True,
text=True,
encoding="utf-8",
timeout=300,
)
assert build.returncode == 0, build.stderr
bundle = work / "bundle.mjs"
shutil.copy(work / "helper_272_detail_memory_entry.js", bundle)
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_272_detail_memory.mjs"), str(bundle)],
capture_output=True,
text=True,
encoding="utf-8",
timeout=120,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
@pytest.fixture(scope="module")
def got(tmp_path_factory) -> dict:
return run_helper(tmp_path_factory.mktemp("b272"))
def test_초안_동안은_메모리만_갈아끼움(got) -> None:
m = got["memory"]
assert m["swapped"] and m["during"] == [0, 20, 30, 40, 60]
assert m["session"] == [0, 20, 40, 60] # 세션 = 저장 정본
def test_폐기만으론_메모리_그대로_떠나면_정본(got) -> None:
m = got["memory"]
assert m["pipesAfterDiscard"] is None # 관 초안 지움
assert m["afterDiscard"] == [0, 20, 30, 40, 60] # 같은 페이지 안 = 메모리(떠날 때 비움)
assert m["peekAfterForget"] is None
assert m["reopened"] == [0, 20, 40, 60] and m["reopenedSame"] is False # 새로고침 길
assert m["canonAsked"] == 1 # 세션으로 서고 뒤에서 판 확인(새로고침과 같음)
assert m["otherKept"] is True
def test_페이지가_떠날_때_비움() -> None:
page = (ROOT / "A00_Common/design/design_page.ts").read_text(encoding="utf-8")
dispose = page[page.index(" covers: (route)") :]
assert "forgetSectionMemory(projectId);" in dispose[: dispose.index("\n };\n")]
def test_초안_있으면_열_때_측점_냄() -> None:
src = (ROOT / "A00_Common/design/design_pipeline_page.ts").read_text(encoding="utf-8")
start = src[src.index(" const start = (): void => {") :]
body = start[: start.index("\n };\n")]
assert 'store.get("pipes") ?? store.get("structures") ?? readPlusDraft(projectId)' in body
assert "quietGeneration = inputs.route || drafts ? -1 : pipe.generation;" in body
def test_화면_선만_바뀌면_낡음_다시_셈() -> None:
src = (ROOT / "A00_Common/design/design_pipeline_page.ts").read_text(encoding="utf-8")
restart = src[src.index(" restart() {") :]
# 정본 지문은 `design_pipeline_page_saved`(472-5 나눔) — 노선 번호를 거기서 읽음
assert (
"publisher.recheck(projectId, pageSaved.canonRouteId()"
in restart[: restart.index(" },")]
)
store = (ROOT / "B06_Section/B06_Section_Section_Store.ts").read_text(encoding="utf-8")
fn = store[store.index("export function recrossIfStale(") :]
assert "recrossSaved(projectId, key, detail, routeId)" in fn[: fn.index("\n}\n")]
def test_확정_성공도_상세_비움() -> None:
# 470 N1 — [확정] 은 다음 페이지(B07)로 바로 감 · [저장]처럼 상세 메모리 · 옛 세션 사본을 비움
shared = (ROOT / "A00_Common/design/design_shared.ts").read_text(encoding="utf-8")
done = shared[shared.index(" done: async (isConfirm) => {") :]
confirm = done[done.index("if (isConfirm) {") : done.index("goToWorkflowStage(")]
assert "invalidateSectionDetail(shared.projectId);" in confirm