test: improve coverage for app/views/audit_logs.py from 61% to 100%
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/fbdb1e8c-ede3-4574-b0b6-7d5df3496320
This commit is contained in:
@@ -5,12 +5,15 @@ Covers the audit service (recording, querying, SIEM forwarding),
|
|||||||
the REST API endpoints, and the admin viewer page.
|
the REST API endpoints, and the admin viewer page.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
import socket
|
import socket
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, Mock, PropertyMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from itsdangerous import TimestampSigner
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.pool import StaticPool
|
from sqlalchemy.pool import StaticPool
|
||||||
@@ -645,6 +648,16 @@ class TestAuditLogAPI:
|
|||||||
# View tests
|
# View tests
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_TEST_SESSION_SECRET = "test_secret_key_for_testing_must_be_at_least_32_characters_long"
|
||||||
|
|
||||||
|
|
||||||
|
def _make_admin_session_cookie() -> str:
|
||||||
|
"""Create a signed session cookie with admin user data for integration tests."""
|
||||||
|
session_data = {"user": {"id": "admin", "is_admin": True}}
|
||||||
|
signer = TimestampSigner(_TEST_SESSION_SECRET)
|
||||||
|
data = base64.b64encode(json.dumps(session_data).encode()).decode("utf-8")
|
||||||
|
return signer.sign(data).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration
|
@pytest.mark.integration
|
||||||
class TestAuditLogView:
|
class TestAuditLogView:
|
||||||
@@ -655,3 +668,85 @@ class TestAuditLogView:
|
|||||||
resp = client.get("/admin/audit-logs")
|
resp = client.get("/admin/audit-logs")
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
assert "Audit Logs" in resp.text
|
assert "Audit Logs" in resp.text
|
||||||
|
|
||||||
|
def test_audit_logs_page_accessible_with_admin_session(self, client):
|
||||||
|
"""GET /admin/audit-logs with admin session cookie returns 200."""
|
||||||
|
client.cookies.set("session", _make_admin_session_cookie())
|
||||||
|
resp = client.get("/admin/audit-logs", follow_redirects=False)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert "Audit Logs" in resp.text
|
||||||
|
|
||||||
|
def test_audit_logs_page_redirects_non_admin(self, client):
|
||||||
|
"""GET /admin/audit-logs without admin session redirects to home."""
|
||||||
|
resp = client.get("/admin/audit-logs", follow_redirects=False)
|
||||||
|
assert resp.status_code == 302
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
class TestAuditLogsPageUnit:
|
||||||
|
"""Unit tests for the audit_logs_page view function (lines 29-43)."""
|
||||||
|
|
||||||
|
@patch("app.views.audit_logs.templates")
|
||||||
|
@patch("app.views.audit_logs.settings")
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_audit_logs_page_siem_disabled(self, mock_settings, mock_templates):
|
||||||
|
"""Renders the template with siem_transport=None when SIEM is disabled."""
|
||||||
|
from app.views.audit_logs import audit_logs_page
|
||||||
|
|
||||||
|
mock_settings.audit_siem_enabled = False
|
||||||
|
mock_settings.version = "2.0.0"
|
||||||
|
|
||||||
|
mock_request = Mock()
|
||||||
|
mock_request.session = {"user": {"id": "admin", "is_admin": True}}
|
||||||
|
mock_db = Mock()
|
||||||
|
|
||||||
|
await audit_logs_page(mock_request, mock_db)
|
||||||
|
|
||||||
|
mock_templates.TemplateResponse.assert_called_once()
|
||||||
|
call_args = mock_templates.TemplateResponse.call_args
|
||||||
|
assert call_args[0][0] == "audit_logs.html"
|
||||||
|
context = call_args[0][1]
|
||||||
|
assert context["siem_enabled"] is False
|
||||||
|
assert context["siem_transport"] is None
|
||||||
|
assert context["app_version"] == "2.0.0"
|
||||||
|
|
||||||
|
@patch("app.views.audit_logs.templates")
|
||||||
|
@patch("app.views.audit_logs.settings")
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_audit_logs_page_siem_enabled(self, mock_settings, mock_templates):
|
||||||
|
"""Renders the template with siem_transport set when SIEM is enabled."""
|
||||||
|
from app.views.audit_logs import audit_logs_page
|
||||||
|
|
||||||
|
mock_settings.audit_siem_enabled = True
|
||||||
|
mock_settings.audit_siem_transport = "syslog"
|
||||||
|
mock_settings.version = "2.0.0"
|
||||||
|
|
||||||
|
mock_request = Mock()
|
||||||
|
mock_request.session = {"user": {"id": "admin", "is_admin": True}}
|
||||||
|
mock_db = Mock()
|
||||||
|
|
||||||
|
await audit_logs_page(mock_request, mock_db)
|
||||||
|
|
||||||
|
mock_templates.TemplateResponse.assert_called_once()
|
||||||
|
call_args = mock_templates.TemplateResponse.call_args
|
||||||
|
context = call_args[0][1]
|
||||||
|
assert context["siem_enabled"] is True
|
||||||
|
assert context["siem_transport"] == "syslog"
|
||||||
|
|
||||||
|
@patch("app.views.audit_logs.settings")
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_audit_logs_page_raises_500_on_error(self, mock_settings):
|
||||||
|
"""Raises HTTP 500 when an unexpected error occurs while loading the page."""
|
||||||
|
from app.views.audit_logs import audit_logs_page
|
||||||
|
|
||||||
|
# Make accessing audit_siem_enabled raise an exception to trigger the except branch
|
||||||
|
type(mock_settings).audit_siem_enabled = PropertyMock(side_effect=RuntimeError("settings unavailable"))
|
||||||
|
|
||||||
|
mock_request = Mock()
|
||||||
|
mock_request.session = {"user": {"id": "admin", "is_admin": True}}
|
||||||
|
mock_db = Mock()
|
||||||
|
|
||||||
|
with pytest.raises(HTTPException) as exc_info:
|
||||||
|
await audit_logs_page(mock_request, mock_db)
|
||||||
|
assert exc_info.value.status_code == 500
|
||||||
|
assert "Failed to load audit logs page" in exc_info.value.detail
|
||||||
|
|||||||
Reference in New Issue
Block a user