omnidiag / tests /test_audit_log.py
yahyoha's picture
test: add OmniDiag test suite — 181 tests across 7 new files
54286b5
Raw
History Blame Contribute Delete
4.52 kB
"""
Integration Tests — AuditMiddleware (I-7 through I-11)
Verifies that every API request is recorded in the audit_logs table.
The AuditMiddleware uses AsyncSessionLocal from backend.database, which points to
the production DB. We patch it to use TestSessionLocal so the middleware writes
to the same in-memory SQLite that fixtures use.
"""
import pytest
from unittest.mock import patch
from sqlalchemy import select
from backend.db_models.audit_log import AuditLog
# TestSessionLocal is the in-memory session factory defined in conftest.py
from tests.conftest import TestSessionLocal
HEART_PAYLOAD = {
"Age": 55, "Sex": "M", "ChestPainType": "ATA", "RestingBP": 130,
"Cholesterol": 250, "FastingBS": 0, "RestingECG": "Normal",
"MaxHR": 150, "ExerciseAngina": "N", "Oldpeak": 1.5, "ST_Slope": "Up",
}
@pytest.fixture(autouse=True)
def patch_middleware_session(db_tables):
"""Route AuditMiddleware DB writes to the test in-memory SQLite database."""
with patch("backend.middleware.audit.AsyncSessionLocal", TestSessionLocal):
yield
class TestAuditMiddlewareLogsRequests:
async def test_authenticated_predict_creates_audit_log(self, client, doctor_token, db_session):
resp = await client.post(
"/api/v4/heart_disease/predict",
json=HEART_PAYLOAD,
headers={"Authorization": f"Bearer {doctor_token}"},
)
assert resp.status_code == 200
result = await db_session.execute(
select(AuditLog).where(AuditLog.endpoint == "/api/v4/heart_disease/predict")
)
logs = result.scalars().all()
assert len(logs) >= 1, "Expected at least one audit log entry for /predict"
async def test_audit_log_has_correct_status_code(self, client, doctor_token, db_session):
resp = await client.post(
"/api/v4/heart_disease/predict",
json=HEART_PAYLOAD,
headers={"Authorization": f"Bearer {doctor_token}"},
)
result = await db_session.execute(
select(AuditLog).where(AuditLog.endpoint == "/api/v4/heart_disease/predict")
)
logs = result.scalars().all()
assert any(log.status_code == 200 for log in logs)
async def test_audit_log_duration_ms_positive(self, client, doctor_token, db_session):
await client.post(
"/api/v4/heart_disease/predict",
json=HEART_PAYLOAD,
headers={"Authorization": f"Bearer {doctor_token}"},
)
result = await db_session.execute(
select(AuditLog).where(AuditLog.endpoint == "/api/v4/heart_disease/predict")
)
logs = result.scalars().all()
assert all(log.duration_ms is not None and log.duration_ms > 0 for log in logs)
async def test_audit_log_records_user_id_for_authenticated_request(
self, client, doctor_token, db_session
):
await client.post(
"/api/v4/heart_disease/predict",
json=HEART_PAYLOAD,
headers={"Authorization": f"Bearer {doctor_token}"},
)
result = await db_session.execute(
select(AuditLog).where(AuditLog.endpoint == "/api/v4/heart_disease/predict")
)
logs = result.scalars().all()
authenticated_logs = [log for log in logs if log.user_id is not None]
assert len(authenticated_logs) >= 1
async def test_unauthenticated_request_logs_null_user_id(self, client, db_session):
# Login endpoint is always logged; unauthenticated POST with invalid creds
await client.post(
"/auth/login",
json={"email": "nonexistent@test.com", "password": "wrongpassword"},
)
result = await db_session.execute(
select(AuditLog).where(
AuditLog.endpoint == "/auth/login",
AuditLog.user_id.is_(None),
)
)
logs = result.scalars().all()
assert len(logs) >= 1, "Expected audit log with null user_id for failed login"
async def test_audit_log_records_http_method(self, client, doctor_token, db_session):
await client.post(
"/api/v4/heart_disease/predict",
json=HEART_PAYLOAD,
headers={"Authorization": f"Bearer {doctor_token}"},
)
result = await db_session.execute(
select(AuditLog).where(AuditLog.endpoint == "/api/v4/heart_disease/predict")
)
logs = result.scalars().all()
assert any(log.method == "POST" for log in logs)