import base64 from pathlib import Path import pytest from sqlalchemy import select from app.models.entities import Backend, BlobReplica def _encode_metadata(value: str) -> str: return base64.b64encode(value.encode("utf-8")).decode("utf-8") @pytest.mark.anyio async def test_tus_create_head_patch_and_finalize(api_client, session_factory, runtime_paths) -> None: metadata_header = f"filename {_encode_metadata('movie.mp4')}" create_response = await api_client.post( "/files", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": "11", "Upload-Metadata": metadata_header, }, ) assert create_response.status_code == 201 upload_location = create_response.headers["Location"] upload_id = upload_location.rsplit("/", 1)[-1] head_response = await api_client.head( f"/files/{upload_id}", headers={"Tus-Resumable": "1.0.0"}, ) assert head_response.status_code == 200 assert head_response.headers["Upload-Offset"] == "0" assert head_response.headers["Upload-Length"] == "11" patch_response = await api_client.patch( f"/files/{upload_id}", headers={ "Tus-Resumable": "1.0.0", "Upload-Offset": "0", "Content-Type": "application/offset+octet-stream", }, content=b"hello world", ) assert patch_response.status_code == 204 assert patch_response.headers["Upload-Offset"] == "11" finalize_response = await api_client.post( f"/api/uploads/{upload_id}/finalize", json={"directory_id": "dir_root", "filename": "movie.mp4"}, ) assert finalize_response.status_code == 200 payload = finalize_response.json() assert payload["upload"]["status"] == "finalized" assert payload["file"]["name"] == "movie.mp4" assert payload["file"]["size_bytes"] == 11 detail_response = await api_client.get(f"/api/files/{payload['file']['id']}") assert detail_response.status_code == 200 assert detail_response.json()["file"]["name"] == "movie.mp4" async with session_factory() as session: backend = ( await session.execute(select(Backend).where(Backend.name == "local-default")) ).scalar_one() replica = (await session.execute(select(BlobReplica).where(BlobReplica.backend_id == backend.id))).scalar_one() assert replica.storage_key.startswith("objects/file/sha256/") assert replica.storage_key.endswith(".blob") stored_path = Path(runtime_paths["local_storage_dir"]) / replica.storage_key assert stored_path.exists() assert stored_path.read_bytes() == b"hello world" @pytest.mark.anyio async def test_tus_patch_rejects_wrong_offset(api_client) -> None: create_response = await api_client.post( "/files", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": "5", }, ) upload_id = create_response.headers["Location"].rsplit("/", 1)[-1] patch_response = await api_client.patch( f"/files/{upload_id}", headers={ "Tus-Resumable": "1.0.0", "Upload-Offset": "3", "Content-Type": "application/offset+octet-stream", }, content=b"hello", ) assert patch_response.status_code == 409 assert patch_response.json()["error"]["code"] == "upload_conflict" @pytest.mark.anyio async def test_finalize_requires_complete_upload(api_client) -> None: create_response = await api_client.post( "/files", headers={ "Tus-Resumable": "1.0.0", "Upload-Length": "10", }, ) upload_id = create_response.headers["Location"].rsplit("/", 1)[-1] patch_response = await api_client.patch( f"/files/{upload_id}", headers={ "Tus-Resumable": "1.0.0", "Upload-Offset": "0", "Content-Type": "application/offset+octet-stream", }, content=b"abc", ) assert patch_response.status_code == 204 finalize_response = await api_client.post( f"/api/uploads/{upload_id}/finalize", json={"directory_id": "dir_root", "filename": "partial.bin"}, ) assert finalize_response.status_code == 409 assert finalize_response.json()["error"]["code"] == "upload_conflict"