7.5, 75 => 15.0, 90 => 18.0, 95 => 20.0, 99 => 22.0, ], sampleCount: 20, createdAt: $now, lastUpdated: $now, windowSize: Duration::fromMinutes(30), confidence: 0.8 ); } // Hilfsfunktion zum Erstellen von Testfeatures function createTestFeatures(): array { return [ new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_depth', value: 3.0, unit: 'count' ), new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_segments', value: 4.0, unit: 'count' ), new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 25.0, unit: 'characters' ), new BehaviorFeature( type: BehaviorType::PARAMETER_PATTERNS, name: 'param_count', value: 2.0, unit: 'count' ), new BehaviorFeature( type: BehaviorType::PARAMETER_PATTERNS, name: 'param_length_avg', value: 8.0, unit: 'characters' ), ]; } test('erkennt Cluster-Abweichungen', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: true, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); // Normale Features $normalFeatures = createTestFeatures(); // Anomales Feature mit deutlich abweichenden Werten $anomalousFeature = new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 150.0, // Deutlich höher als normal unit: 'characters' ); $features = array_merge($normalFeatures, [$anomalousFeature]); // Act $anomalies = $detector->detectAnomalies($features, null); // Assert expect($anomalies)->not->toBeEmpty(); expect($anomalies[0]->type)->toBe(AnomalyType::CLUSTERING_DEVIATION); }); test('gruppiert Features nach Typ', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: true, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); // Features mit verschiedenen Typen $features = [ new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_feature', value: 10.0, unit: 'count' ), new BehaviorFeature( type: BehaviorType::PARAMETER_PATTERNS, name: 'param_feature', value: 5.0, unit: 'count' ), new BehaviorFeature( type: BehaviorType::REQUEST_FREQUENCY, name: 'freq_feature', value: 2.0, unit: 'requests/second' ), ]; // Wir können die private Methode nicht direkt testen, aber wir können testen, // dass der Detektor die Features analysieren kann // Act & Assert expect($detector->canAnalyze($features))->toBeTrue(); }); test('unterstützt verschiedene Verhaltenstypen', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: true, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); // Act $supportedTypes = $detector->getSupportedBehaviorTypes(); // Assert expect($supportedTypes)->toBeArray(); expect($supportedTypes)->toContain(BehaviorType::REQUEST_FREQUENCY); expect($supportedTypes)->toContain(BehaviorType::PATH_PATTERNS); expect($supportedTypes)->toContain(BehaviorType::PARAMETER_PATTERNS); expect($supportedTypes)->toContain(BehaviorType::USER_AGENT_PATTERNS); }); test('erkennt Dichte-Anomalien wenn aktiviert', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: false, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); // Normale Features mit ähnlichen Werten $normalFeatures = [ new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 20.0, unit: 'characters' ), new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 22.0, unit: 'characters' ), new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 19.0, unit: 'characters' ), new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 21.0, unit: 'characters' ), ]; // Isoliertes Feature $isolatedFeature = new BehaviorFeature( type: BehaviorType::PATH_PATTERNS, name: 'path_length', value: 100.0, // Deutlich abseits der anderen unit: 'characters' ); $features = array_merge($normalFeatures, [$isolatedFeature]); // Act $anomalies = $detector->detectAnomalies($features, null); // Assert expect($anomalies)->not->toBeEmpty(); // Je nach Implementierung könnte es verschiedene Anomalietypen sein expect($anomalies[0]->type)->toBe(AnomalyType::CLUSTERING_DEVIATION); }); test('aktualisiert Modell mit neuen Daten', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: true, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); $features = createTestFeatures(); // Act - Keine Assertion möglich, da interne Daten private sind // Wir testen nur, dass keine Exception geworfen wird $detector->updateModel($features); // Assert expect(true)->toBeTrue(); // Dummy assertion }); test('gibt Konfiguration korrekt zurück', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: true, confidenceThreshold: 0.75, maxClusters: 5, minClusterSize: 3, outlierThreshold: 0.9, maxIterations: 20, convergenceThreshold: 0.005, enableDensityAnalysis: true, enableGroupAnomalyDetection: false, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); // Act $config = $detector->getConfiguration(); // Assert expect($config)->toBeArray(); expect($config['enabled'])->toBeTrue(); expect($config['confidence_threshold'])->toBe(0.75); expect($config['max_clusters'])->toBe(5); expect($config['min_cluster_size'])->toBe(3); expect($config['outlier_threshold'])->toBe(0.9); expect($config['max_iterations'])->toBe(20); expect($config['enable_density_analysis'])->toBeTrue(); expect($config['enable_group_anomaly_detection'])->toBeFalse(); }); test('gibt leere Ergebnisse zurück wenn deaktiviert', function () { // Arrange $detector = new ClusteringAnomalyDetector( enabled: false, confidenceThreshold: 0.5, maxClusters: 3, minClusterSize: 2, outlierThreshold: 0.8, maxIterations: 10, convergenceThreshold: 0.01, enableDensityAnalysis: true, enableGroupAnomalyDetection: true, clusterCenters: [], clusterAssignments: [], featureVectors: [] ); $features = createTestFeatures(); // Act $anomalies = $detector->detectAnomalies($features, null); // Assert expect($anomalies)->toBeEmpty(); });