generated from john/python-template
This commit is contained in:
@@ -1,6 +1,85 @@
|
||||
from pathlib import Path
|
||||
|
||||
from transcription.ui.components.media_urls import public_media_path_label
|
||||
from transcription.ui.components.media_urls import resolve_media_url
|
||||
|
||||
|
||||
def test_resolve_media_url_maps_managed_absolute_path_to_upload_route(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
managed_path = upload_dir / "documents" / "abc" / "page.jpg"
|
||||
managed_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
managed_path.write_bytes(b"x")
|
||||
|
||||
resolved = resolve_media_url(str(managed_path), upload_dir=upload_dir, base_url="http://localhost:8000")
|
||||
assert resolved == "http://localhost:8000/uploads/documents/abc/page.jpg"
|
||||
|
||||
|
||||
def test_resolve_media_url_rejects_unmanaged_absolute_path(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
managed_path = upload_dir / "documents" / "abc" / "page.jpg"
|
||||
managed_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
managed_path.write_bytes(b"x")
|
||||
unmanaged_path = tmp_path / "other-root" / "secret" / "page.jpg"
|
||||
unmanaged_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
unmanaged_path.write_bytes(b"x")
|
||||
|
||||
resolved = resolve_media_url(str(unmanaged_path), upload_dir=upload_dir, base_url="http://localhost:8000")
|
||||
assert resolved is None
|
||||
|
||||
|
||||
def test_resolve_media_url_rejects_stale_relative_path(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
|
||||
resolved = resolve_media_url(
|
||||
"documents/missing/page.jpg",
|
||||
upload_dir=upload_dir,
|
||||
base_url="http://localhost:8000",
|
||||
)
|
||||
assert resolved is None
|
||||
|
||||
|
||||
def test_resolve_media_url_rejects_basename_collision_from_unmanaged_path(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
managed_path = upload_dir / "documents" / "abc" / "shared-name.jpg"
|
||||
managed_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
managed_path.write_bytes(b"managed")
|
||||
|
||||
unmanaged_path = tmp_path / "scratch" / "shared-name.jpg"
|
||||
unmanaged_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
unmanaged_path.write_bytes(b"unmanaged")
|
||||
|
||||
resolved = resolve_media_url(
|
||||
str(unmanaged_path),
|
||||
upload_dir=upload_dir,
|
||||
base_url="http://localhost:8000",
|
||||
)
|
||||
assert resolved is None
|
||||
|
||||
|
||||
def test_resolve_media_url_accepts_existing_upload_relative_path(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
managed_path = upload_dir / "documents" / "abc" / "page.jpg"
|
||||
managed_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
managed_path.write_bytes(b"x")
|
||||
|
||||
resolved = resolve_media_url(
|
||||
"documents/abc/page.jpg",
|
||||
upload_dir=upload_dir,
|
||||
base_url="http://localhost:8000",
|
||||
)
|
||||
assert resolved == "http://localhost:8000/uploads/documents/abc/page.jpg"
|
||||
|
||||
|
||||
def test_resolve_media_url_accepts_existing_portraits_relative_path(tmp_path):
|
||||
upload_dir = tmp_path / "uploads"
|
||||
managed_path = upload_dir / "portraits" / "person" / "seeded.png"
|
||||
managed_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
managed_path.write_bytes(b"x")
|
||||
|
||||
resolved = resolve_media_url(
|
||||
"portraits/person/seeded.png",
|
||||
upload_dir=upload_dir,
|
||||
base_url="http://localhost:8000",
|
||||
)
|
||||
assert resolved == "http://localhost:8000/uploads/portraits/person/seeded.png"
|
||||
|
||||
|
||||
def test_public_media_path_label_maps_managed_absolute_path_to_upload_route(tmp_path):
|
||||
|
||||
@@ -6,6 +6,7 @@ from uuid import uuid4
|
||||
import pytest
|
||||
from sqlmodel import select
|
||||
|
||||
from transcription.config import get_settings
|
||||
from transcription.db import session_scope
|
||||
from transcription.db.models import Document
|
||||
from transcription.db.models import DocumentPerson
|
||||
@@ -102,7 +103,12 @@ class TestPeoplePageRendering:
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_person_detail_page_resolves_relative_portrait_path(self, app_client):
|
||||
_, client = app_client
|
||||
app, client = app_client
|
||||
upload_dirs = {app.state.settings.upload_dir, get_settings().upload_dir}
|
||||
for upload_dir in upload_dirs:
|
||||
portrait_file = upload_dir / "portraits" / "person" / "seeded.png"
|
||||
portrait_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
portrait_file.write_bytes(b"portrait")
|
||||
|
||||
async with session_scope() as session:
|
||||
person = Person(
|
||||
@@ -116,7 +122,7 @@ class TestPeoplePageRendering:
|
||||
response = client.get(f"/ui/people/{person_id}")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "/uploads/portraits/person/seeded.png" in response.text
|
||||
assert "No source media available for inspection." not in response.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_person_detail_page_renders_linked_documents(self, app_client):
|
||||
|
||||
@@ -225,6 +225,32 @@ class TestSourcesPageRendering:
|
||||
assert "finish_reason" in response.text
|
||||
assert "response-123" in response.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_source_detail_page_shows_unavailable_placeholder_for_unmanaged_media_path(self, app_client):
|
||||
_, client = app_client
|
||||
|
||||
async with session_scope() as session:
|
||||
document = Document(name="Missing media document")
|
||||
session.add(document)
|
||||
await session.flush()
|
||||
source = Source(
|
||||
document_id=document.id,
|
||||
page_number=1,
|
||||
upload_name="missing-media.png",
|
||||
filename="missing-media.png",
|
||||
file_path=str((Path.cwd().parent / "external" / "missing-media.png").resolve()),
|
||||
file_hash="f" * 64,
|
||||
file_size_bytes=1,
|
||||
)
|
||||
session.add(source)
|
||||
await session.commit()
|
||||
source_id = str(source.id)
|
||||
|
||||
response = client.get(f"/ui/sources/{source_id}")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "No source media available for inspection." in response.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_source_detail_separates_v42_evidence_layers(self, app_client, seed_job):
|
||||
app, client = app_client
|
||||
|
||||
Reference in New Issue
Block a user