"""공유 storage 를 쓰는 실DB 시험 → 프로젝트 폴더를 임시 storage 사본으로(492 · 요구 283). storage 는 Synology 로 데스크탑까지 번지므로 시험이 쓰는 자리는 사본이어야 함. 프로젝트 폴더를 `<임시>/storage/<같은 상대 경로>` 로 베끼고 `common_util_storage.STORAGE_BASE_DIR` 를 그 뿌리로 바꿈 — DB 의 저장 경로(`storage/…`)가 그대로 사본을 가리킴. 큰 원본 입력(파일 입력 · 전처리 산출)은 안 베끼고 정션(읽기만 · 저장 차례가 안 씀). """ from __future__ import annotations import os import shutil import subprocess import tempfile from contextlib import contextmanager from pathlib import Path import pytest #: 저장 차례가 안 쓰는 큰 입력 — 정션으로 이음 _LINKED = ("B03_FileInput", "B04_PreProcess/processed") def _junction(target: Path, source: Path) -> None: subprocess.run( ["cmd", "/c", "mklink", "/J", str(target), str(source)], check=True, capture_output=True, ) def _copy(source: Path, target: Path, relative: str = "") -> None: target.mkdir(parents=True, exist_ok=True) for entry in source.iterdir(): name = f"{relative}/{entry.name}" if relative else entry.name if name in _LINKED and entry.is_dir(): _junction(target / entry.name, entry) elif entry.is_dir(): if any(link.startswith(f"{name}/") for link in _LINKED): _copy(entry, target / entry.name, name) else: shutil.copytree(entry, target / entry.name) else: shutil.copy2(entry, target / entry.name) def _unlink_junctions(root: Path) -> None: for link in _LINKED: path = root / link if path.exists() or os.path.islink(path): os.rmdir(path) # 정션만 걷음(원본 안 지움) @contextmanager def temp_project_storage(shared_root: Path): """공유 프로젝트 폴더 → 사본 뿌리(yield) · 끝나면 STORAGE_BASE_DIR 되돌리고 사본 지움.""" from common_util import common_util_storage as storage base = Path(os.path.realpath(storage.STORAGE_BASE_DIR)) relative = Path(os.path.realpath(shared_root)).relative_to(base) work = Path(tempfile.mkdtemp(prefix="aislo_storage_")) copy_root = work / "storage" / relative _copy(Path(shared_root), copy_root) patch = pytest.MonkeyPatch() patch.setattr(storage, "STORAGE_BASE_DIR", str(work / "storage")) try: # DB 경로가 사본을 가리키는지 — 아니면 공유 storage 를 쓰게 되므로 시작 전 멈춤 resolved = storage.resolve_stored_project_path(f"storage/{relative.as_posix()}") assert Path(resolved) == Path(os.path.realpath(copy_root)), resolved yield copy_root finally: patch.undo() _unlink_junctions(copy_root) shutil.rmtree(work, ignore_errors=True)