Files
contexta_be/tests/test_upload.py
belviskhoremk 92d4c2fc5e feat: add appointments, campaigns, admin, storage, tests and various updates
- 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>
2026-04-03 09:11:58 +00:00

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