"""Tests for space management endpoints.""" from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.models.user import User def test_create_space_as_admin(client: TestClient, admin_token: str) -> None: """Test creating a space as admin.""" response = client.post( "/api/admin/spaces", json={ "name": "Conference Room A", "type": "sala", "capacity": 10, "description": "Main conference room", }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 201 data = response.json() assert data["name"] == "Conference Room A" assert data["type"] == "sala" assert data["capacity"] == 10 assert data["is_active"] is True def test_create_space_as_user_forbidden(client: TestClient, user_token: str) -> None: """Test that regular users cannot create spaces.""" response = client.post( "/api/admin/spaces", json={ "name": "Test Space", "type": "birou", "capacity": 1, }, headers={"Authorization": f"Bearer {user_token}"}, ) assert response.status_code == 403 def test_create_space_duplicate_name(client: TestClient, admin_token: str) -> None: """Test that duplicate space names are rejected.""" space_data = { "name": "Duplicate Room", "type": "sala", "capacity": 5, } # Create first space response = client.post( "/api/admin/spaces", json=space_data, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 201 # Try to create duplicate response = client.post( "/api/admin/spaces", json=space_data, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 400 assert "already exists" in response.json()["detail"] def test_create_space_invalid_capacity(client: TestClient, admin_token: str) -> None: """Test that invalid capacity is rejected.""" response = client.post( "/api/admin/spaces", json={ "name": "Invalid Space", "type": "sala", "capacity": 0, }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 422 # Validation error def test_create_space_invalid_type(client: TestClient, admin_token: str) -> None: """Test that invalid type is rejected.""" response = client.post( "/api/admin/spaces", json={ "name": "Invalid Type Space", "type": "invalid", "capacity": 5, }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 422 # Validation error def test_list_spaces_as_user(client: TestClient, user_token: str, admin_token: str) -> None: """Test that users see only active spaces.""" # Create active space client.post( "/api/admin/spaces", json={"name": "Active Space", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) # Create inactive space response = client.post( "/api/admin/spaces", json={"name": "Inactive Space", "type": "birou", "capacity": 1}, headers={"Authorization": f"Bearer {admin_token}"}, ) space_id = response.json()["id"] # Deactivate the second space client.patch( f"/api/admin/spaces/{space_id}/status", json={"is_active": False}, headers={"Authorization": f"Bearer {admin_token}"}, ) # List as user - should see only active response = client.get( "/api/spaces", headers={"Authorization": f"Bearer {user_token}"}, ) assert response.status_code == 200 spaces = response.json() names = [s["name"] for s in spaces] assert "Active Space" in names assert "Inactive Space" not in names def test_list_spaces_as_admin(client: TestClient, admin_token: str) -> None: """Test that admins see all spaces.""" # Create active space client.post( "/api/admin/spaces", json={"name": "Admin View Active", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) # Create inactive space response = client.post( "/api/admin/spaces", json={"name": "Admin View Inactive", "type": "birou", "capacity": 1}, headers={"Authorization": f"Bearer {admin_token}"}, ) space_id = response.json()["id"] # Deactivate client.patch( f"/api/admin/spaces/{space_id}/status", json={"is_active": False}, headers={"Authorization": f"Bearer {admin_token}"}, ) # List as admin - should see both response = client.get( "/api/spaces", headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 spaces = response.json() names = [s["name"] for s in spaces] assert "Admin View Active" in names assert "Admin View Inactive" in names def test_update_space(client: TestClient, admin_token: str) -> None: """Test updating a space.""" # Create space response = client.post( "/api/admin/spaces", json={"name": "Original Name", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) space_id = response.json()["id"] # Update space response = client.put( f"/api/admin/spaces/{space_id}", json={ "name": "Updated Name", "type": "birou", "capacity": 2, "description": "Updated description", }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 data = response.json() assert data["name"] == "Updated Name" assert data["type"] == "birou" assert data["capacity"] == 2 assert data["description"] == "Updated description" def test_update_space_not_found(client: TestClient, admin_token: str) -> None: """Test updating non-existent space.""" response = client.put( "/api/admin/spaces/99999", json={"name": "Test", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 404 def test_update_space_status(client: TestClient, admin_token: str) -> None: """Test activating/deactivating a space.""" # Create space response = client.post( "/api/admin/spaces", json={"name": "Toggle Space", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) space_id = response.json()["id"] # Deactivate response = client.patch( f"/api/admin/spaces/{space_id}/status", json={"is_active": False}, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 assert response.json()["is_active"] is False # Reactivate response = client.patch( f"/api/admin/spaces/{space_id}/status", json={"is_active": True}, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 assert response.json()["is_active"] is True def test_update_space_status_not_found(client: TestClient, admin_token: str) -> None: """Test updating status of non-existent space.""" response = client.patch( "/api/admin/spaces/99999/status", json={"is_active": False}, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 404 # ===== Audit Log Integration Tests ===== def test_space_creation_creates_audit_log( client: TestClient, admin_token: str, test_admin: User, db: Session, ) -> None: """Test that creating a space creates an audit log entry.""" from app.models.audit_log import AuditLog response = client.post( "/api/admin/spaces", json={ "name": "Conference Room A", "type": "sala", "capacity": 10, "description": "Main conference room", }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 201 space_id = response.json()["id"] # Check audit log was created audit = db.query(AuditLog).filter( AuditLog.action == "space_created", AuditLog.target_id == space_id ).first() assert audit is not None assert audit.target_type == "space" assert audit.user_id == test_admin.id assert audit.details == {"name": "Conference Room A", "type": "sala", "capacity": 10} def test_space_update_creates_audit_log( client: TestClient, admin_token: str, test_admin: User, db: Session, ) -> None: """Test that updating a space creates an audit log entry.""" from app.models.audit_log import AuditLog # Create space response = client.post( "/api/admin/spaces", json={"name": "Original Name", "type": "sala", "capacity": 5}, headers={"Authorization": f"Bearer {admin_token}"}, ) space_id = response.json()["id"] # Update space response = client.put( f"/api/admin/spaces/{space_id}", json={ "name": "Updated Name", "type": "birou", "capacity": 2, "description": "Updated description", }, headers={"Authorization": f"Bearer {admin_token}"}, ) assert response.status_code == 200 # Check audit log was created audit = db.query(AuditLog).filter( AuditLog.action == "space_updated", AuditLog.target_id == space_id ).first() assert audit is not None assert audit.target_type == "space" assert audit.user_id == test_admin.id # Should track all changed fields assert "name" in audit.details["updated_fields"] assert "type" in audit.details["updated_fields"] assert "capacity" in audit.details["updated_fields"] assert len(audit.details["updated_fields"]) == 4 # name, type, capacity, description