Files
space-booking/backend/tests/test_audit_log.py
Claude Agent df4031d99c feat: Space Booking System - MVP complet
Sistem web pentru rezervarea de birouri și săli de ședință
cu flux de aprobare administrativă.

Stack: FastAPI + Vue.js 3 + SQLite + TypeScript

Features implementate:
- Autentificare JWT + Self-registration cu email verification
- CRUD Spații, Utilizatori, Settings (Admin)
- Calendar interactiv (FullCalendar) cu drag-and-drop
- Creare rezervări cu validare (durată, program, overlap, max/zi)
- Rezervări recurente (săptămânal)
- Admin: aprobare/respingere/anulare cereri
- Admin: creare directă rezervări (bypass approval)
- Admin: editare orice rezervare
- User: editare/anulare rezervări proprii
- Notificări in-app (bell icon + dropdown)
- Notificări email (async SMTP cu BackgroundTasks)
- Jurnal acțiuni administrative (audit log)
- Rapoarte avansate (utilizare, top users, approval rate)
- Șabloane rezervări (booking templates)
- Atașamente fișiere (upload/download)
- Conflict warnings (verificare disponibilitate real-time)
- Integrare Google Calendar (OAuth2)
- Suport timezone (UTC storage + user preference)
- 225+ teste backend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 17:51:29 +00:00

166 lines
4.9 KiB
Python

"""Tests for audit log API."""
from datetime import datetime, timedelta
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from app.models.user import User
from app.services.audit_service import log_action
def test_get_audit_logs(client: TestClient, admin_token: str, db_session: Session, test_admin: User) -> None:
"""Test getting audit logs."""
# Create some audit logs
log_action(db_session, "booking_approved", test_admin.id, "booking", 1)
log_action(db_session, "space_created", test_admin.id, "space", 2)
response = client.get(
"/api/admin/audit-log",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
data = response.json()
assert len(data) >= 2
assert data[0]["user_name"] == test_admin.full_name
assert data[0]["user_email"] == test_admin.email
def test_filter_audit_logs_by_action(
client: TestClient,
admin_token: str,
db_session: Session,
test_admin: User
) -> None:
"""Test filtering by action."""
log_action(db_session, "booking_approved", test_admin.id, "booking", 1)
log_action(db_session, "space_created", test_admin.id, "space", 2)
response = client.get(
"/api/admin/audit-log?action=booking_approved",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
data = response.json()
assert all(log["action"] == "booking_approved" for log in data)
def test_filter_audit_logs_by_date(
client: TestClient,
admin_token: str,
db_session: Session,
test_admin: User
) -> None:
"""Test filtering by date range."""
log_action(db_session, "booking_approved", test_admin.id, "booking", 1)
# Test with date filters
yesterday = (datetime.utcnow() - timedelta(days=1)).isoformat()
tomorrow = (datetime.utcnow() + timedelta(days=1)).isoformat()
response = client.get(
f"/api/admin/audit-log?start_date={yesterday}&end_date={tomorrow}",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
def test_audit_logs_require_admin(client: TestClient, user_token: str) -> None:
"""Test that regular users cannot access audit logs."""
response = client.get(
"/api/admin/audit-log",
headers={"Authorization": f"Bearer {user_token}"}
)
assert response.status_code == 403
def test_pagination_audit_logs(
client: TestClient,
admin_token: str,
db_session: Session,
test_admin: User
) -> None:
"""Test pagination."""
# Create multiple logs
for i in range(10):
log_action(db_session, f"action_{i}", test_admin.id, "booking", i)
# Get page 1
response = client.get(
"/api/admin/audit-log?page=1&limit=5",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
assert len(response.json()) == 5
# Get page 2
response = client.get(
"/api/admin/audit-log?page=2&limit=5",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
assert len(response.json()) == 5
def test_audit_logs_with_details(
client: TestClient,
admin_token: str,
db_session: Session,
test_admin: User
) -> None:
"""Test audit logs with additional details."""
log_action(
db_session,
"booking_rejected",
test_admin.id,
"booking",
1,
details={"reason": "Room not available", "original_status": "pending"}
)
response = client.get(
"/api/admin/audit-log",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
log_entry = next((log for log in data if log["action"] == "booking_rejected"), None)
assert log_entry is not None
assert log_entry["details"]["reason"] == "Room not available"
assert log_entry["details"]["original_status"] == "pending"
def test_audit_logs_ordered_by_date_desc(
client: TestClient,
admin_token: str,
db_session: Session,
test_admin: User
) -> None:
"""Test that audit logs are ordered by date descending (newest first)."""
# Create logs with different actions to identify them
log_action(db_session, "first_action", test_admin.id, "booking", 1)
log_action(db_session, "second_action", test_admin.id, "booking", 2)
log_action(db_session, "third_action", test_admin.id, "booking", 3)
response = client.get(
"/api/admin/audit-log",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert response.status_code == 200
data = response.json()
assert len(data) >= 3
# Most recent should be first
assert data[0]["action"] == "third_action"
assert data[1]["action"] == "second_action"
assert data[2]["action"] == "first_action"