Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
218
tests/Framework/DDoS/DDoSProtectionEngineTest.php
Normal file
218
tests/Framework/DDoS/DDoSProtectionEngineTest.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\Core\ValueObjects\Duration;
|
||||
use App\Framework\DateTime\SystemClock;
|
||||
use App\Framework\DDoS\DDoSConfig;
|
||||
use App\Framework\DDoS\ValueObjects\ThreatLevel;
|
||||
|
||||
require_once __DIR__ . '/Helpers/TestHelpers.php';
|
||||
|
||||
beforeEach(function () {
|
||||
$this->clock = new SystemClock();
|
||||
|
||||
// Create DDoS config for testing
|
||||
$this->config = new DDoSConfig(
|
||||
enabled: true,
|
||||
volumetricThreshold: 100.0, // Lower threshold for faster testing
|
||||
distributedThreshold: 0.8,
|
||||
analysisWindow: Duration::fromMinutes(5),
|
||||
trustedIps: ['127.0.0.1', '::1'],
|
||||
exemptPaths: ['/health', '/ping']
|
||||
);
|
||||
|
||||
// Mock the engine (we'll need to set up proper DI for real tests)
|
||||
$this->engine = $this->createMockEngine();
|
||||
});
|
||||
|
||||
describe('DDoS Protection Engine', function () {
|
||||
|
||||
it('allows normal requests through', function () {
|
||||
$request = createTestRequest('192.168.1.100', 'GET', '/api/users');
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
expect($assessment->threatLevel)->toBe(ThreatLevel::LOW);
|
||||
expect($assessment->shouldBlock)->toBeFalse();
|
||||
expect($assessment->threatScore)->toBeLessThan(0.3);
|
||||
});
|
||||
|
||||
it('detects high volume attacks from single IP', function () {
|
||||
$attackerIp = '10.0.0.1';
|
||||
$assessment = null;
|
||||
|
||||
// Simulate rapid requests from same IP
|
||||
for ($i = 1; $i <= 20; $i++) {
|
||||
$request = createTestRequest($attackerIp, 'GET', "/page{$i}");
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
if ($assessment->shouldBlock) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expect($assessment->threatLevel)->toBeIn([ThreatLevel::HIGH, ThreatLevel::CRITICAL]);
|
||||
expect($assessment->shouldBlock)->toBeTrue();
|
||||
expect($assessment->threatScore)->toBeGreaterThan(0.7);
|
||||
});
|
||||
|
||||
it('detects distributed attacks', function () {
|
||||
$attackIps = ['1.2.3.4', '5.6.7.8', '9.10.11.12', '13.14.15.16'];
|
||||
$assessments = [];
|
||||
|
||||
foreach ($attackIps as $ip) {
|
||||
for ($i = 1; $i <= 15; $i++) {
|
||||
$request = createTestRequest($ip, 'POST', '/api/login');
|
||||
$assessments[] = $this->engine->assessRequest($request);
|
||||
}
|
||||
}
|
||||
|
||||
// Should detect distributed pattern
|
||||
$lastAssessment = end($assessments);
|
||||
expect($lastAssessment->threatLevel)->toBeIn([ThreatLevel::MEDIUM, ThreatLevel::HIGH]);
|
||||
expect($lastAssessment->threatScore)->toBeGreaterThan(0.4);
|
||||
});
|
||||
|
||||
it('blocks suspicious bot traffic', function () {
|
||||
$request = createTestRequest('192.168.1.200', 'GET', '/sensitive-data', [
|
||||
'User-Agent' => 'BadBot/1.0 (automated scraper)',
|
||||
]);
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
expect($assessment->threatLevel)->toBeIn([ThreatLevel::MEDIUM, ThreatLevel::HIGH]);
|
||||
expect($assessment->threatScore)->toBeGreaterThan(0.5);
|
||||
});
|
||||
|
||||
it('allows trusted IPs through', function () {
|
||||
$request = createTestRequest('127.0.0.1', 'GET', '/admin/sensitive');
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
expect($assessment->threatLevel)->toBe(ThreatLevel::LOW);
|
||||
expect($assessment->shouldBlock)->toBeFalse();
|
||||
});
|
||||
|
||||
it('bypasses exempt paths', function () {
|
||||
$request = createTestRequest('10.0.0.1', 'GET', '/health');
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
expect($assessment->threatLevel)->toBe(ThreatLevel::LOW);
|
||||
expect($assessment->shouldBlock)->toBeFalse();
|
||||
});
|
||||
|
||||
it('escalates threat level with repeated attacks', function () {
|
||||
$attackerIp = '192.168.1.50';
|
||||
$assessments = [];
|
||||
|
||||
// First wave - should be low threat
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$request = createTestRequest($attackerIp, 'GET', "/api/data{$i}");
|
||||
$assessments[] = $this->engine->assessRequest($request);
|
||||
}
|
||||
|
||||
expect($assessments[0]->threatLevel)->toBe(ThreatLevel::LOW);
|
||||
|
||||
// Second wave - should escalate
|
||||
for ($i = 6; $i <= 25; $i++) {
|
||||
$request = createTestRequest($attackerIp, 'GET', "/api/data{$i}");
|
||||
$assessments[] = $this->engine->assessRequest($request);
|
||||
}
|
||||
|
||||
$lastAssessment = end($assessments);
|
||||
expect($lastAssessment->threatLevel)->toBeIn([ThreatLevel::MEDIUM, ThreatLevel::HIGH, ThreatLevel::CRITICAL]);
|
||||
expect($lastAssessment->threatScore)->toBeGreaterThan($assessments[0]->threatScore);
|
||||
});
|
||||
|
||||
it('handles malformed requests gracefully', function () {
|
||||
$request = createTestRequest('invalid-ip', 'INVALID_METHOD', '');
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
// Should not crash and should treat as suspicious
|
||||
expect($assessment)->not()->toBeNull();
|
||||
expect($assessment->threatLevel)->toBeIn([ThreatLevel::MEDIUM, ThreatLevel::HIGH]);
|
||||
});
|
||||
|
||||
it('provides detailed assessment information', function () {
|
||||
$request = createTestRequest('192.168.1.100', 'GET', '/api/test');
|
||||
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
expect($assessment)->toHaveProperties([
|
||||
'threatLevel',
|
||||
'threatScore',
|
||||
'shouldBlock',
|
||||
'detectedPatterns',
|
||||
'responseRecommendation',
|
||||
]);
|
||||
|
||||
expect($assessment->threatScore)->toBeBetween(0.0, 1.0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('DDoS Configuration', function () {
|
||||
|
||||
it('respects custom thresholds', function () {
|
||||
$strictConfig = new DDoSConfig(
|
||||
volumetricThreshold: 10.0, // Very low threshold
|
||||
highThreatThreshold: 0.3 // Lower threshold for high threat
|
||||
);
|
||||
|
||||
$engine = createEngineWithConfig($strictConfig);
|
||||
$request = createTestRequest('192.168.1.100', 'GET', '/api/test');
|
||||
|
||||
// With strict config, even normal requests might be flagged
|
||||
$assessment = $engine->assessRequest($request);
|
||||
expect($assessment)->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('can be disabled', function () {
|
||||
$disabledConfig = new DDoSConfig(enabled: false);
|
||||
$engine = createEngineWithConfig($disabledConfig);
|
||||
|
||||
$request = createTestRequest('10.0.0.1', 'GET', '/api/test');
|
||||
$assessment = $engine->assessRequest($request);
|
||||
|
||||
expect($assessment->threatLevel)->toBe(ThreatLevel::LOW);
|
||||
expect($assessment->shouldBlock)->toBeFalse();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Performance', function () {
|
||||
|
||||
it('completes assessment within reasonable time', function () {
|
||||
$start = microtime(true);
|
||||
|
||||
$request = createTestRequest('192.168.1.100', 'GET', '/api/test');
|
||||
$assessment = $this->engine->assessRequest($request);
|
||||
|
||||
$duration = microtime(true) - $start;
|
||||
|
||||
expect($duration)->toBeLessThan(0.1); // Should complete within 100ms
|
||||
expect($assessment)->not()->toBeNull();
|
||||
});
|
||||
|
||||
it('handles high request volume efficiently', function () {
|
||||
$start = microtime(true);
|
||||
|
||||
// Process 100 requests
|
||||
for ($i = 1; $i <= 100; $i++) {
|
||||
$ip = '192.168.1.' . ($i % 254 + 1);
|
||||
$request = createTestRequest($ip, 'GET', "/api/test{$i}");
|
||||
$this->engine->assessRequest($request);
|
||||
}
|
||||
|
||||
$duration = microtime(true) - $start;
|
||||
$avgPerRequest = $duration / 100;
|
||||
|
||||
expect($avgPerRequest)->toBeLessThan(0.01); // Average <10ms per request
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Helper functions are now in Helpers/TestHelpers.php
|
||||
Reference in New Issue
Block a user