- 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
268 lines
12 KiB
PHP
268 lines
12 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Framework\Logging;
|
|
|
|
use App\Framework\Core\PathProvider;
|
|
use App\Framework\Logging\DefaultLogger;
|
|
use App\Framework\Logging\Handlers\MultiFileHandler;
|
|
use App\Framework\Logging\LogConfig;
|
|
use App\Framework\Logging\LogLevel;
|
|
use App\Framework\Logging\ProcessorManager;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class ChannelLoggingIntegrationTest extends TestCase
|
|
{
|
|
private string $testLogDir;
|
|
|
|
private DefaultLogger $logger;
|
|
|
|
private LogConfig $logConfig;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
// Temporäres Test-Verzeichnis erstellen
|
|
$this->testLogDir = sys_get_temp_dir() . '/integration_logs_' . uniqid();
|
|
mkdir($this->testLogDir, 0755, true);
|
|
|
|
// PathProvider Mock
|
|
$pathProvider = $this->createMock(PathProvider::class);
|
|
$pathProvider->method('resolvePath')->willReturnCallback(function (string $path) {
|
|
return $this->testLogDir . '/' . $path;
|
|
});
|
|
|
|
// LogConfig Mock
|
|
$this->logConfig = $this->createMock(LogConfig::class);
|
|
$this->logConfig->method('getLogPath')->willReturnCallback(function (string $type) {
|
|
return match ($type) {
|
|
'security' => $this->testLogDir . '/security/security.log',
|
|
'cache' => $this->testLogDir . '/debug/cache.log',
|
|
'database' => $this->testLogDir . '/debug/database.log',
|
|
'framework' => $this->testLogDir . '/debug/framework.log',
|
|
'error' => $this->testLogDir . '/app/error.log',
|
|
default => $this->testLogDir . '/app/app.log'
|
|
};
|
|
});
|
|
|
|
// MultiFileHandler
|
|
$multiFileHandler = new MultiFileHandler(
|
|
$this->logConfig,
|
|
$pathProvider,
|
|
LogLevel::DEBUG,
|
|
'[{timestamp}] [{level_name}] [{channel}] {message}'
|
|
);
|
|
|
|
// DefaultLogger mit echtem MultiFileHandler
|
|
$this->logger = new DefaultLogger(
|
|
minLevel: LogLevel::DEBUG,
|
|
handlers: [$multiFileHandler],
|
|
processorManager: new ProcessorManager()
|
|
);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
// Cleanup: Test-Verzeichnis löschen
|
|
if (is_dir($this->testLogDir)) {
|
|
$this->deleteDirectory($this->testLogDir);
|
|
}
|
|
}
|
|
|
|
private function deleteDirectory(string $dir): void
|
|
{
|
|
if (! is_dir($dir)) {
|
|
return;
|
|
}
|
|
|
|
$files = array_diff(scandir($dir), ['.', '..']);
|
|
foreach ($files as $file) {
|
|
$path = $dir . '/' . $file;
|
|
is_dir($path) ? $this->deleteDirectory($path) : unlink($path);
|
|
}
|
|
rmdir($dir);
|
|
}
|
|
|
|
public function test_complete_channel_system_integration(): void
|
|
{
|
|
// Verschiedene Channel-Logs erstellen
|
|
$this->logger->security->warning('Failed login attempt', ['email' => 'test@example.com', 'ip' => '192.168.1.1']);
|
|
$this->logger->cache->debug('Cache miss', ['key' => 'user_123']);
|
|
$this->logger->database->error('Query timeout', ['query' => 'SELECT * FROM users', 'duration' => 30.5]);
|
|
$this->logger->framework->info('Route registered', ['route' => '/api/users', 'method' => 'GET']);
|
|
$this->logger->error->critical('System failure', ['component' => 'payment', 'error_code' => 'PAY_001']);
|
|
|
|
// Alle Log-Dateien sollten erstellt worden sein
|
|
expect(file_exists($this->testLogDir . '/security/security.log'))->toBeTrue();
|
|
expect(file_exists($this->testLogDir . '/debug/cache.log'))->toBeTrue();
|
|
expect(file_exists($this->testLogDir . '/debug/database.log'))->toBeTrue();
|
|
expect(file_exists($this->testLogDir . '/debug/framework.log'))->toBeTrue();
|
|
expect(file_exists($this->testLogDir . '/app/error.log'))->toBeTrue();
|
|
|
|
// Security Log Inhalt prüfen
|
|
$securityContent = file_get_contents($this->testLogDir . '/security/security.log');
|
|
expect($securityContent)->toContain('[WARNING] [security] Failed login attempt');
|
|
expect($securityContent)->toContain('"email":"test@example.com"');
|
|
expect($securityContent)->toContain('"ip":"192.168.1.1"');
|
|
|
|
// Cache Log Inhalt prüfen
|
|
$cacheContent = file_get_contents($this->testLogDir . '/debug/cache.log');
|
|
expect($cacheContent)->toContain('[DEBUG] [cache] Cache miss');
|
|
expect($cacheContent)->toContain('"key":"user_123"');
|
|
|
|
// Database Log Inhalt prüfen
|
|
$databaseContent = file_get_contents($this->testLogDir . '/debug/database.log');
|
|
expect($databaseContent)->toContain('[ERROR] [database] Query timeout');
|
|
expect($databaseContent)->toContain('"query":"SELECT * FROM users"');
|
|
expect($databaseContent)->toContain('"duration":30.5');
|
|
|
|
// Framework Log Inhalt prüfen
|
|
$frameworkContent = file_get_contents($this->testLogDir . '/debug/framework.log');
|
|
expect($frameworkContent)->toContain('[INFO] [framework] Route registered');
|
|
expect($frameworkContent)->toContain('"route":"\/api\/users"');
|
|
expect($frameworkContent)->toContain('"method":"GET"');
|
|
|
|
// Error Log Inhalt prüfen
|
|
$errorContent = file_get_contents($this->testLogDir . '/app/error.log');
|
|
expect($errorContent)->toContain('[CRITICAL] [error] System failure');
|
|
expect($errorContent)->toContain('"component":"payment"');
|
|
expect($errorContent)->toContain('"error_code":"PAY_001"');
|
|
}
|
|
|
|
public function test_mixed_standard_and_channel_logging(): void
|
|
{
|
|
// Mix aus Standard-Logging und Channel-Logging
|
|
$this->logger->info('Standard application log');
|
|
$this->logger->security->error('Security incident');
|
|
$this->logger->warning('Another standard log');
|
|
$this->logger->cache->info('Cache operation');
|
|
|
|
// Standard-Logs sollten nicht in den spezifischen Channel-Dateien landen
|
|
expect(file_exists($this->testLogDir . '/security/security.log'))->toBeTrue();
|
|
expect(file_exists($this->testLogDir . '/debug/cache.log'))->toBeTrue();
|
|
|
|
// Security Log sollte nur Security-spezifische Einträge haben
|
|
$securityContent = file_get_contents($this->testLogDir . '/security/security.log');
|
|
expect($securityContent)->toContain('Security incident');
|
|
expect($securityContent)->not->toContain('Standard application log');
|
|
expect($securityContent)->not->toContain('Another standard log');
|
|
|
|
// Cache Log sollte nur Cache-spezifische Einträge haben
|
|
$cacheContent = file_get_contents($this->testLogDir . '/debug/cache.log');
|
|
expect($cacheContent)->toContain('Cache operation');
|
|
expect($cacheContent)->not->toContain('Standard application log');
|
|
expect($cacheContent)->not->toContain('Security incident');
|
|
}
|
|
|
|
public function test_multiple_entries_same_channel(): void
|
|
{
|
|
// Mehrere Einträge in den gleichen Channel
|
|
$this->logger->security->info('User login', ['user_id' => 123]);
|
|
$this->logger->security->warning('Suspicious activity', ['user_id' => 123, 'actions' => ['login', 'password_change']]);
|
|
$this->logger->security->error('Account locked', ['user_id' => 123, 'reason' => 'too_many_attempts']);
|
|
|
|
$securityFile = $this->testLogDir . '/security/security.log';
|
|
expect(file_exists($securityFile))->toBeTrue();
|
|
|
|
$content = file_get_contents($securityFile);
|
|
$lines = explode("\n", trim($content));
|
|
|
|
// Drei Zeilen sollten vorhanden sein
|
|
expect($lines)->toHaveCount(3);
|
|
|
|
expect($content)->toContain('[INFO] [security] User login');
|
|
expect($content)->toContain('[WARNING] [security] Suspicious activity');
|
|
expect($content)->toContain('[ERROR] [security] Account locked');
|
|
|
|
// Alle Einträge sollten user_id 123 enthalten
|
|
expect($content)->toContain('"user_id":123');
|
|
}
|
|
|
|
public function test_channel_system_with_different_log_levels(): void
|
|
{
|
|
// Verschiedene Log-Level in verschiedenen Channels
|
|
$this->logger->cache->debug('Debug cache operation');
|
|
$this->logger->security->info('Info security event');
|
|
$this->logger->database->warning('Warning database issue');
|
|
$this->logger->framework->error('Error in framework');
|
|
$this->logger->error->critical('Critical system error');
|
|
|
|
// Alle Dateien sollten existieren
|
|
$files = [
|
|
'cache' => $this->testLogDir . '/debug/cache.log',
|
|
'security' => $this->testLogDir . '/security/security.log',
|
|
'database' => $this->testLogDir . '/debug/database.log',
|
|
'framework' => $this->testLogDir . '/debug/framework.log',
|
|
'error' => $this->testLogDir . '/app/error.log',
|
|
];
|
|
|
|
foreach ($files as $channel => $file) {
|
|
expect(file_exists($file))->toBeTrue("File for {$channel} channel should exist");
|
|
}
|
|
|
|
// Level sollten korrekt sein
|
|
expect(file_get_contents($files['cache']))->toContain('[DEBUG]');
|
|
expect(file_get_contents($files['security']))->toContain('[INFO]');
|
|
expect(file_get_contents($files['database']))->toContain('[WARNING]');
|
|
expect(file_get_contents($files['framework']))->toContain('[ERROR]');
|
|
expect(file_get_contents($files['error']))->toContain('[CRITICAL]');
|
|
}
|
|
|
|
public function test_realistic_application_scenario(): void
|
|
{
|
|
// Simuliere eine realistische Anwendungsszenario
|
|
|
|
// User Authentication Flow
|
|
$this->logger->security->info('Authentication attempt started', ['email' => 'user@example.com']);
|
|
$this->logger->cache->debug('Checking user cache', ['cache_key' => 'user_user@example.com']);
|
|
$this->logger->cache->debug('Cache miss - loading from database');
|
|
$this->logger->database->debug('User query executed', ['query' => 'SELECT * FROM users WHERE email = ?']);
|
|
$this->logger->security->info('User authenticated successfully', ['user_id' => 42]);
|
|
$this->logger->cache->info('User cached', ['cache_key' => 'user_42', 'ttl' => 3600]);
|
|
|
|
// API Request Processing
|
|
$this->logger->framework->debug('Route matched', ['route' => '/api/orders', 'method' => 'GET']);
|
|
$this->logger->database->debug('Orders query', ['user_id' => 42, 'limit' => 10]);
|
|
$this->logger->cache->debug('Cache hit', ['cache_key' => 'orders_42_page_1']);
|
|
|
|
// Error Scenario
|
|
$this->logger->database->error('Database connection lost', ['host' => 'db.example.com', 'port' => 3306]);
|
|
$this->logger->error->critical('Service degraded', ['affected_services' => ['orders', 'payments']]);
|
|
$this->logger->security->warning('Potential attack detected', ['ip' => '1.2.3.4', 'pattern' => 'sql_injection']);
|
|
|
|
// Überprüfe dass alle Logs korrekt in ihre Kanäle geschrieben wurden
|
|
$securityLog = file_get_contents($this->testLogDir . '/security/security.log');
|
|
$cacheLog = file_get_contents($this->testLogDir . '/debug/cache.log');
|
|
$databaseLog = file_get_contents($this->testLogDir . '/debug/database.log');
|
|
$frameworkLog = file_get_contents($this->testLogDir . '/debug/framework.log');
|
|
$errorLog = file_get_contents($this->testLogDir . '/app/error.log');
|
|
|
|
// Security-Ereignisse
|
|
expect($securityLog)->toContain('Authentication attempt started');
|
|
expect($securityLog)->toContain('User authenticated successfully');
|
|
expect($securityLog)->toContain('Potential attack detected');
|
|
|
|
// Cache-Operationen
|
|
expect($cacheLog)->toContain('Checking user cache');
|
|
expect($cacheLog)->toContain('Cache miss');
|
|
expect($cacheLog)->toContain('User cached');
|
|
expect($cacheLog)->toContain('Cache hit');
|
|
|
|
// Database-Operationen
|
|
expect($databaseLog)->toContain('User query executed');
|
|
expect($databaseLog)->toContain('Orders query');
|
|
expect($databaseLog)->toContain('Database connection lost');
|
|
|
|
// Framework-Ereignisse
|
|
expect($frameworkLog)->toContain('Route matched');
|
|
|
|
// Error-Ereignisse
|
|
expect($errorLog)->toContain('Service degraded');
|
|
|
|
// Cross-channel Isolation prüfen
|
|
expect($securityLog)->not->toContain('Cache miss');
|
|
expect($cacheLog)->not->toContain('Authentication attempt');
|
|
expect($databaseLog)->not->toContain('Route matched');
|
|
}
|
|
}
|