test(packs-lab): routes 통합 테스트 (DSM·supabase mock)
This commit is contained in:
102
packs-lab/tests/test_routes.py
Normal file
102
packs-lab/tests/test_routes.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
"""routes.py 통합 테스트 (DSM, supabase는 mock)."""
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
# 테스트용 환경변수 (auth import 전)
|
||||||
|
os.environ["BACKEND_HMAC_SECRET"] = "test-secret-32-bytes-XXXXXXXXXXXX"
|
||||||
|
os.environ["DSM_HOST"] = "https://test.synology.me:5001"
|
||||||
|
os.environ["DSM_USER"] = "test"
|
||||||
|
os.environ["DSM_PASS"] = "test"
|
||||||
|
os.environ["SUPABASE_URL"] = "https://placeholder.supabase.co"
|
||||||
|
os.environ["SUPABASE_SERVICE_KEY"] = "placeholder-key"
|
||||||
|
|
||||||
|
from app import auth # noqa: E402
|
||||||
|
from app.main import app # noqa: E402
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def _signed(body: bytes) -> dict:
|
||||||
|
ts = str(int(time.time()))
|
||||||
|
sig = auth._sign(ts.encode() + b"." + body)
|
||||||
|
return {"X-Timestamp": ts, "X-Signature": sig, "Content-Type": "application/json"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_health():
|
||||||
|
r = client.get("/health")
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert r.json()["service"] == "packs-lab"
|
||||||
|
|
||||||
|
|
||||||
|
@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도 동일하게 패치
|
||||||
|
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):
|
||||||
|
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
|
||||||
|
assert "url" in r.json()
|
||||||
|
|
||||||
|
|
||||||
|
def test_sign_link_no_hmac():
|
||||||
|
r = client.post("/api/packs/sign-link", json={"file_path": "/x"})
|
||||||
|
assert r.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
def test_sign_link_path_outside_base():
|
||||||
|
body = b'{"file_path":"/etc/passwd","expires_in_seconds":14400}'
|
||||||
|
r = client.post("/api/packs/sign-link", content=body, headers=_signed(body))
|
||||||
|
assert r.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_upload_invalid_token():
|
||||||
|
r = client.post(
|
||||||
|
"/api/packs/upload",
|
||||||
|
files={"file": ("x.pdf", b"abc", "application/pdf")},
|
||||||
|
headers={"Authorization": "Bearer invalid"},
|
||||||
|
)
|
||||||
|
assert r.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
def test_upload_no_auth():
|
||||||
|
r = client.post(
|
||||||
|
"/api/packs/upload",
|
||||||
|
files={"file": ("x.pdf", b"abc", "application/pdf")},
|
||||||
|
)
|
||||||
|
assert r.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
@patch("app.routes._supabase")
|
||||||
|
def test_list_success(mock_sb):
|
||||||
|
mock_table = MagicMock()
|
||||||
|
mock_table.select.return_value = mock_table
|
||||||
|
mock_table.is_.return_value = mock_table
|
||||||
|
mock_table.order.return_value = mock_table
|
||||||
|
mock_table.execute.return_value = MagicMock(data=[
|
||||||
|
{
|
||||||
|
"id": str(uuid.uuid4()),
|
||||||
|
"min_tier": "starter",
|
||||||
|
"label": "테스트",
|
||||||
|
"file_path": "/volume1/.../x.pdf",
|
||||||
|
"filename": "x.pdf",
|
||||||
|
"size_bytes": 100,
|
||||||
|
"sort_order": 0,
|
||||||
|
"uploaded_at": "2026-05-02T12:00:00+00:00",
|
||||||
|
}
|
||||||
|
])
|
||||||
|
mock_sb.return_value.table.return_value = mock_table
|
||||||
|
|
||||||
|
body = b''
|
||||||
|
r = client.get("/api/packs/list", headers=_signed(body))
|
||||||
|
assert r.status_code == 200
|
||||||
|
assert len(r.json()) == 1
|
||||||
Reference in New Issue
Block a user