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>
168 lines
5.7 KiB
Python
168 lines
5.7 KiB
Python
"""Tests for Notfallplan routes and schemas (notfallplan_routes.py)."""
|
|
|
|
import pytest
|
|
from compliance.api.notfallplan_routes import (
|
|
ContactCreate,
|
|
ContactUpdate,
|
|
ScenarioCreate,
|
|
ScenarioUpdate,
|
|
ChecklistCreate,
|
|
ExerciseCreate,
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ContactCreate
|
|
# =============================================================================
|
|
|
|
class TestContactCreate:
|
|
def test_minimal_valid(self):
|
|
req = ContactCreate(name="Max Mustermann")
|
|
assert req.name == "Max Mustermann"
|
|
assert req.is_primary is False
|
|
assert req.available_24h is False
|
|
assert req.email is None
|
|
assert req.phone is None
|
|
|
|
def test_full_contact(self):
|
|
req = ContactCreate(
|
|
name="Anna Schmidt",
|
|
role="DSB",
|
|
email="anna@example.com",
|
|
phone="+49 160 12345678",
|
|
is_primary=True,
|
|
available_24h=True,
|
|
)
|
|
assert req.role == "DSB"
|
|
assert req.is_primary is True
|
|
assert req.available_24h is True
|
|
|
|
def test_serialization(self):
|
|
req = ContactCreate(name="Test Kontakt", role="IT-Leiter")
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data["name"] == "Test Kontakt"
|
|
assert data["role"] == "IT-Leiter"
|
|
assert "email" not in data
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ContactUpdate
|
|
# =============================================================================
|
|
|
|
class TestContactUpdate:
|
|
def test_empty_update(self):
|
|
req = ContactUpdate()
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {}
|
|
|
|
def test_partial_update(self):
|
|
req = ContactUpdate(phone="+49 170 9876543", available_24h=True)
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {"phone": "+49 170 9876543", "available_24h": True}
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ScenarioCreate
|
|
# =============================================================================
|
|
|
|
class TestScenarioCreate:
|
|
def test_minimal_valid(self):
|
|
req = ScenarioCreate(title="Datenpanne")
|
|
assert req.title == "Datenpanne"
|
|
assert req.severity == "medium"
|
|
assert req.is_active is True
|
|
assert req.response_steps == []
|
|
|
|
def test_with_response_steps(self):
|
|
steps = ["Schritt 1: Incident identifizieren", "Schritt 2: DSB informieren"]
|
|
req = ScenarioCreate(
|
|
title="Ransomware-Angriff",
|
|
category="system_failure",
|
|
severity="critical",
|
|
response_steps=steps,
|
|
estimated_recovery_time=48,
|
|
)
|
|
assert req.category == "system_failure"
|
|
assert req.severity == "critical"
|
|
assert len(req.response_steps) == 2
|
|
assert req.estimated_recovery_time == 48
|
|
|
|
def test_full_serialization(self):
|
|
req = ScenarioCreate(
|
|
title="Phishing",
|
|
category="data_breach",
|
|
severity="high",
|
|
description="Mitarbeiter wurde Opfer eines Phishing-Angriffs",
|
|
)
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data["severity"] == "high"
|
|
assert data["category"] == "data_breach"
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ScenarioUpdate
|
|
# =============================================================================
|
|
|
|
class TestScenarioUpdate:
|
|
def test_empty_update(self):
|
|
req = ScenarioUpdate()
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {}
|
|
|
|
def test_severity_update(self):
|
|
req = ScenarioUpdate(severity="low")
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data == {"severity": "low"}
|
|
|
|
def test_deactivate(self):
|
|
req = ScenarioUpdate(is_active=False)
|
|
data = req.model_dump(exclude_none=True)
|
|
assert data["is_active"] is False
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ChecklistCreate
|
|
# =============================================================================
|
|
|
|
class TestChecklistCreate:
|
|
def test_minimal_valid(self):
|
|
req = ChecklistCreate(title="DSB benachrichtigen")
|
|
assert req.title == "DSB benachrichtigen"
|
|
assert req.is_required is True
|
|
assert req.order_index == 0
|
|
assert req.scenario_id is None
|
|
|
|
def test_with_scenario_link(self):
|
|
req = ChecklistCreate(
|
|
title="IT-Team alarmieren",
|
|
scenario_id="550e8400-e29b-41d4-a716-446655440000",
|
|
order_index=1,
|
|
is_required=True,
|
|
)
|
|
assert req.scenario_id == "550e8400-e29b-41d4-a716-446655440000"
|
|
assert req.order_index == 1
|
|
|
|
|
|
# =============================================================================
|
|
# Schema Tests — ExerciseCreate
|
|
# =============================================================================
|
|
|
|
class TestExerciseCreate:
|
|
def test_minimal_valid(self):
|
|
req = ExerciseCreate(title="Jahresübung 2026")
|
|
assert req.title == "Jahresübung 2026"
|
|
assert req.participants == []
|
|
assert req.outcome is None
|
|
|
|
def test_full_exercise(self):
|
|
req = ExerciseCreate(
|
|
title="Ransomware-Simulation",
|
|
scenario_id="550e8400-e29b-41d4-a716-446655440000",
|
|
participants=["Max Mustermann", "Anna Schmidt"],
|
|
outcome="passed",
|
|
notes="Übung verlief planmäßig",
|
|
)
|
|
assert req.outcome == "passed"
|
|
assert len(req.participants) == 2
|
|
assert req.notes == "Übung verlief planmäßig"
|