mirror of
http://88.130.71.182:3000/BlitTech/contexta_be.git
synced 2026-06-13 08:30:07 +00:00
- Add new routers: admin, appointments, campaigns - Add storage service and logging config - Add migrations directory and test suite with pytest config - Add supabase_migration_features.sql - Update models, dependencies, config, and existing routers - Remove whatsapp_service (deleted) - Update pyproject.toml and uv.lock dependencies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
126 lines
4.7 KiB
Python
126 lines
4.7 KiB
Python
"""Tests for upload endpoints."""
|
|
import pytest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
AUTH = {"Authorization": "Bearer test-token"}
|
|
|
|
|
|
class TestUploadAuth:
|
|
def test_logo_upload_requires_auth(self, client):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("logo.png", b"fake-image-data", "image/png")},
|
|
)
|
|
assert resp.status_code == 401
|
|
|
|
|
|
class TestUploadLogoValidation:
|
|
def test_rejects_unsupported_file_type(self, client):
|
|
with patch("app.routers.upload.get_supabase"):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("doc.pdf", b"PDF content", "application/pdf")},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 400
|
|
assert "Invalid file type" in resp.json()["detail"]
|
|
|
|
def test_rejects_file_over_2mb(self, client):
|
|
big_bytes = b"x" * (2 * 1024 * 1024 + 1)
|
|
with patch("app.routers.upload.get_supabase"):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("big.png", big_bytes, "image/png")},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 413
|
|
|
|
@pytest.mark.parametrize("mime,filename", [
|
|
("image/png", "logo.png"),
|
|
("image/jpeg", "photo.jpg"),
|
|
("image/gif", "anim.gif"),
|
|
("image/svg+xml", "icon.svg"),
|
|
("image/webp", "img.webp"),
|
|
])
|
|
def test_accepts_all_allowed_image_types(self, client, mime, filename):
|
|
fake_url = "https://cdn.example.com/logos/test.png"
|
|
sb = MagicMock()
|
|
sb.storage.from_.return_value.upload.return_value = MagicMock()
|
|
sb.storage.from_.return_value.get_public_url.return_value = fake_url
|
|
sb.auth = MagicMock()
|
|
|
|
with patch("app.routers.upload.get_supabase", return_value=sb):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": (filename, b"image-bytes", mime)},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["url"] == fake_url
|
|
|
|
|
|
class TestUploadLogoSuccess:
|
|
def test_returns_public_url(self, client):
|
|
public_url = "https://storage.example.com/logos/test-user-id/abc123.png"
|
|
sb = MagicMock()
|
|
sb.storage.from_.return_value.upload.return_value = MagicMock()
|
|
sb.storage.from_.return_value.get_public_url.return_value = public_url
|
|
sb.auth = MagicMock()
|
|
|
|
with patch("app.routers.upload.get_supabase", return_value=sb):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("logo.png", b"fake-png-data", "image/png")},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert "url" in body
|
|
assert body["url"] == public_url
|
|
|
|
def test_upload_path_uses_user_id(self, client):
|
|
"""Storage path should be scoped to the authenticated user's ID."""
|
|
sb = MagicMock()
|
|
upload_mock = sb.storage.from_.return_value.upload
|
|
sb.storage.from_.return_value.get_public_url.return_value = "https://url"
|
|
sb.auth = MagicMock()
|
|
|
|
# Track the actual user returned by auth
|
|
auth_user = MagicMock()
|
|
auth_user.id = "test-user-id"
|
|
sb.auth.get_user.return_value = MagicMock(user=auth_user)
|
|
|
|
# Also mock user_profiles check
|
|
profile_mock = MagicMock()
|
|
profile_mock.select.return_value = profile_mock
|
|
profile_mock.eq.return_value = profile_mock
|
|
profile_mock.execute.return_value = MagicMock(data=[])
|
|
sb.table.return_value = profile_mock
|
|
|
|
with patch("app.routers.upload.get_supabase", return_value=sb), \
|
|
patch("app.dependencies.get_supabase", return_value=sb):
|
|
client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("logo.png", b"data", "image/png")},
|
|
headers=AUTH,
|
|
)
|
|
|
|
upload_mock.assert_called_once()
|
|
call_kwargs = upload_mock.call_args
|
|
path = call_kwargs[1].get("path") or call_kwargs[0][0]
|
|
# Path should start with the user's ID
|
|
assert path.startswith("test-user-id")
|
|
|
|
def test_storage_failure_returns_500(self, client):
|
|
sb = MagicMock()
|
|
sb.storage.from_.return_value.upload.side_effect = Exception("Storage error")
|
|
sb.auth = MagicMock()
|
|
|
|
with patch("app.routers.upload.get_supabase", return_value=sb):
|
|
resp = client.post(
|
|
"/api/v1/upload/logo",
|
|
files={"file": ("logo.png", b"data", "image/png")},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 500
|