Files
Pier_v1/Code/교각모델링앱/tools/test_delete_pier.py
T
ahnyongjooandClaude Sonnet 5.5 964a841de1 chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:20:18 +09:00

69 lines
3.6 KiB
Python

"""Pier delete test (2026-10-12): own data root (검증/web_delete_test_data, recreated); real piers are not touched.
Checks: wrong / empty confirmation name refused; refused while a batch runs; correct name moves the folder to
data/_휴지통/<name>_<time> with its files; the pier disappears from the list; the trash folder is not listed as
a pier; restoring the folder brings the pier back.
"""
import os
import shutil
import sys
import threading
import time
from pathlib import Path
APP = Path(__file__).resolve().parents[1]
TD = APP / "검증" / "web_delete_test_data"
if TD.exists():
shutil.rmtree(TD)
(TD / "원본").mkdir(parents=True)
for f in ("params.json", "expected.json"):
shutil.copy2(APP / "data" / "운곡교P1" / f, TD / "원본" / f)
os.environ["PIERAPP_DATA"] = str(TD)
sys.path.insert(0, str(APP / "web"))
import app as webapp # noqa: E402
import store # noqa: E402
ok = True
def check(name, cond, detail=""):
global ok
ok &= bool(cond)
print("PASS" if cond else "FAIL", name, detail)
c = webapp.app.test_client()
c.post("/pier/new", data={"name": "삭제대상", "type": "T형", "template": "원본"})
check("pier created", "삭제대상" in store.piers())
h = c.get("/").get_data(as_text=True)
check("list shows a delete form per pier", h.count('name="confirm_name"') == 2)
r = c.post("/pier/삭제대상/delete", data={"confirm_name": "삭제"}, follow_redirects=True)
check("wrong name refused", "정확히 입력하세요" in r.get_data(as_text=True) and "삭제대상" in store.piers())
r = c.post("/pier/삭제대상/delete", data={"confirm_name": ""}, follow_redirects=True)
check("empty name refused", "삭제대상" in store.piers())
# a running batch blocks deletion
p = store.Pier("삭제대상")
stop = threading.Event()
t = threading.Thread(target=stop.wait, daemon=True)
t.start()
webapp.BATCH["삭제대상"] = t
store.wjson(p.run_dir / "batch.json", {"state": "실행 중", "by": "x", "pid": os.getpid(), "at": store.now(), "log": []})
r = c.post("/pier/삭제대상/delete", data={"confirm_name": "삭제대상"}, follow_redirects=True)
check("refused while a batch runs", "실행 중입니다" in r.get_data(as_text=True) and "삭제대상" in store.piers())
stop.set()
t.join()
store.wjson(p.run_dir / "batch.json", {"state": "완료", "by": "x", "pid": os.getpid(), "at": store.now(), "log": []})
r = c.post("/pier/삭제대상/delete", data={"confirm_name": "삭제대상"}, follow_redirects=True)
trash = sorted((TD / store.TRASH).glob("삭제대상_*"))
check("correct name: moved to trash", "휴지통으로 이동" in r.get_data(as_text=True) and "삭제대상" not in store.piers()
and len(trash) == 1 and (trash[0] / "params.json").exists() and (trash[0] / "runs" / "current" / "batch.json").exists())
check("trash folder not listed as a pier", store.TRASH not in store.piers() and store.piers() == ["원본"])
check("deleted pier page is 404", c.get("/pier/삭제대상").status_code == 404)
check("delete of a missing pier is 404", c.post("/pier/없는교각/delete", data={"confirm_name": "없는교각"}).status_code == 404)
shutil.move(str(trash[0]), str(TD / "삭제대상"))
check("restore by moving the folder back", "삭제대상" in store.piers() and c.get("/pier/삭제대상").status_code == 200)
shutil.rmtree(TD / store.TRASH) # also when no trash folder exists yet
r = c.post("/pier/new", data={"name": store.TRASH, "type": "T형", "template": "원본"}, follow_redirects=True)
check("a pier cannot be named like the trash folder", "휴지통 폴더 이름" in r.get_data(as_text=True)
and not (TD / store.TRASH).exists())
sys.exit(0 if ok else 1)