- 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.
114 lines
3.3 KiB
PHP
114 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\Logging;
|
|
|
|
use App\Framework\CircuitBreaker\CircuitBreaker;
|
|
use App\Framework\CircuitBreaker\CircuitBreakerConfig;
|
|
use App\Framework\Logging\Handlers\ResilientLogHandler;
|
|
use App\Framework\Logging\LogHandler;
|
|
use App\Framework\Logging\LogLevel;
|
|
use App\Framework\Logging\LogRecord;
|
|
use App\Framework\Logging\ValueObjects\LogContext;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class ResilientLogHandlerTest extends TestCase
|
|
{
|
|
public function test_uses_primary_handler_when_healthy(): void
|
|
{
|
|
$primary = $this->createMock(LogHandler::class);
|
|
$fallback = $this->createMock(LogHandler::class);
|
|
|
|
$record = $this->createLogRecord();
|
|
|
|
$primary->expects($this->once())
|
|
->method('handle')
|
|
->with($record);
|
|
|
|
$fallback->expects($this->never())
|
|
->method('handle');
|
|
|
|
$handler = new ResilientLogHandler($primary, $fallback);
|
|
$handler->handle($record);
|
|
}
|
|
|
|
public function test_uses_fallback_when_primary_fails(): void
|
|
{
|
|
$primary = $this->createMock(LogHandler::class);
|
|
$fallback = $this->createMock(LogHandler::class);
|
|
|
|
$record = $this->createLogRecord();
|
|
|
|
$primary->method('handle')
|
|
->willThrowException(new \RuntimeException('Primary failed'));
|
|
|
|
$fallback->expects($this->atLeastOnce())
|
|
->method('handle');
|
|
|
|
$handler = new ResilientLogHandler($primary, $fallback);
|
|
$handler->handle($record);
|
|
|
|
// Should not throw exception
|
|
$this->assertTrue(true);
|
|
}
|
|
|
|
public function test_never_throws_exception(): void
|
|
{
|
|
$primary = $this->createMock(LogHandler::class);
|
|
$fallback = $this->createMock(LogHandler::class);
|
|
|
|
$primary->method('handle')
|
|
->willThrowException(new \RuntimeException('Primary failed'));
|
|
|
|
$fallback->method('handle')
|
|
->willThrowException(new \RuntimeException('Fallback failed'));
|
|
|
|
$handler = new ResilientLogHandler($primary, $fallback);
|
|
|
|
// Should never throw - uses error_log as last resort
|
|
$handler->handle($this->createLogRecord());
|
|
|
|
$this->assertTrue(true);
|
|
}
|
|
|
|
public function test_circuit_breaker_opens_after_failures(): void
|
|
{
|
|
$primary = $this->createMock(LogHandler::class);
|
|
$fallback = $this->createMock(LogHandler::class);
|
|
|
|
$circuitBreaker = new CircuitBreaker(
|
|
new CircuitBreakerConfig(
|
|
name: 'test',
|
|
failureThreshold: 3,
|
|
successThreshold: 1,
|
|
timeout: 60.0
|
|
)
|
|
);
|
|
|
|
$primary->method('handle')
|
|
->willThrowException(new \RuntimeException('Failed'));
|
|
|
|
$handler = new ResilientLogHandler($primary, $fallback, $circuitBreaker);
|
|
|
|
// Trigger failures to open circuit
|
|
for ($i = 0; $i < 5; $i++) {
|
|
$handler->handle($this->createLogRecord());
|
|
}
|
|
|
|
$this->assertTrue($circuitBreaker->isOpen());
|
|
$this->assertFalse($handler->isHealthy());
|
|
}
|
|
|
|
private function createLogRecord(string $message = 'test'): LogRecord
|
|
{
|
|
return new LogRecord(
|
|
level: LogLevel::INFO,
|
|
message: $message,
|
|
channel: 'test',
|
|
context: LogContext::empty(),
|
|
timestamp: new \DateTimeImmutable()
|
|
);
|
|
}
|
|
}
|