Files
michaelschiemer/tests/Unit/Framework/Logging/Handlers/SyslogHandlerTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- 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.
2025-10-25 19:18:37 +02:00

340 lines
11 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Logging\Handlers\SyslogHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
use App\Framework\Logging\ValueObjects\LogContext;
describe('SyslogHandler', function () {
beforeEach(function () {
$this->timestamp = new DateTimeImmutable('2024-01-15 10:30:45', new DateTimeZone('Europe/Berlin'));
});
describe('constructor', function () {
it('accepts custom ident and facility', function () {
$handler = new SyslogHandler(
ident: 'test-app',
facility: LOG_LOCAL0,
minLevel: LogLevel::WARNING
);
expect($handler)->toBeInstanceOf(SyslogHandler::class);
});
it('uses default values when not specified', function () {
$handler = new SyslogHandler();
expect($handler)->toBeInstanceOf(SyslogHandler::class);
});
});
describe('isHandling()', function () {
it('returns true when record level is above minLevel', function () {
$handler = new SyslogHandler(minLevel: LogLevel::WARNING);
$record = new LogRecord(
message: 'test message',
context: LogContext::empty(),
level: LogLevel::ERROR,
timestamp: $this->timestamp
);
expect($handler->isHandling($record))->toBeTrue();
});
it('returns true when record level equals minLevel', function () {
$handler = new SyslogHandler(minLevel: LogLevel::WARNING);
$record = new LogRecord(
message: 'test message',
context: LogContext::empty(),
level: LogLevel::WARNING,
timestamp: $this->timestamp
);
expect($handler->isHandling($record))->toBeTrue();
});
it('returns false when record level is below minLevel', function () {
$handler = new SyslogHandler(minLevel: LogLevel::ERROR);
$record = new LogRecord(
message: 'test message',
context: LogContext::empty(),
level: LogLevel::WARNING,
timestamp: $this->timestamp
);
expect($handler->isHandling($record))->toBeFalse();
});
});
describe('handle()', function () {
it('handles log records without errors', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Test log message',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
it('handles records with request_id extra', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = (new LogRecord(
message: 'Test message',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
))->addExtra('request_id', 'req-123');
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
it('handles records with channel', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Test message',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp,
channel: 'security'
);
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
it('handles records with context data', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Test message',
context: LogContext::withData(['user_id' => 123, 'action' => 'login']),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
it('handles all log levels', function () {
$handler = new SyslogHandler(ident: 'pest-test', minLevel: LogLevel::DEBUG);
$levels = [
LogLevel::DEBUG,
LogLevel::INFO,
LogLevel::NOTICE,
LogLevel::WARNING,
LogLevel::ERROR,
LogLevel::CRITICAL,
LogLevel::ALERT,
LogLevel::EMERGENCY,
];
foreach ($levels as $level) {
$record = new LogRecord(
message: "{$level->getName()} message",
context: LogContext::empty(),
level: $level,
timestamp: $this->timestamp
);
// Should not throw exception
$handler->handle($record);
}
expect(true)->toBeTrue();
});
it('handles records with empty context', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Message without context',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
it('handles complex context data with special characters', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Test message',
context: LogContext::withData([
'email' => 'test@example.com',
'path' => '/api/users/123',
'special' => "line1\nline2\ttabbed",
]),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
// Should not throw exception
$handler->handle($record);
expect(true)->toBeTrue();
});
});
describe('syslog priority mapping', function () {
it('correctly maps emergency level', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Emergency',
context: LogContext::empty(),
level: LogLevel::EMERGENCY,
timestamp: $this->timestamp
);
// Should use LOG_EMERG priority internally
$handler->handle($record);
expect(true)->toBeTrue();
});
it('correctly maps alert level', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Alert',
context: LogContext::empty(),
level: LogLevel::ALERT,
timestamp: $this->timestamp
);
// Should use LOG_ALERT priority internally
$handler->handle($record);
expect(true)->toBeTrue();
});
it('correctly maps critical level', function () {
$handler = new SyslogHandler(ident: 'pest-test');
$record = new LogRecord(
message: 'Critical',
context: LogContext::empty(),
level: LogLevel::CRITICAL,
timestamp: $this->timestamp
);
// Should use LOG_CRIT priority internally
$handler->handle($record);
expect(true)->toBeTrue();
});
});
describe('syslog connection management', function () {
it('opens syslog connection on first handle', function () {
$handler = new SyslogHandler(ident: 'pest-test-connection');
$record = new LogRecord(
message: 'First message',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
// Should open connection internally
$handler->handle($record);
expect(true)->toBeTrue();
});
it('reuses open syslog connection for multiple records', function () {
$handler = new SyslogHandler(ident: 'pest-test-reuse');
$record1 = new LogRecord(
message: 'First message',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$record2 = new LogRecord(
message: 'Second message',
context: LogContext::empty(),
level: LogLevel::WARNING,
timestamp: $this->timestamp
);
// Should reuse connection
$handler->handle($record1);
$handler->handle($record2);
expect(true)->toBeTrue();
});
});
describe('different facilities', function () {
it('accepts LOG_USER facility', function () {
$handler = new SyslogHandler(
ident: 'pest-test',
facility: LOG_USER
);
$record = new LogRecord(
message: 'Test',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$handler->handle($record);
expect(true)->toBeTrue();
});
it('accepts LOG_LOCAL0 facility', function () {
$handler = new SyslogHandler(
ident: 'pest-test',
facility: LOG_LOCAL0
);
$record = new LogRecord(
message: 'Test',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$handler->handle($record);
expect(true)->toBeTrue();
});
it('accepts LOG_DAEMON facility', function () {
$handler = new SyslogHandler(
ident: 'pest-test',
facility: LOG_DAEMON
);
$record = new LogRecord(
message: 'Test',
context: LogContext::empty(),
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$handler->handle($record);
expect(true)->toBeTrue();
});
});
});