Files
michaelschiemer/tests/Unit/Framework/Logging/LogRecordTest.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

269 lines
8.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\Logging;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
use App\Framework\Logging\ValueObjects\LogContext;
use DateTimeImmutable;
use DateTimeZone;
beforeEach(function () {
$this->timestamp = new DateTimeImmutable('2024-01-15 10:30:45', new DateTimeZone('Europe/Berlin'));
$this->context = LogContext::withData(['user' => 'test', 'action' => 'login']);
});
it('can create a log record with required fields', function () {
$record = new LogRecord(
message: 'Test message',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
expect($record->getMessage())->toBe('Test message');
expect($record->getLevel())->toBe(LogLevel::INFO);
expect($record->getTimestamp())->toBe($this->timestamp);
expect($record->getChannel())->toBeNull();
});
it('can create a log record with channel', function () {
$record = new LogRecord(
message: 'Database query executed',
context: $this->context,
level: LogLevel::DEBUG,
timestamp: $this->timestamp,
channel: 'database'
);
expect($record->getChannel())->toBe('database');
});
it('can modify message', function () {
$record = new LogRecord(
message: 'Original message',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$modified = $record->withMessage('Modified message');
expect($modified->getMessage())->toBe('Modified message');
expect($record->getMessage())->toBe('Original message'); // Original unverändert
});
it('can set channel after creation', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$withChannel = $record->withChannel('security');
expect($withChannel->getChannel())->toBe('security');
expect($record->getChannel())->toBeNull(); // Original unverändert
});
it('can format timestamp', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
expect($record->getFormattedTimestamp())->toBe('2024-01-15 10:30:45');
expect($record->getFormattedTimestamp('Y-m-d'))->toBe('2024-01-15');
expect($record->getFormattedTimestamp('H:i:s'))->toBe('10:30:45');
});
it('can add extra data', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$withExtra = $record->withExtra('request_id', 'req-123');
$withBoth = $withExtra->withExtra('process_id', 5678);
expect($withBoth->hasExtra('request_id'))->toBeTrue();
expect($withBoth->getExtra('request_id'))->toBe('req-123');
expect($withBoth->getExtra('process_id'))->toBe(5678);
expect($withBoth->hasExtra('non_existent'))->toBeFalse();
expect($record->hasExtra('request_id'))->toBeFalse(); // Original unverändert
});
it('can add multiple extras at once', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$extras = [
'server' => 'web-01',
'memory_usage' => 1024000,
'execution_time' => 0.123,
];
$withExtras = $record->withExtras($extras);
expect($withExtras->getExtras())->toBe($extras);
expect($withExtras->getExtra('server'))->toBe('web-01');
expect($withExtras->getExtra('memory_usage'))->toBe(1024000);
expect($withExtras->getExtra('execution_time'))->toBe(0.123);
expect($record->getExtras())->toBe([]); // Original unverändert
});
it('returns default value for non-existent extra', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
expect($record->getExtra('missing'))->toBeNull();
expect($record->getExtra('missing', 'default'))->toBe('default');
});
it('maintains fluent interface for setters', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$result = $record
->withMessage('New message')
->withChannel('custom')
->withExtra('key1', 'value1')
->withExtras(['key2' => 'value2']);
expect($result)->not->toBe($record); // Neues Objekt
expect($result->getMessage())->toBe('New message');
expect($result->getChannel())->toBe('custom');
expect($result->getExtra('key1'))->toBe('value1');
expect($result->getExtra('key2'))->toBe('value2');
expect($record->getMessage())->toBe('Test'); // Original unverändert
});
it('converts to array correctly', function () {
$record = new LogRecord(
message: 'Test message',
context: $this->context,
level: LogLevel::WARNING,
timestamp: $this->timestamp,
channel: 'test-channel'
);
$withExtra = $record->withExtra('request_id', 'req-456');
$array = $withExtra->toArray();
expect($array)->toHaveKeys([
'message',
'context',
'level',
'level_name',
'timestamp',
'datetime',
'channel',
'extra',
]);
expect($array['message'])->toBe('Test message');
expect($array['context'])->toMatchArray(['structured' => ['user' => 'test', 'action' => 'login']]);
expect($array['level'])->toBe(LogLevel::WARNING->value);
expect($array['level_name'])->toBe('WARNING');
expect($array['timestamp'])->toBe('2024-01-15 10:30:45');
expect($array['datetime'])->toBe($this->timestamp);
expect($array['channel'])->toBe('test-channel');
expect($array['extra'])->toBe(['request_id' => 'req-456']);
});
it('handles different log levels correctly', function () {
$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: "Test {$level->getName()}",
context: $this->context,
level: $level,
timestamp: $this->timestamp
);
expect($record->getLevel())->toBe($level);
expect($record->toArray()['level'])->toBe($level->value);
expect($record->toArray()['level_name'])->toBe($level->getName());
}
});
it('preserves context as LogContext object', function () {
$context = LogContext::withData(['test' => 'data'])
->addTags('important', 'audit');
$record = new LogRecord(
message: 'Test',
context: $context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$contextArray = $record->getContext();
expect($contextArray)->toMatchArray([
'test' => 'data',
'_tags' => ['important', 'audit'],
]);
});
it('can handle empty extras', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
expect($record->getExtras())->toBe([]);
expect($record->hasExtra('any'))->toBeFalse();
});
it('overrides existing extras when adding with same key', function () {
$record = new LogRecord(
message: 'Test',
context: $this->context,
level: LogLevel::INFO,
timestamp: $this->timestamp
);
$withOriginal = $record->withExtra('key', 'original');
expect($withOriginal->getExtra('key'))->toBe('original');
$withModified = $withOriginal->withExtra('key', 'modified');
expect($withModified->getExtra('key'))->toBe('modified');
expect($withOriginal->getExtra('key'))->toBe('original'); // Vorherige Version unverändert
$withFinal = $withModified->withExtras(['key' => 'final']);
expect($withFinal->getExtra('key'))->toBe('final');
expect($withModified->getExtra('key'))->toBe('modified'); // Vorherige Version unverändert
});