213 lines
7.0 KiB
Python
213 lines
7.0 KiB
Python
"""
|
|
Tests for user management endpoints.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
|
|
from cpv3.modules.users.models import User
|
|
|
|
|
|
class TestListUsersEndpoint:
|
|
"""Tests for GET /api/users/."""
|
|
|
|
async def test_list_users_authenticated(
|
|
self, auth_client: AsyncClient, test_user: User
|
|
):
|
|
"""Test listing users as authenticated user."""
|
|
response = await auth_client.get("/api/users/")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert isinstance(data, list)
|
|
|
|
async def test_list_users_unauthenticated(self, async_client: AsyncClient):
|
|
"""Test listing users without auth returns 401."""
|
|
response = await async_client.get("/api/users/")
|
|
|
|
assert response.status_code == 401
|
|
|
|
|
|
class TestCreateUserEndpoint:
|
|
"""Tests for POST /api/users/."""
|
|
|
|
async def test_create_user_as_staff(self, staff_client: AsyncClient):
|
|
"""Test staff can create a new user."""
|
|
response = await staff_client.post(
|
|
"/api/users/",
|
|
json={
|
|
"username": "newcreateduser",
|
|
"email": "newcreated@example.com",
|
|
"password": "password123",
|
|
"first_name": "New",
|
|
"last_name": "Created",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 201
|
|
data = response.json()
|
|
assert data["username"] == "newcreateduser"
|
|
assert data["email"] == "newcreated@example.com"
|
|
|
|
async def test_create_user_unauthenticated(self, async_client: AsyncClient):
|
|
"""Test creating user without auth returns 401."""
|
|
response = await async_client.post(
|
|
"/api/users/",
|
|
json={
|
|
"username": "newuser",
|
|
"email": "new@example.com",
|
|
"password": "password123",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 401
|
|
|
|
|
|
class TestMeEndpoint:
|
|
"""Tests for GET /api/users/me/."""
|
|
|
|
async def test_me_returns_current_user(
|
|
self, auth_client: AsyncClient, test_user: User
|
|
):
|
|
"""Test getting current user info."""
|
|
response = await auth_client.get("/api/users/me/")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["username"] == test_user.username
|
|
assert data["email"] == test_user.email
|
|
assert data["id"] == str(test_user.id)
|
|
|
|
async def test_me_unauthenticated(self, async_client: AsyncClient):
|
|
"""Test getting current user without auth returns 401."""
|
|
response = await async_client.get("/api/users/me/")
|
|
|
|
assert response.status_code == 401
|
|
|
|
|
|
class TestRetrieveUserEndpoint:
|
|
"""Tests for GET /api/users/{user_id}/."""
|
|
|
|
async def test_retrieve_own_user(self, auth_client: AsyncClient, test_user: User):
|
|
"""Test user can retrieve their own info."""
|
|
response = await auth_client.get(f"/api/users/{test_user.id}/")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["id"] == str(test_user.id)
|
|
assert data["username"] == test_user.username
|
|
|
|
async def test_retrieve_other_user_as_staff(
|
|
self, staff_client: AsyncClient, test_user: User
|
|
):
|
|
"""Test staff can retrieve other user's info."""
|
|
response = await staff_client.get(f"/api/users/{test_user.id}/")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["id"] == str(test_user.id)
|
|
|
|
async def test_retrieve_nonexistent_user(self, auth_client: AsyncClient):
|
|
"""Test retrieving nonexistent user returns 404."""
|
|
fake_id = uuid.uuid4()
|
|
response = await auth_client.get(f"/api/users/{fake_id}/")
|
|
|
|
assert response.status_code == 404
|
|
assert response.json()["detail"] == "Not found"
|
|
|
|
async def test_retrieve_other_user_forbidden(
|
|
self, auth_client: AsyncClient, other_user: User
|
|
):
|
|
"""Test regular user cannot retrieve other user's info."""
|
|
response = await auth_client.get(f"/api/users/{other_user.id}/")
|
|
|
|
assert response.status_code == 403
|
|
assert response.json()["detail"] == "Forbidden"
|
|
|
|
|
|
class TestPatchUserEndpoint:
|
|
"""Tests for PATCH /api/users/{user_id}/."""
|
|
|
|
async def test_patch_own_user(self, auth_client: AsyncClient, test_user: User):
|
|
"""Test user can update their own info."""
|
|
response = await auth_client.patch(
|
|
f"/api/users/{test_user.id}/",
|
|
json={"first_name": "Updated", "last_name": "Name"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["first_name"] == "Updated"
|
|
assert data["last_name"] == "Name"
|
|
|
|
async def test_patch_other_user_as_staff(
|
|
self, staff_client: AsyncClient, test_user: User
|
|
):
|
|
"""Test staff can update other user's info."""
|
|
response = await staff_client.patch(
|
|
f"/api/users/{test_user.id}/",
|
|
json={"first_name": "StaffUpdated"},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["first_name"] == "StaffUpdated"
|
|
|
|
async def test_patch_nonexistent_user(self, auth_client: AsyncClient):
|
|
"""Test patching nonexistent user returns 404."""
|
|
fake_id = uuid.uuid4()
|
|
response = await auth_client.patch(
|
|
f"/api/users/{fake_id}/",
|
|
json={"first_name": "Test"},
|
|
)
|
|
|
|
assert response.status_code == 404
|
|
|
|
async def test_patch_other_user_forbidden(
|
|
self, auth_client: AsyncClient, other_user: User
|
|
):
|
|
"""Test regular user cannot update other user's info."""
|
|
response = await auth_client.patch(
|
|
f"/api/users/{other_user.id}/",
|
|
json={"first_name": "Hacked"},
|
|
)
|
|
|
|
assert response.status_code == 403
|
|
|
|
|
|
class TestDeleteUserEndpoint:
|
|
"""Tests for DELETE /api/users/{user_id}/."""
|
|
|
|
async def test_delete_own_user(self, auth_client: AsyncClient, test_user: User):
|
|
"""Test user can delete (deactivate) their own account."""
|
|
response = await auth_client.delete(f"/api/users/{test_user.id}/")
|
|
|
|
assert response.status_code == 204
|
|
|
|
async def test_delete_other_user_as_staff(
|
|
self, staff_client: AsyncClient, test_user: User
|
|
):
|
|
"""Test staff can delete other user's account."""
|
|
response = await staff_client.delete(f"/api/users/{test_user.id}/")
|
|
|
|
assert response.status_code == 204
|
|
|
|
async def test_delete_nonexistent_user(self, auth_client: AsyncClient):
|
|
"""Test deleting nonexistent user returns 404."""
|
|
fake_id = uuid.uuid4()
|
|
response = await auth_client.delete(f"/api/users/{fake_id}/")
|
|
|
|
assert response.status_code == 404
|
|
|
|
async def test_delete_other_user_forbidden(
|
|
self, auth_client: AsyncClient, other_user: User
|
|
):
|
|
"""Test regular user cannot delete other user's account."""
|
|
response = await auth_client.delete(f"/api/users/{other_user.id}/")
|
|
|
|
assert response.status_code == 403
|