"""Tests for user management endpoints.""" from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.models.user import User def test_get_current_user(client: TestClient, test_user: User, auth_headers: dict) -> None: """Test getting current user info.""" response = client.get("/api/users/me", headers=auth_headers) assert response.status_code == 200 data = response.json() assert data["email"] == "test@example.com" assert data["role"] == "user" def test_list_users_admin( client: TestClient, test_user: User, admin_headers: dict ) -> None: """Test listing all users as admin.""" response = client.get("/api/admin/users", headers=admin_headers) assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) >= 2 # test_user + admin_user def test_list_users_unauthorized(client: TestClient, auth_headers: dict) -> None: """Test listing users as non-admin (should fail).""" response = client.get("/api/admin/users", headers=auth_headers) assert response.status_code == 403 def test_list_users_filter_by_role(client: TestClient, admin_headers: dict) -> None: """Test filtering users by role.""" response = client.get("/api/admin/users?role=admin", headers=admin_headers) assert response.status_code == 200 data = response.json() assert all(user["role"] == "admin" for user in data) def test_create_user_admin(client: TestClient, admin_headers: dict) -> None: """Test creating a new user as admin.""" response = client.post( "/api/admin/users", headers=admin_headers, json={ "email": "newuser@example.com", "full_name": "New User", "password": "newpassword", "role": "user", "organization": "Test Org", }, ) assert response.status_code == 201 data = response.json() assert data["email"] == "newuser@example.com" assert data["full_name"] == "New User" assert data["role"] == "user" assert data["organization"] == "Test Org" assert data["is_active"] is True def test_create_user_duplicate_email( client: TestClient, test_user: User, admin_headers: dict ) -> None: """Test creating user with duplicate email.""" response = client.post( "/api/admin/users", headers=admin_headers, json={ "email": "test@example.com", # Already exists "full_name": "Duplicate User", "password": "password", "role": "user", }, ) assert response.status_code == 400 assert "already exists" in response.json()["detail"] def test_create_user_invalid_role(client: TestClient, admin_headers: dict) -> None: """Test creating user with invalid role.""" response = client.post( "/api/admin/users", headers=admin_headers, json={ "email": "invalid@example.com", "full_name": "Invalid User", "password": "password", "role": "superadmin", # Invalid role }, ) assert response.status_code == 400 assert "admin" in response.json()["detail"].lower() def test_update_user_admin(client: TestClient, test_user: User, admin_headers: dict) -> None: """Test updating user as admin.""" response = client.put( f"/api/admin/users/{test_user.id}", headers=admin_headers, json={ "full_name": "Updated Name", "organization": "Updated Org", }, ) assert response.status_code == 200 data = response.json() assert data["full_name"] == "Updated Name" assert data["organization"] == "Updated Org" assert data["email"] == "test@example.com" # Should remain unchanged def test_update_user_not_found(client: TestClient, admin_headers: dict) -> None: """Test updating non-existent user.""" response = client.put( "/api/admin/users/99999", headers=admin_headers, json={"full_name": "Updated"}, ) assert response.status_code == 404 def test_update_user_status(client: TestClient, test_user: User, admin_headers: dict) -> None: """Test deactivating user.""" response = client.patch( f"/api/admin/users/{test_user.id}/status", headers=admin_headers, json={"is_active": False}, ) assert response.status_code == 200 data = response.json() assert data["is_active"] is False # Verify user cannot login login_response = client.post( "/api/auth/login", json={"email": "test@example.com", "password": "testpassword"}, ) assert login_response.status_code == 403 def test_reset_password( client: TestClient, test_user: User, admin_headers: dict, db: Session ) -> None: """Test resetting user password.""" response = client.post( f"/api/admin/users/{test_user.id}/reset-password", headers=admin_headers, json={"new_password": "newpassword123"}, ) assert response.status_code == 200 # Verify new password works login_response = client.post( "/api/auth/login", json={"email": "test@example.com", "password": "newpassword123"}, ) assert login_response.status_code == 200 # Verify old password doesn't work old_login_response = client.post( "/api/auth/login", json={"email": "test@example.com", "password": "testpassword"}, ) assert old_login_response.status_code == 401 def test_reset_password_not_found(client: TestClient, admin_headers: dict) -> None: """Test resetting password for non-existent user.""" response = client.post( "/api/admin/users/99999/reset-password", headers=admin_headers, json={"new_password": "newpassword"}, ) assert response.status_code == 404 # ===== Audit Log Integration Tests ===== def test_user_creation_creates_audit_log( client: TestClient, admin_token: str, test_admin: User, db: Session, ) -> None: """Test that creating a user creates an audit log entry.""" from app.models.audit_log import AuditLog response = client.post( "/api/admin/users", headers={"Authorization": f"Bearer {admin_token}"}, json={ "email": "newuser@example.com", "full_name": "New User", "password": "newpassword", "role": "user", "organization": "Test Org", }, ) assert response.status_code == 201 user_id = response.json()["id"] # Check audit log was created audit = db.query(AuditLog).filter( AuditLog.action == "user_created", AuditLog.target_id == user_id ).first() assert audit is not None assert audit.target_type == "user" assert audit.user_id == test_admin.id assert audit.details == {"email": "newuser@example.com", "role": "user"} def test_user_update_creates_audit_log( client: TestClient, admin_token: str, test_admin: User, test_user: User, db: Session, ) -> None: """Test that updating a user creates an audit log entry.""" from app.models.audit_log import AuditLog response = client.put( f"/api/admin/users/{test_user.id}", headers={"Authorization": f"Bearer {admin_token}"}, json={ "full_name": "Updated Name", "role": "admin", }, ) assert response.status_code == 200 # Check audit log was created audit = db.query(AuditLog).filter( AuditLog.action == "user_updated", AuditLog.target_id == test_user.id ).first() assert audit is not None assert audit.target_type == "user" assert audit.user_id == test_admin.id # Should track changed fields assert "full_name" in audit.details["updated_fields"] assert "role" in audit.details["updated_fields"]