mirror of
https://github.com/furyhawk/agent_delta.git
synced 2026-07-21 18:25:37 +00:00
201 lines
6.0 KiB
Python
201 lines
6.0 KiB
Python
"""Tests for user routes."""
|
|
# ruff: noqa: I001 - Imports structured for Jinja2 template conditionals
|
|
|
|
from datetime import UTC, datetime
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
ServiceMock = AsyncMock
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from httpx import ASGITransport, AsyncClient
|
|
|
|
from app.api.deps import get_current_active_superuser, get_current_user, get_user_service
|
|
from app.api.deps import get_db_session
|
|
from app.api.deps import get_redis
|
|
from app.core.config import settings
|
|
from app.main import app
|
|
|
|
|
|
class MockUser:
|
|
"""Mock user for testing."""
|
|
|
|
def __init__(
|
|
self,
|
|
id=None,
|
|
email="test@example.com",
|
|
full_name="Test User",
|
|
is_active=True,
|
|
role="user",
|
|
):
|
|
self.id = id or uuid4()
|
|
self.email = email
|
|
self.full_name = full_name
|
|
self.is_active = is_active
|
|
self.role = role
|
|
self.hashed_password = "hashed"
|
|
self.created_at = datetime.now(UTC)
|
|
self.updated_at = datetime.now(UTC)
|
|
|
|
def has_role(self, role) -> bool:
|
|
"""Check if user has the specified role."""
|
|
if hasattr(role, "value"):
|
|
return self.role == role.value
|
|
return self.role == role
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_user() -> MockUser:
|
|
"""Create a mock regular user."""
|
|
return MockUser()
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_superuser() -> MockUser:
|
|
"""Create a mock superuser."""
|
|
return MockUser(role="admin", email="admin@example.com")
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_user_service(mock_user: MockUser) -> MagicMock:
|
|
"""Create a mock user service."""
|
|
service = MagicMock()
|
|
service.get_by_id = ServiceMock(return_value=mock_user)
|
|
service.get_multi = ServiceMock(return_value=[mock_user])
|
|
service.update = ServiceMock(return_value=mock_user)
|
|
service.delete = ServiceMock(return_value=mock_user)
|
|
return service
|
|
|
|
|
|
@pytest.fixture
|
|
async def auth_client(
|
|
mock_user: MockUser,
|
|
mock_user_service: MagicMock,
|
|
mock_redis: MagicMock,
|
|
mock_db_session,
|
|
) -> AsyncClient:
|
|
"""Client with authenticated regular user."""
|
|
app.dependency_overrides[get_current_user] = lambda: mock_user
|
|
app.dependency_overrides[get_user_service] = lambda: mock_user_service
|
|
app.dependency_overrides[get_redis] = lambda: mock_redis
|
|
app.dependency_overrides[get_db_session] = lambda: mock_db_session
|
|
|
|
async with AsyncClient(
|
|
transport=ASGITransport(app=app),
|
|
base_url="http://test",
|
|
) as ac:
|
|
yield ac
|
|
|
|
app.dependency_overrides.clear()
|
|
|
|
|
|
@pytest.fixture
|
|
async def superuser_client(
|
|
mock_superuser: MockUser,
|
|
mock_user_service: MagicMock,
|
|
mock_redis: MagicMock,
|
|
mock_db_session,
|
|
) -> AsyncClient:
|
|
"""Client with authenticated superuser."""
|
|
app.dependency_overrides[get_current_user] = lambda: mock_superuser
|
|
app.dependency_overrides[get_current_active_superuser] = lambda: mock_superuser
|
|
app.dependency_overrides[get_user_service] = lambda: mock_user_service
|
|
app.dependency_overrides[get_redis] = lambda: mock_redis
|
|
app.dependency_overrides[get_db_session] = lambda: mock_db_session
|
|
|
|
async with AsyncClient(
|
|
transport=ASGITransport(app=app),
|
|
base_url="http://test",
|
|
) as ac:
|
|
yield ac
|
|
|
|
app.dependency_overrides.clear()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_read_current_user(auth_client: AsyncClient, mock_user: MockUser):
|
|
"""Test getting current user."""
|
|
response = await auth_client.get(f"{settings.API_V1_STR}/users/me")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["email"] == mock_user.email
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_update_current_user(auth_client: AsyncClient, mock_user_service: MagicMock):
|
|
"""Test updating current user."""
|
|
response = await auth_client.patch(
|
|
f"{settings.API_V1_STR}/users/me",
|
|
json={"full_name": "Updated Name"},
|
|
)
|
|
assert response.status_code == 200
|
|
mock_user_service.update.assert_called_once()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_read_user_by_id(
|
|
superuser_client: AsyncClient,
|
|
mock_user: MockUser,
|
|
mock_user_service: MagicMock,
|
|
):
|
|
"""Test getting user by ID as superuser."""
|
|
response = await superuser_client.get(f"{settings.API_V1_STR}/users/{mock_user.id}")
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["email"] == mock_user.email
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_read_user_by_id_not_found(
|
|
superuser_client: AsyncClient,
|
|
mock_user_service: MagicMock,
|
|
):
|
|
"""Test getting non-existent user."""
|
|
from app.core.exceptions import NotFoundError
|
|
|
|
mock_user_service.get_by_id = ServiceMock(side_effect=NotFoundError(message="User not found"))
|
|
|
|
response = await superuser_client.get(f"{settings.API_V1_STR}/users/{uuid4()}")
|
|
assert response.status_code == 404
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_update_user_by_id(
|
|
superuser_client: AsyncClient,
|
|
mock_user: MockUser,
|
|
mock_user_service: MagicMock,
|
|
):
|
|
"""Test updating user by ID as superuser."""
|
|
response = await superuser_client.patch(
|
|
f"{settings.API_V1_STR}/users/{mock_user.id}",
|
|
json={"full_name": "Admin Updated"},
|
|
)
|
|
assert response.status_code == 200
|
|
mock_user_service.update.assert_called_once()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_delete_user_by_id(
|
|
superuser_client: AsyncClient,
|
|
mock_user: MockUser,
|
|
mock_user_service: MagicMock,
|
|
):
|
|
"""Test deleting user by ID as superuser."""
|
|
response = await superuser_client.delete(f"{settings.API_V1_STR}/users/{mock_user.id}")
|
|
assert response.status_code == 204
|
|
mock_user_service.delete.assert_called_once()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_delete_user_by_id_not_found(
|
|
superuser_client: AsyncClient,
|
|
mock_user_service: MagicMock,
|
|
):
|
|
"""Test deleting non-existent user."""
|
|
from app.core.exceptions import NotFoundError
|
|
|
|
mock_user_service.delete = ServiceMock(side_effect=NotFoundError(message="User not found"))
|
|
|
|
response = await superuser_client.delete(f"{settings.API_V1_STR}/users/{uuid4()}")
|
|
assert response.status_code == 404
|