Files
michaelschiemer/tests/Unit/Framework/Logging/ValueObjects/LogReadResultTest.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.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\ValueObjects\LogEntry;
use App\Framework\Logging\ValueObjects\LogName;
use App\Framework\Logging\ValueObjects\LogReadResult;
describe('LogReadResult', function () {
beforeEach(function () {
$this->logName = LogName::fromString('app_error');
$this->logPath = FilePath::create('/tmp/test.log');
$this->entries = [
LogEntry::fromParsedLine(
timestamp: '2024-01-15 10:30:45',
level: 'ERROR',
messageWithContext: 'Database error',
raw: '[2024-01-15 10:30:45] local.ERROR: Database error',
sourcePath: $this->logPath
),
LogEntry::fromParsedLine(
timestamp: '2024-01-15 10:31:00',
level: 'WARNING',
messageWithContext: 'Cache miss',
raw: '[2024-01-15 10:31:00] local.WARNING: Cache miss',
sourcePath: $this->logPath
),
LogEntry::fromParsedLine(
timestamp: '2024-01-15 10:31:30',
level: 'INFO',
messageWithContext: 'User logged in',
raw: '[2024-01-15 10:31:30] local.INFO: User logged in',
sourcePath: $this->logPath
),
];
});
it('creates from entries', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
expect($result->logName)->toBe($this->logName);
expect($result->logPath)->toBe($this->logPath);
expect($result->entries)->toHaveCount(3);
expect($result->totalEntries)->toBe(3);
expect($result->limit)->toBe(100);
});
it('checks if empty', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: [],
limit: 100
);
expect($result->isEmpty())->toBeTrue();
expect($result->hasEntries())->toBeFalse();
});
it('filters by log level', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$filtered = $result->filterByLevel(LogLevel::ERROR);
expect($filtered->entries)->toHaveCount(1);
expect($filtered->entries[0]->level)->toBe(LogLevel::ERROR);
});
it('filters by search term', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$filtered = $result->filterBySearch('database');
expect($filtered->entries)->toHaveCount(1);
expect($filtered->entries[0]->message)->toContain('Database');
});
it('filters by minimum log level', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$filtered = $result->filterByMinimumLevel(LogLevel::WARNING);
expect($filtered->entries)->toHaveCount(2); // ERROR and WARNING
expect($filtered->first()->level)->toBe(LogLevel::ERROR);
expect($filtered->last()->level)->toBe(LogLevel::WARNING);
});
it('gets first entry', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$first = $result->first();
expect($first)->not->toBeNull();
expect($first->level)->toBe(LogLevel::ERROR);
});
it('gets last entry', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$last = $result->last();
expect($last)->not->toBeNull();
expect($last->level)->toBe(LogLevel::INFO);
});
it('returns null for first/last on empty result', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: [],
limit: 100
);
expect($result->first())->toBeNull();
expect($result->last())->toBeNull();
});
it('takes limited entries', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$limited = $result->take(2);
expect($limited->entries)->toHaveCount(2);
expect($limited->totalEntries)->toBe(2);
});
it('skips entries', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$skipped = $result->skip(1);
expect($skipped->entries)->toHaveCount(2);
expect($skipped->first()->level)->toBe(LogLevel::WARNING);
});
it('reverses entry order', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$reversed = $result->reverse();
expect($reversed->first()->level)->toBe(LogLevel::INFO);
expect($reversed->last()->level)->toBe(LogLevel::ERROR);
});
it('gets level statistics', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$stats = $result->getLevelStatistics();
expect($stats)->toBeArray();
expect($stats['ERROR'])->toBe(1);
expect($stats['WARNING'])->toBe(1);
expect($stats['INFO'])->toBe(1);
});
it('gets metadata', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100,
search: 'test',
levelFilter: LogLevel::ERROR
);
$metadata = $result->getMetadata();
expect($metadata)->toBeArray();
expect($metadata['log_name'])->toBe('app_error');
expect($metadata['total_entries'])->toBe(3);
expect($metadata['limit'])->toBe(100);
expect($metadata['search'])->toBe('test');
expect($metadata['level_filter'])->toBe('ERROR');
});
it('converts to array', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$array = $result->toArray();
expect($array)->toHaveKey('log_name');
expect($array)->toHaveKey('log_path');
expect($array)->toHaveKey('entries');
expect($array)->toHaveKey('total_entries');
expect($array)->toHaveKey('metadata');
expect($array['entries'])->toBeArray();
expect($array['entries'])->toHaveCount(3);
});
it('creates iterator', function () {
$result = LogReadResult::fromEntries(
logName: $this->logName,
logPath: $this->logPath,
entries: $this->entries,
limit: 100
);
$iterator = $result->getIterator();
expect($iterator)->toBeInstanceOf(\ArrayIterator::class);
$count = 0;
foreach ($iterator as $entry) {
expect($entry)->toBeInstanceOf(LogEntry::class);
$count++;
}
expect($count)->toBe(3);
});
});