Spaces:
Sleeping
Sleeping
| import hashlib | |
| import io | |
| import re | |
| from pathlib import Path | |
| import pytest | |
| from fastapi import UploadFile | |
| from app.config import Settings | |
| from app.services import storage | |
| from app.services.storage import StoredFile, UploadTooLargeError, save_upload | |
| def make_upload(data: bytes, filename: str) -> UploadFile: | |
| return UploadFile(file=io.BytesIO(data), filename=filename) | |
| def test_save_upload_streams_and_hashes(settings: Settings) -> None: | |
| # ~3 MiB so the copy spans multiple 1 MiB chunks. | |
| data = b"\x89PNG\r\n\x1a\n" + bytes(range(256)) * (12 * 1024) | |
| assert len(data) > 2 * storage._CHUNK | |
| stored = save_upload(settings, 1, make_upload(data, "scan.png")) | |
| assert isinstance(stored, StoredFile) | |
| assert stored.size_bytes == len(data) | |
| assert stored.sha256 == hashlib.sha256(data).hexdigest() | |
| target = Path(stored.storage_path) | |
| assert target.is_file() | |
| assert target.read_bytes() == data | |
| def test_save_upload_uses_server_side_uuid_name(settings: Settings) -> None: | |
| stored = save_upload(settings, 7, make_upload(b"png-bytes", "../../evil.png")) | |
| target = Path(stored.storage_path) | |
| assert target.parent == settings.upload_dir / "7" | |
| assert target.resolve().is_relative_to(settings.upload_dir.resolve()) | |
| assert ".." not in target.parts | |
| assert "evil" not in target.name | |
| assert re.fullmatch(r"[0-9a-f]{32}\.png", target.name), target.name | |
| assert target.is_file() | |
| def test_save_upload_size_cap_removes_partial_file( | |
| settings: Settings, monkeypatch: pytest.MonkeyPatch | |
| ) -> None: | |
| monkeypatch.setattr(storage, "MAX_UPLOAD_BYTES", 10) | |
| with pytest.raises(UploadTooLargeError): | |
| save_upload(settings, 3, make_upload(b"x" * 64, "big.png")) | |
| claim_dir = settings.upload_dir / "3" | |
| assert claim_dir.is_dir() | |
| assert list(claim_dir.iterdir()) == [] | |
| def test_save_upload_exactly_at_cap_is_allowed( | |
| settings: Settings, monkeypatch: pytest.MonkeyPatch | |
| ) -> None: | |
| monkeypatch.setattr(storage, "MAX_UPLOAD_BYTES", 10) | |
| stored = save_upload(settings, 4, make_upload(b"x" * 10, "ok.bin")) | |
| assert stored.size_bytes == 10 | |
| assert Path(stored.storage_path).read_bytes() == b"x" * 10 | |