- Move 12 markdown files from root to docs/ subdirectories - Organize documentation by category: • docs/troubleshooting/ (1 file) - Technical troubleshooting guides • docs/deployment/ (4 files) - Deployment and security documentation • docs/guides/ (3 files) - Feature-specific guides • docs/planning/ (4 files) - Planning and improvement proposals Root directory cleanup: - Reduced from 16 to 4 markdown files in root - Only essential project files remain: • CLAUDE.md (AI instructions) • README.md (Main project readme) • CLEANUP_PLAN.md (Current cleanup plan) • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements) This improves: ✅ Documentation discoverability ✅ Logical organization by purpose ✅ Clean root directory ✅ Better maintainability
262 lines
7.3 KiB
PHP
262 lines
7.3 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
|
|
);
|
|
|
|
$record->setMessage('Modified message');
|
|
|
|
expect($record->getMessage())->toBe('Modified message');
|
|
});
|
|
|
|
it('can set channel after creation', function () {
|
|
$record = new LogRecord(
|
|
message: 'Test',
|
|
context: $this->context,
|
|
level: LogLevel::INFO,
|
|
timestamp: $this->timestamp
|
|
);
|
|
|
|
$record->setChannel('security');
|
|
|
|
expect($record->getChannel())->toBe('security');
|
|
});
|
|
|
|
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
|
|
);
|
|
|
|
$record->addExtra('request_id', 'req-123');
|
|
$record->addExtra('process_id', 5678);
|
|
|
|
expect($record->hasExtra('request_id'))->toBeTrue();
|
|
expect($record->getExtra('request_id'))->toBe('req-123');
|
|
expect($record->getExtra('process_id'))->toBe(5678);
|
|
expect($record->hasExtra('non_existent'))->toBeFalse();
|
|
});
|
|
|
|
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,
|
|
];
|
|
|
|
$record->addExtras($extras);
|
|
|
|
expect($record->getExtras())->toBe($extras);
|
|
expect($record->getExtra('server'))->toBe('web-01');
|
|
expect($record->getExtra('memory_usage'))->toBe(1024000);
|
|
expect($record->getExtra('execution_time'))->toBe(0.123);
|
|
});
|
|
|
|
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
|
|
->setMessage('New message')
|
|
->setChannel('custom')
|
|
->addExtra('key1', 'value1')
|
|
->addExtras(['key2' => 'value2']);
|
|
|
|
expect($result)->toBe($record);
|
|
expect($record->getMessage())->toBe('New message');
|
|
expect($record->getChannel())->toBe('custom');
|
|
expect($record->getExtra('key1'))->toBe('value1');
|
|
expect($record->getExtra('key2'))->toBe('value2');
|
|
});
|
|
|
|
it('converts to array correctly', function () {
|
|
$record = new LogRecord(
|
|
message: 'Test message',
|
|
context: $this->context,
|
|
level: LogLevel::WARNING,
|
|
timestamp: $this->timestamp,
|
|
channel: 'test-channel'
|
|
);
|
|
|
|
$record->addExtra('request_id', 'req-456');
|
|
|
|
$array = $record->toArray();
|
|
|
|
expect($array)->toHaveKeys([
|
|
'message',
|
|
'context',
|
|
'level',
|
|
'level_name',
|
|
'timestamp',
|
|
'datetime',
|
|
'channel',
|
|
'extra',
|
|
]);
|
|
|
|
expect($array['message'])->toBe('Test message');
|
|
expect($array['context'])->toMatchArray(['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
|
|
);
|
|
|
|
$record->addExtra('key', 'original');
|
|
expect($record->getExtra('key'))->toBe('original');
|
|
|
|
$record->addExtra('key', 'modified');
|
|
expect($record->getExtra('key'))->toBe('modified');
|
|
|
|
$record->addExtras(['key' => 'final']);
|
|
expect($record->getExtra('key'))->toBe('final');
|
|
});
|