Files
breakpilot-compliance/ai-compliance-sdk/internal/ucca/escalation_test.go
Benjamin Boenisch 4435e7ea0a Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance,
AI-Compliance-SDK, Consent-SDK, Developer-Portal,
PCA-Platform, DSMS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:28 +01:00

447 lines
12 KiB
Go

package ucca
import (
"testing"
)
// ============================================================================
// EscalationTrigger Tests
// ============================================================================
func TestDetermineEscalationLevel_E0_LowRiskInfoOnly(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityYES,
RiskLevel: RiskLevelMINIMAL,
RiskScore: 10,
TriggeredRules: []TriggeredRule{
{Code: "R-INFO-001", Severity: "INFO", Description: "Informative Regel"},
},
DSFARecommended: false,
Art22Risk: false,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE0 {
t.Errorf("Expected E0 for low-risk case, got %s", level)
}
if reason == "" {
t.Error("Expected non-empty reason")
}
}
func TestDetermineEscalationLevel_E1_WarnRules(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelLOW,
RiskScore: 25,
TriggeredRules: []TriggeredRule{
{Code: "R-WARN-001", Severity: "WARN", Description: "Warnung"},
},
DSFARecommended: false,
Art22Risk: false,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE1 {
t.Errorf("Expected E1 for WARN rule, got %s", level)
}
if reason == "" {
t.Error("Expected non-empty reason")
}
}
func TestDetermineEscalationLevel_E1_RiskScore20to40(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelLOW,
RiskScore: 35,
TriggeredRules: []TriggeredRule{},
DSFARecommended: false,
Art22Risk: false,
}
level, _ := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE1 {
t.Errorf("Expected E1 for risk score 35, got %s", level)
}
}
func TestDetermineEscalationLevel_E2_Article9Data(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelMEDIUM,
RiskScore: 45,
TriggeredRules: []TriggeredRule{
{Code: "R-002", Severity: "WARN", Description: "Art. 9 Daten"},
},
DSFARecommended: false,
Art22Risk: false,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE2 {
t.Errorf("Expected E2 for Art. 9 data, got %s", level)
}
if reason == "" {
t.Error("Expected non-empty reason mentioning Art. 9")
}
}
func TestDetermineEscalationLevel_E2_DSFARecommended(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelMEDIUM,
RiskScore: 42,
TriggeredRules: []TriggeredRule{},
DSFARecommended: true,
Art22Risk: false,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE2 {
t.Errorf("Expected E2 for DSFA recommended, got %s", level)
}
if reason == "" {
t.Error("Expected reason to mention DSFA")
}
}
func TestDetermineEscalationLevel_E3_BlockRule(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityNO,
RiskLevel: RiskLevelHIGH,
RiskScore: 75,
TriggeredRules: []TriggeredRule{
{Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Blockierung"},
},
DSFARecommended: true,
Art22Risk: false,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE3 {
t.Errorf("Expected E3 for BLOCK rule, got %s", level)
}
if reason == "" {
t.Error("Expected reason to mention BLOCK")
}
}
func TestDetermineEscalationLevel_E3_Art22Risk(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelHIGH,
RiskScore: 55,
TriggeredRules: []TriggeredRule{},
DSFARecommended: false,
Art22Risk: true,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE3 {
t.Errorf("Expected E3 for Art. 22 risk, got %s", level)
}
if reason == "" {
t.Error("Expected reason to mention Art. 22")
}
}
func TestDetermineEscalationLevel_E3_HighRiskScore(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
Feasibility: FeasibilityCONDITIONAL,
RiskLevel: RiskLevelHIGH,
RiskScore: 70, // Above E3 threshold
TriggeredRules: []TriggeredRule{},
DSFARecommended: false,
Art22Risk: false,
}
level, _ := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE3 {
t.Errorf("Expected E3 for risk score 70, got %s", level)
}
}
// ============================================================================
// SLA Tests
// ============================================================================
func TestGetDefaultSLA_E0(t *testing.T) {
response, resolution := GetDefaultSLA(EscalationLevelE0)
if response != 0 || resolution != 0 {
t.Errorf("E0 should have no SLA, got response=%d, resolution=%d", response, resolution)
}
}
func TestGetDefaultSLA_E1(t *testing.T) {
response, resolution := GetDefaultSLA(EscalationLevelE1)
if response != 24 {
t.Errorf("E1 should have 24h response SLA, got %d", response)
}
if resolution != 72 {
t.Errorf("E1 should have 72h resolution SLA, got %d", resolution)
}
}
func TestGetDefaultSLA_E2(t *testing.T) {
response, resolution := GetDefaultSLA(EscalationLevelE2)
if response != 8 {
t.Errorf("E2 should have 8h response SLA, got %d", response)
}
if resolution != 48 {
t.Errorf("E2 should have 48h resolution SLA, got %d", resolution)
}
}
func TestGetDefaultSLA_E3(t *testing.T) {
response, resolution := GetDefaultSLA(EscalationLevelE3)
if response != 4 {
t.Errorf("E3 should have 4h response SLA, got %d", response)
}
if resolution != 24 {
t.Errorf("E3 should have 24h resolution SLA, got %d", resolution)
}
}
// ============================================================================
// Role Assignment Tests
// ============================================================================
func TestGetRoleForLevel_E0(t *testing.T) {
role := GetRoleForLevel(EscalationLevelE0)
if role != "" {
t.Errorf("E0 should have no role, got %s", role)
}
}
func TestGetRoleForLevel_E1(t *testing.T) {
role := GetRoleForLevel(EscalationLevelE1)
if role != "team_lead" {
t.Errorf("E1 should require team_lead, got %s", role)
}
}
func TestGetRoleForLevel_E2(t *testing.T) {
role := GetRoleForLevel(EscalationLevelE2)
if role != "dsb" {
t.Errorf("E2 should require dsb, got %s", role)
}
}
func TestGetRoleForLevel_E3(t *testing.T) {
role := GetRoleForLevel(EscalationLevelE3)
if role != "dsb" {
t.Errorf("E3 should require dsb (primary), got %s", role)
}
}
// ============================================================================
// Default Trigger Configuration Tests
// ============================================================================
func TestDefaultEscalationTrigger_Thresholds(t *testing.T) {
trigger := DefaultEscalationTrigger()
if trigger.E1RiskThreshold != 20 {
t.Errorf("E1 threshold should be 20, got %d", trigger.E1RiskThreshold)
}
if trigger.E2RiskThreshold != 40 {
t.Errorf("E2 threshold should be 40, got %d", trigger.E2RiskThreshold)
}
if trigger.E3RiskThreshold != 60 {
t.Errorf("E3 threshold should be 60, got %d", trigger.E3RiskThreshold)
}
}
// ============================================================================
// Edge Case Tests
// ============================================================================
func TestDetermineEscalationLevel_BoundaryRiskScores(t *testing.T) {
trigger := DefaultEscalationTrigger()
tests := []struct {
name string
riskScore int
expectedLevel EscalationLevel
}{
{"Risk 0 → E0", 0, EscalationLevelE0},
{"Risk 19 → E0", 19, EscalationLevelE0},
{"Risk 20 → E0 (boundary)", 20, EscalationLevelE0},
{"Risk 21 → E1", 21, EscalationLevelE1},
{"Risk 39 → E1", 39, EscalationLevelE1},
{"Risk 40 → E1 (boundary)", 40, EscalationLevelE1},
{"Risk 41 → E2", 41, EscalationLevelE2},
{"Risk 59 → E2", 59, EscalationLevelE2},
{"Risk 60 → E2 (boundary)", 60, EscalationLevelE2},
{"Risk 61 → E3", 61, EscalationLevelE3},
{"Risk 100 → E3", 100, EscalationLevelE3},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := &AssessmentResult{
RiskScore: tt.riskScore,
TriggeredRules: []TriggeredRule{},
DSFARecommended: false,
Art22Risk: false,
}
level, _ := trigger.DetermineEscalationLevel(result)
if level != tt.expectedLevel {
t.Errorf("Expected %s for risk score %d, got %s", tt.expectedLevel, tt.riskScore, level)
}
})
}
}
func TestDetermineEscalationLevel_CombinedFactors(t *testing.T) {
trigger := DefaultEscalationTrigger()
// Multiple E3 factors should still result in E3
result := &AssessmentResult{
RiskScore: 80,
TriggeredRules: []TriggeredRule{
{Code: "R-BLOCK-001", Severity: "BLOCK", Description: "Block 1"},
{Code: "R-BLOCK-002", Severity: "BLOCK", Description: "Block 2"},
},
DSFARecommended: true,
Art22Risk: true,
}
level, reason := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE3 {
t.Errorf("Expected E3 for multiple high-risk factors, got %s", level)
}
// Reason should mention multiple factors
if reason == "" {
t.Error("Expected comprehensive reason for multiple factors")
}
}
func TestDetermineEscalationLevel_EmptyRules(t *testing.T) {
trigger := DefaultEscalationTrigger()
result := &AssessmentResult{
RiskScore: 5,
TriggeredRules: []TriggeredRule{},
DSFARecommended: false,
Art22Risk: false,
}
level, _ := trigger.DetermineEscalationLevel(result)
if level != EscalationLevelE0 {
t.Errorf("Expected E0 for empty rules and low risk, got %s", level)
}
}
// ============================================================================
// Constants Validation Tests
// ============================================================================
func TestEscalationLevelConstants(t *testing.T) {
levels := []EscalationLevel{
EscalationLevelE0,
EscalationLevelE1,
EscalationLevelE2,
EscalationLevelE3,
}
expected := []string{"E0", "E1", "E2", "E3"}
for i, level := range levels {
if string(level) != expected[i] {
t.Errorf("Expected %s, got %s", expected[i], level)
}
}
}
func TestEscalationStatusConstants(t *testing.T) {
statuses := map[EscalationStatus]string{
EscalationStatusPending: "pending",
EscalationStatusAssigned: "assigned",
EscalationStatusInReview: "in_review",
EscalationStatusApproved: "approved",
EscalationStatusRejected: "rejected",
EscalationStatusReturned: "returned",
}
for status, expected := range statuses {
if string(status) != expected {
t.Errorf("Expected status %s, got %s", expected, status)
}
}
}
func TestEscalationDecisionConstants(t *testing.T) {
decisions := map[EscalationDecision]string{
EscalationDecisionApprove: "approve",
EscalationDecisionReject: "reject",
EscalationDecisionModify: "modify",
EscalationDecisionEscalate: "escalate",
}
for decision, expected := range decisions {
if string(decision) != expected {
t.Errorf("Expected decision %s, got %s", expected, decision)
}
}
}
// ============================================================================
// Helper Function Tests
// ============================================================================
func TestJoinReasons_Empty(t *testing.T) {
result := joinReasons([]string{}, "Prefix: ")
if result != "Prefix: " {
t.Errorf("Expected 'Prefix: ', got '%s'", result)
}
}
func TestJoinReasons_Single(t *testing.T) {
result := joinReasons([]string{"Reason 1"}, "Test: ")
if result != "Test: Reason 1" {
t.Errorf("Expected 'Test: Reason 1', got '%s'", result)
}
}
func TestJoinReasons_Multiple(t *testing.T) {
result := joinReasons([]string{"Reason 1", "Reason 2", "Reason 3"}, "Test: ")
expected := "Test: Reason 1; Reason 2; Reason 3"
if result != expected {
t.Errorf("Expected '%s', got '%s'", expected, result)
}
}