from types import SimpleNamespace from unittest.mock import AsyncMock from fastapi.testclient import TestClient from app.api.v1.endpoints import user_management as user_management_endpoint from app.auth.dependencies import get_current_active_user, get_user_repository from app.auth.permissions import get_current_admin from app.domain.models.role import UserRole from tests.conftest import build_test_app, make_user def _build_client(repo, *, current_user=None, admin_user=None) -> TestClient: app = build_test_app(user_management_endpoint.router, "/users") app.dependency_overrides[get_user_repository] = lambda: repo if current_user is not None: app.dependency_overrides[get_current_active_user] = lambda: current_user if admin_user is not None: app.dependency_overrides[get_current_admin] = lambda: admin_user return TestClient(app) def test_list_users_requires_admin_role(): repo = SimpleNamespace( get_all_users=AsyncMock( return_value=[ make_user(id=1, username="admin", role=UserRole.ADMIN), make_user(id=2, username="user2"), ] ) ) client = _build_client( repo, current_user=make_user(id=1, role=UserRole.ADMIN), ) response = client.get("/users/", params={"skip": 5, "limit": 2}) assert response.status_code == 200 assert len(response.json()) == 2 repo.get_all_users.assert_awaited_once_with(skip=5, limit=2) def test_get_user_rejects_non_owner_non_admin(): repo = SimpleNamespace(get_user_by_id=AsyncMock()) client = _build_client(repo, current_user=make_user(id=2, role=UserRole.USER)) response = client.get("/users/3") assert response.status_code == 403 assert response.json()["detail"] == "You don't have permission to view this user" repo.get_user_by_id.assert_not_awaited() def test_update_user_blocks_role_change_for_non_admin(): repo = SimpleNamespace( get_user_by_id=AsyncMock(return_value=make_user(id=1)), update_user=AsyncMock(), ) client = _build_client(repo, current_user=make_user(id=1, role=UserRole.USER)) response = client.put("/users/1", json={"role": "ADMIN"}) assert response.status_code == 403 assert response.json()["detail"] == "Only admins can change user roles" repo.update_user.assert_not_awaited() def test_delete_user_blocks_self_delete_for_admin(): admin_user = make_user(id=1, role=UserRole.ADMIN, is_superuser=True) repo = SimpleNamespace(delete_user=AsyncMock()) client = _build_client(repo, admin_user=admin_user) response = client.delete("/users/1") assert response.status_code == 400 assert response.json()["detail"] == "You cannot delete your own account" repo.delete_user.assert_not_awaited() def test_activate_user_updates_active_flag(): repo = SimpleNamespace( update_user=AsyncMock(return_value=make_user(id=2, is_active=True)), ) client = _build_client( repo, admin_user=make_user(id=1, role=UserRole.ADMIN, is_superuser=True), ) response = client.post("/users/2/activate") assert response.status_code == 200 assert response.json()["is_active"] is True user_update = repo.update_user.await_args.args[1] assert user_update.is_active is True