fix(packs-lab): PACK_HOST_DIR 도입 — sign-link 시 DSM이 NAS 호스트경로 받도록
이전: upload가 컨테이너 경로(/app/data/packs/...)를 Supabase에 저장 →
sign-link 시 그 경로를 DSM에 전달 → DSM은 NAS 호스트 절대경로
(/volume1/.../media/packs/...) 기준이라 파일을 찾지 못함.
수정:
- routes.py: PACK_HOST_DIR 신규 (env, fallback=PACK_BASE_DIR)
- upload 시 host_path = PACK_HOST_DIR/{tier}/{filename}을 Supabase에 INSERT
- sign-link 시 PACK_HOST_DIR 기준 경로 검증
- docker-compose: PACK_HOST_DIR env 주입 (default=PACK_DATA_PATH)
- .env.example + CLAUDE.md: 환경변수 의미 분리 명시
- tests: 호스트경로 저장 검증 신규 (test_upload_stores_host_path_not_container_path)
- 25/25 passing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,11 +37,12 @@ def test_health():
|
||||
@patch("app.routes.create_share_link", new_callable=AsyncMock)
|
||||
def test_sign_link_success(mock_share):
|
||||
mock_share.return_value = ("https://test.synology.me:5001/d/s/abc", datetime.now(timezone.utc))
|
||||
# Windows에서는 절대경로 resolve 결과가 C:\... 로 prefix되므로 PACK_BASE_DIR도 동일하게 패치
|
||||
# Windows에서는 절대경로 resolve 결과가 C:\... 로 prefix되므로 PACK_HOST_DIR도 동일하게 패치
|
||||
# sign-link는 PACK_HOST_DIR(NAS 호스트경로) 기준으로 검증함.
|
||||
from pathlib import Path
|
||||
abs_resolved = Path("/volume1/docker/webpage/media/packs/master/x.mp4").resolve()
|
||||
base_resolved = Path(str(abs_resolved).rsplit("master", 1)[0].rstrip("\\/"))
|
||||
with patch("app.routes.PACK_BASE_DIR", base_resolved):
|
||||
with patch("app.routes.PACK_HOST_DIR", base_resolved):
|
||||
body = b'{"file_path":"/volume1/docker/webpage/media/packs/master/x.mp4","expires_in_seconds":14400}'
|
||||
r = client.post("/api/packs/sign-link", content=body, headers=_signed(body))
|
||||
assert r.status_code == 200
|
||||
@@ -245,3 +246,55 @@ def test_list_filters_deleted():
|
||||
|
||||
assert resp.status_code == 200
|
||||
fake_supabase.table.return_value.select.return_value.is_.assert_called_with("deleted_at", "null")
|
||||
|
||||
|
||||
def test_upload_stores_host_path_not_container_path(tmp_path, monkeypatch):
|
||||
"""upload 시 Supabase에 저장되는 file_path는 PACK_BASE_DIR(컨테이너) 가 아닌 PACK_HOST_DIR(NAS 호스트) 절대경로여야 한다.
|
||||
|
||||
DSM API는 NAS 호스트 절대경로 기준이라 컨테이너 내부 경로(/app/data/packs/...)를
|
||||
Supabase에 저장하면 sign-link 시 DSM이 파일을 못 찾는다.
|
||||
"""
|
||||
from pathlib import Path
|
||||
container_base = tmp_path / "container"
|
||||
host_base = Path("/volume1/docker/webpage/media/packs")
|
||||
|
||||
monkeypatch.setattr("app.routes.PACK_BASE_DIR", container_base)
|
||||
monkeypatch.setattr("app.routes.PACK_HOST_DIR", host_base)
|
||||
|
||||
captured_insert = {}
|
||||
|
||||
fake_supabase = MagicMock()
|
||||
|
||||
def capture_insert(payload):
|
||||
captured_insert.update(payload)
|
||||
m = MagicMock()
|
||||
m.execute.return_value = MagicMock(data=[{"uploaded_at": "2026-05-11T00:00:00+00:00"}])
|
||||
return m
|
||||
|
||||
fake_supabase.table.return_value.insert.side_effect = capture_insert
|
||||
|
||||
token = auth.mint_upload_token({
|
||||
"tier": "pro",
|
||||
"label": "샘플",
|
||||
"filename": "host_path_check.zip",
|
||||
"size_bytes": 5,
|
||||
"jti": str(uuid.uuid4()),
|
||||
"expires_at": int(time.time()) + 1800,
|
||||
})
|
||||
|
||||
with patch("app.routes._supabase", return_value=fake_supabase):
|
||||
test_client = TestClient(app)
|
||||
resp = test_client.post(
|
||||
"/api/packs/upload",
|
||||
files={"file": ("host_path_check.zip", b"hello")},
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
# Supabase에 저장된 file_path는 호스트 경로
|
||||
expected_host = str(host_base / "pro" / "host_path_check.zip")
|
||||
assert captured_insert["file_path"] == expected_host
|
||||
# 응답의 file_path도 호스트 경로
|
||||
assert resp.json()["file_path"] == expected_host
|
||||
# 컨테이너 경로(tmp_path 하위)와 다름
|
||||
assert str(container_base) not in captured_insert["file_path"]
|
||||
|
||||
Reference in New Issue
Block a user