All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 37s
CI / test-python-backend-compliance (push) Successful in 34s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 18s
Alle 7 Betrieb-Module von 30–75% auf 100% gebracht: **Gruppe 1 — UI-Ergänzungen (Backend bereits vorhanden):** - incidents/page.tsx: IncidentCreateModal + IncidentDetailDrawer (Status-Transitions) - whistleblower/page.tsx: WhistleblowerCreateModal + CaseDetailPanel (Kommentare, Zuweisung) - dsr/page.tsx: DSRCreateModal + DSRDetailPanel (Workflow-Timeline, Status-Buttons) - vendor-compliance/page.tsx: VendorCreateModal + "Neuer Vendor" Button **Gruppe 2 — Escalations Full Stack:** - Migration 011: compliance_escalations Tabelle - Backend: escalation_routes.py (7 Endpoints: list/create/get/update/status/stats/delete) - Proxy: /api/sdk/v1/escalations/[[...path]] → backend:8002 - Frontend: Mock-Array komplett ersetzt durch echte API + EscalationCreateModal + EscalationDetailDrawer **Gruppe 2 — Consent Templates:** - Migration 010: compliance_consent_email_templates + compliance_consent_gdpr_processes (7+7 Seed-Einträge) - Backend: consent_template_routes.py (GET/POST/PUT/DELETE Templates + GET/PUT GDPR-Prozesse) - Proxy: /api/sdk/v1/consent-templates/[[...path]] - Frontend: consent-management/page.tsx lädt Templates + Prozesse aus DB (ApiTemplateEditor, ApiGdprProcessEditor) **Gruppe 3 — Notfallplan:** - Migration 012: 4 Tabellen (contacts, scenarios, checklists, exercises) - Backend: notfallplan_routes.py (vollständiges CRUD + /stats) - Proxy: /api/sdk/v1/notfallplan/[[...path]] - Frontend: notfallplan/page.tsx — DB-backed Kontakte + Szenarien + Übungen, ContactCreateModal + ScenarioCreateModal **Infrastruktur:** - __init__.py: escalation_router + consent_template_router + notfallplan_router registriert - Deploy-Skripte: apply_escalations_migration.sh, apply_consent_templates_migration.sh, apply_notfallplan_migration.sh - Tests: 40 neue Tests (test_escalation_routes.py, test_consent_template_routes.py, test_notfallplan_routes.py) - flow-data.ts: Completion aller 7 Module auf 100% gesetzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
"""Tests for escalation routes and schemas (escalation_routes.py)."""
|
|
|
|
import pytest
|
|
from unittest.mock import MagicMock
|
|
from datetime import datetime
|
|
|
|
from compliance.api.escalation_routes import (
|
|
EscalationCreate,
|
|
EscalationUpdate,
|
|
EscalationStatusUpdate,
|
|
_row_to_dict,
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — EscalationCreate
|
|
# =============================================================================
|
|
|
|
class TestEscalationCreate:
|
|
def test_minimal_valid(self):
|
|
req = EscalationCreate(title="Test Eskalation")
|
|
assert req.title == "Test Eskalation"
|
|
assert req.priority == "medium"
|
|
assert req.description is None
|
|
assert req.category is None
|
|
assert req.assignee is None
|
|
|
|
def test_full_values(self):
|
|
req = EscalationCreate(
|
|
title="DSGVO-Verstoß",
|
|
description="Datenleck entdeckt",
|
|
priority="critical",
|
|
category="dsgvo_breach",
|
|
assignee="admin@example.com",
|
|
reporter="user@example.com",
|
|
source_module="incidents",
|
|
)
|
|
assert req.title == "DSGVO-Verstoß"
|
|
assert req.priority == "critical"
|
|
assert req.category == "dsgvo_breach"
|
|
assert req.source_module == "incidents"
|
|
|
|
def test_serialization(self):
|
|
req = EscalationCreate(title="Test", priority="high")
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data["title"] == "Test"
|
|
assert data["priority"] == "high"
|
|
assert "description" not in data
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — EscalationUpdate
|
|
# =============================================================================
|
|
|
|
class TestEscalationUpdate:
|
|
def test_empty_update(self):
|
|
req = EscalationUpdate()
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {}
|
|
|
|
def test_partial_update(self):
|
|
req = EscalationUpdate(assignee="new@example.com", priority="low")
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {"assignee": "new@example.com", "priority": "low"}
|
|
|
|
def test_title_update(self):
|
|
req = EscalationUpdate(title="Aktualisierter Titel")
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data["title"] == "Aktualisierter Titel"
|
|
assert "priority" not in data
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — EscalationStatusUpdate
|
|
# =============================================================================
|
|
|
|
class TestEscalationStatusUpdate:
|
|
def test_status_only(self):
|
|
req = EscalationStatusUpdate(status="in_progress")
|
|
assert req.status == "in_progress"
|
|
assert req.resolved_at is None
|
|
|
|
def test_with_resolved_at(self):
|
|
ts = datetime(2026, 3, 1, 12, 0, 0)
|
|
req = EscalationStatusUpdate(status="resolved", resolved_at=ts)
|
|
assert req.status == "resolved"
|
|
assert req.resolved_at == ts
|
|
|
|
def test_closed_status(self):
|
|
req = EscalationStatusUpdate(status="closed")
|
|
assert req.status == "closed"
|
|
|
|
|
|
# =============================================================================
|
|
# Helper Tests — _row_to_dict
|
|
# =============================================================================
|
|
|
|
class TestRowToDict:
|
|
def test_basic_conversion(self):
|
|
row = MagicMock()
|
|
row._mapping = {"id": "abc-123", "title": "Test", "priority": "medium"}
|
|
result = _row_to_dict(row)
|
|
assert result["id"] == "abc-123"
|
|
assert result["title"] == "Test"
|
|
assert result["priority"] == "medium"
|
|
|
|
def test_datetime_serialized(self):
|
|
ts = datetime(2026, 3, 1, 10, 0, 0)
|
|
row = MagicMock()
|
|
row._mapping = {"id": "abc", "created_at": ts}
|
|
result = _row_to_dict(row)
|
|
assert result["created_at"] == ts.isoformat()
|
|
|
|
def test_none_values_preserved(self):
|
|
row = MagicMock()
|
|
row._mapping = {"id": "abc", "description": None, "resolved_at": None}
|
|
result = _row_to_dict(row)
|
|
assert result["description"] is None
|
|
assert result["resolved_at"] is None
|