- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
121 lines
3.7 KiB
PHP
121 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\Logging;
|
|
|
|
use App\Framework\Logging\Handlers\SamplingLogHandler;
|
|
use App\Framework\Logging\LogHandler;
|
|
use App\Framework\Logging\LogLevel;
|
|
use App\Framework\Logging\LogRecord;
|
|
use App\Framework\Logging\Sampling\SamplingConfig;
|
|
use App\Framework\Logging\ValueObjects\LogContext;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class SamplingLogHandlerTest extends TestCase
|
|
{
|
|
public function test_samples_logs_based_on_config(): void
|
|
{
|
|
$inner = $this->createMock(LogHandler::class);
|
|
|
|
// Config: 100% ERROR, 0% INFO
|
|
$config = SamplingConfig::custom([
|
|
'ERROR' => 1.0,
|
|
'INFO' => 0.0,
|
|
]);
|
|
|
|
$handler = new SamplingLogHandler($inner, $config);
|
|
|
|
// ERROR sollte durchkommen
|
|
$inner->expects($this->once())->method('handle');
|
|
$handler->handle($this->createLogRecord('error', LogLevel::ERROR));
|
|
|
|
// INFO sollte gedroppt werden
|
|
$handler->handle($this->createLogRecord('info', LogLevel::INFO));
|
|
|
|
$this->assertEquals(1, $handler->getAcceptedCount());
|
|
$this->assertEquals(1, $handler->getDroppedCount());
|
|
}
|
|
|
|
public function test_never_samples_critical_levels(): void
|
|
{
|
|
$inner = $this->createMock(LogHandler::class);
|
|
|
|
$config = SamplingConfig::production();
|
|
$handler = new SamplingLogHandler($inner, $config);
|
|
|
|
$criticalLevels = [
|
|
LogLevel::ERROR,
|
|
LogLevel::CRITICAL,
|
|
LogLevel::ALERT,
|
|
LogLevel::EMERGENCY,
|
|
];
|
|
|
|
$inner->expects($this->exactly(count($criticalLevels)))
|
|
->method('handle');
|
|
|
|
foreach ($criticalLevels as $level) {
|
|
$handler->handle($this->createLogRecord('test', $level));
|
|
}
|
|
|
|
$this->assertEquals(count($criticalLevels), $handler->getAcceptedCount());
|
|
$this->assertEquals(0, $handler->getDroppedCount());
|
|
}
|
|
|
|
public function test_tracks_dropped_by_level(): void
|
|
{
|
|
$inner = $this->createMock(LogHandler::class);
|
|
|
|
$config = SamplingConfig::custom(['INFO' => 0.0]);
|
|
$handler = new SamplingLogHandler($inner, $config);
|
|
|
|
for ($i = 0; $i < 10; $i++) {
|
|
$handler->handle($this->createLogRecord('info', LogLevel::INFO));
|
|
}
|
|
|
|
$dropped = $handler->getDroppedByLevel();
|
|
|
|
$this->assertArrayHasKey('INFO', $dropped);
|
|
$this->assertEquals(10, $dropped['INFO']);
|
|
}
|
|
|
|
public function test_calculates_drop_rate(): void
|
|
{
|
|
$inner = $this->createMock(LogHandler::class);
|
|
|
|
$config = SamplingConfig::custom(['INFO' => 0.5]);
|
|
$handler = new SamplingLogHandler($inner, $config);
|
|
|
|
// Simulate: sollte ca. 50% droppen
|
|
// Für deterministische Tests mocken wir mt_rand nicht,
|
|
// aber prüfen nur dass Drop-Rate berechnet wird
|
|
|
|
$this->assertEquals(0.0, $handler->getDropRate()); // Noch keine Logs
|
|
}
|
|
|
|
public function test_health_check(): void
|
|
{
|
|
$inner = $this->createMock(LogHandler::class);
|
|
$handler = new SamplingLogHandler($inner, SamplingConfig::production());
|
|
|
|
$health = $handler->check();
|
|
|
|
$this->assertEquals(\App\Framework\Health\HealthStatus::HEALTHY, $health->status);
|
|
$this->assertArrayHasKey('accepted', $health->details);
|
|
$this->assertArrayHasKey('dropped', $health->details);
|
|
}
|
|
|
|
private function createLogRecord(
|
|
string $message = 'test',
|
|
LogLevel $level = LogLevel::INFO
|
|
): LogRecord {
|
|
return new LogRecord(
|
|
level: $level,
|
|
message: $message,
|
|
channel: 'test',
|
|
context: LogContext::empty(),
|
|
timestamp: new \DateTimeImmutable()
|
|
);
|
|
}
|
|
}
|