detector = new AttackPatternDetector($config, $logger); }); describe('AttackPatternDetector', function () { it('detects volumetric attacks', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.9, // Higher than development config threshold (0.8) 'requests_per_minute' => 500, 'normal_rate' => 50, ], ]; $request = createTestRequest('192.168.1.100', 'GET', '/api/data'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::VOLUMETRIC); }); it('detects distributed attacks', function () { $analysisResults = [ 'geo_anomalies' => [ 'threat_score' => 0.7, 'unique_countries' => 15, 'geographic_diversity' => 0.9, ], ]; $request = createTestRequest('10.0.0.1', 'POST', '/api/login'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::DISTRIBUTED); }); it('detects bot attacks from user agent patterns', function () { $analysisResults = [ 'request_signature' => [ 'threat_score' => 0.6, 'user_agent_suspicion' => 0.8, 'automation_indicators' => ['unusual_timing', 'fixed_intervals'], ], ]; $request = createTestRequest('192.168.1.200', 'GET', '/scrape-data', [ 'User-Agent' => 'ScrapingBot/2.0 (automated)', ]); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::BOTNET); }); it('detects application layer attacks', function () { $analysisResults = [ 'waf_analysis' => [ 'threat_score' => 0.9, 'malicious_patterns' => ['sql_injection', 'xss_attempt'], 'payload_analysis' => 'high_risk', ], ]; $request = createTestRequest('192.168.1.300', 'POST', '/api/search', [], [ 'query' => "'; DROP TABLE users; --", ]); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::APPLICATION_LAYER); }); it('detects slow rate attacks', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.4, 'requests_per_minute' => 30, 'sustained_duration' => 3600, // 1 hour 'pattern_consistency' => 0.95, ], ]; $request = createTestRequest('192.168.1.400', 'GET', '/expensive-operation'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::SLOWLORIS); }); it('detects mixed attack patterns', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.8, 'requests_per_minute' => 300, ], 'geo_anomalies' => [ 'threat_score' => 0.6, 'unique_countries' => 10, ], 'waf_analysis' => [ 'threat_score' => 0.7, 'malicious_patterns' => ['xss_attempt'], ], ]; $request = createTestRequest('192.168.1.500', 'POST', '/api/submit'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toHaveCount(3); expect($patterns)->toContain(AttackPattern::VOLUMETRIC); expect($patterns)->toContain(AttackPattern::DISTRIBUTED); expect($patterns)->toContain(AttackPattern::APPLICATION_LAYER); }); it('returns empty array for normal traffic', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.1, 'requests_per_minute' => 15, ], 'geo_anomalies' => [ 'threat_score' => 0.05, 'unique_countries' => 1, ], ]; $request = createTestRequest('192.168.1.600', 'GET', '/api/health'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toBeEmpty(); }); it('identifies coordinated attack patterns', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.6, 'coordination_score' => 0.8, 'timing_patterns' => 'synchronized', ], ]; $request = createTestRequest('192.168.1.700', 'GET', '/target-endpoint'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::DISTRIBUTED); }); it('detects amplification attacks', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.7, 'amplification_ratio' => 50, 'response_size_anomaly' => 0.9, ], ]; $request = createTestRequest('192.168.1.800', 'GET', '/api/export-large-dataset'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toContain(AttackPattern::AMPLIFICATION); }); it('handles malformed analysis results', function () { $analysisResults = [ 'invalid_layer' => null, 'broken_data' => 'not_an_array', ]; $request = createTestRequest('192.168.1.900', 'GET', '/api/test'); $patterns = $this->detector->identifyAttackPatterns($analysisResults, $request); expect($patterns)->toBeArray(); }); it('calculates pattern confidence scores', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.8, 'confidence' => 0.9, ], ]; $request = createTestRequest('192.168.1.100', 'GET', '/api/data'); $confidence = $this->detector->calculatePatternConfidence($analysisResults); expect($confidence)->toBeBetween(0.0, 1.0); expect($confidence)->toBeGreaterThan(0.7); }); it('provides pattern severity assessment', function () { $patterns = [ AttackPattern::VOLUMETRIC, AttackPattern::APPLICATION_LAYER, ]; $severity = $this->detector->assessPatternSeverity($patterns); expect($severity)->toBeIn(['low', 'medium', 'high', 'critical']); }); }); describe('Pattern Analysis Details', function () { it('provides detailed pattern analysis', function () { $analysisResults = [ 'traffic_patterns' => [ 'threat_score' => 0.8, 'requests_per_minute' => 500, 'peak_detection' => true, ], ]; $request = createTestRequest('192.168.1.100', 'GET', '/api/data'); $details = $this->detector->getPatternAnalysisDetails($analysisResults, $request); expect($details)->toHaveKeys([ 'detected_patterns', 'confidence_scores', 'risk_factors', 'recommendations', ]); }); it('tracks pattern evolution over time', function () { $historicalData = [ ['timestamp' => time() - 3600, 'patterns' => [AttackPattern::VOLUMETRIC]], ['timestamp' => time() - 1800, 'patterns' => [AttackPattern::VOLUMETRIC, AttackPattern::BOTNET]], ['timestamp' => time(), 'patterns' => [AttackPattern::DISTRIBUTED]], ]; $evolution = $this->detector->analyzePatternEvolution($historicalData); expect($evolution)->toHaveKeys(['trend', 'escalation_detected', 'pattern_changes']); expect($evolution['escalation_detected'])->toBeTrue(); }); it('generates pattern fingerprints', function () { $analysisResults = [ 'traffic_patterns' => ['threat_score' => 0.8], 'geo_anomalies' => ['threat_score' => 0.6], ]; $request = createTestRequest('192.168.1.100', 'GET', '/api/data'); $fingerprint = $this->detector->generatePatternFingerprint($analysisResults, $request); expect($fingerprint)->toBeString(); expect(strlen($fingerprint))->toBeGreaterThan(10); }); }); // Helper functions are now in ../Helpers/TestHelpers.php