Introduce an admin portal (React + Nginx), WebSocket routing, and API versioning middleware with `/api/v1/` prefix deprecation. Add master API key authentication, new Prometheus metrics for AI token consumption and active WebSockets, and extend S3 config with a public endpoint URL. Update test paths and fixtures to align with the new routing structure.
47 lines
1.4 KiB
Python
47 lines
1.4 KiB
Python
import pytest
|
|
from fastapi import HTTPException
|
|
from app.services.storage import save_upload, delete_files
|
|
from app.services.storage_backend import LocalStorage, S3Storage
|
|
from unittest.mock import MagicMock, patch, AsyncMock
|
|
import io
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_save_upload_unsupported_mime():
|
|
mock_file = MagicMock()
|
|
mock_file.content_type = "text/plain"
|
|
with pytest.raises(HTTPException) as exc:
|
|
await save_upload(mock_file, "client_id")
|
|
assert exc.value.status_code == 415
|
|
|
|
@pytest.mark.asyncio
|
|
@patch("app.services.storage.settings")
|
|
async def test_save_upload_too_large(mock_settings):
|
|
mock_settings.max_upload_bytes = 10
|
|
mock_settings.MAX_UPLOAD_SIZE_MB = 10
|
|
mock_file = MagicMock()
|
|
mock_file.content_type = "image/jpeg"
|
|
mock_file.read = AsyncMock(return_value=b"a" * 20)
|
|
with pytest.raises(HTTPException) as exc:
|
|
await save_upload(mock_file, "client_id")
|
|
assert exc.value.status_code == 413
|
|
|
|
def test_delete_files_exists(tmp_path):
|
|
f1 = tmp_path / "f1.txt"
|
|
f1.write_text("hello")
|
|
f2 = tmp_path / "f2.txt"
|
|
f2.write_text("world")
|
|
|
|
assert f1.exists()
|
|
assert f2.exists()
|
|
|
|
delete_files(str(f1), str(f2))
|
|
|
|
assert not f1.exists()
|
|
assert not f2.exists()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_signed_url():
|
|
storage = LocalStorage("/", "test_secret")
|
|
url = await storage.get_signed_url("uploads/client1/img.jpg")
|
|
assert url.startswith("/files/signed/")
|