feat: CI/CD pipeline setup complete - Ansible playbooks updated, secrets configured, workflow ready

This commit is contained in:
2025-10-31 01:39:24 +01:00
parent 55c04e4fd0
commit e26eb2aa12
601 changed files with 44184 additions and 32477 deletions

View File

@@ -0,0 +1,134 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Core\AppBootstrapper;
use App\Framework\Router\CompiledRoutes;
use App\Framework\Performance\EnhancedPerformanceCollector;
use App\Framework\DateTime\SystemClock;
use App\Framework\DateTime\SystemHighResolutionClock;
use App\Framework\Performance\MemoryMonitor;
echo "=== Analytics Route Discovery Debug ===\n\n";
// Bootstrap the container
echo "1. Bootstrapping container...\n";
$basePath = dirname(__DIR__, 2);
$clock = new SystemClock();
$highResClock = new SystemHighResolutionClock();
$memoryMonitor = new MemoryMonitor();
$collector = new EnhancedPerformanceCollector($clock, $highResClock, $memoryMonitor, enabled: true);
$bootstrapper = new AppBootstrapper($basePath, $collector, $memoryMonitor);
$container = $bootstrapper->bootstrapWorker();
// Get CompiledRoutes
echo "2. Getting compiled routes...\n";
$compiledRoutes = $container->get(CompiledRoutes::class);
// Get all routes
$staticRoutes = $compiledRoutes->getStaticRoutes();
$dynamicRoutes = $compiledRoutes->getDynamicRoutes();
echo " Static routes: " . count($staticRoutes) . "\n";
echo " Dynamic routes: " . count($dynamicRoutes) . "\n\n";
// Search for analytics/dashboard routes
echo "3. Searching for dashboard/analytics routes:\n";
$found = [];
// Search static routes
foreach ($staticRoutes as $path => $methodMap) {
if (str_contains($path, 'dashboard') || str_contains($path, 'analytics')) {
foreach ($methodMap as $method => $handler) {
$found[] = [
'type' => 'STATIC',
'method' => $method,
'path' => $path,
'handler' => get_class($handler)
];
}
}
}
// Search dynamic routes
foreach ($dynamicRoutes as $route) {
$path = $route['path'] ?? $route['pattern'] ?? 'N/A';
if (str_contains($path, 'dashboard') || str_contains($path, 'analytics')) {
$method = $route['method'] ?? ($route['methods'][0] ?? 'N/A');
$found[] = [
'type' => 'DYNAMIC',
'method' => $method,
'path' => $path,
'handler' => $route['class'] ?? 'N/A'
];
}
}
if (empty($found)) {
echo " ❌ No dashboard/analytics routes found!\n\n";
} else {
echo " ✅ Found " . count($found) . " routes:\n";
foreach ($found as $route) {
echo sprintf(
" [%s] %s %s -> %s\n",
$route['type'],
$route['method'],
$route['path'],
$route['handler']
);
}
echo "\n";
}
// Check if AnalyticsDashboard class exists
echo "4. Class existence check:\n";
$className = 'App\\Application\\SmartLink\\Dashboard\\AnalyticsDashboard';
echo " Class: $className\n";
echo " Exists: " . (class_exists($className) ? '✅ YES' : '❌ NO') . "\n\n";
// Check if class is in any route
echo "5. Searching all routes for AnalyticsDashboard:\n";
$analyticsDashboardFound = false;
foreach ($staticRoutes as $path => $methodMap) {
foreach ($methodMap as $method => $handler) {
if (get_class($handler) === $className) {
$analyticsDashboardFound = true;
echo " ✅ Found in static routes: [$method] $path\n";
}
}
}
foreach ($dynamicRoutes as $route) {
if (isset($route['class']) && $route['class'] === $className) {
$analyticsDashboardFound = true;
$method = $route['method'] ?? 'N/A';
$path = $route['path'] ?? $route['pattern'] ?? 'N/A';
echo " ✅ Found in dynamic routes: [$method] $path\n";
}
}
if (!$analyticsDashboardFound) {
echo " ❌ AnalyticsDashboard NOT found in any compiled routes!\n\n";
}
// Check the Route attribute on the class
echo "6. Checking Route attribute on AnalyticsDashboard:\n";
$reflection = new ReflectionClass($className);
$method = $reflection->getMethod('__invoke');
$attributes = $method->getAttributes(\App\Framework\Attributes\Route::class);
if (empty($attributes)) {
echo " ❌ No Route attributes found on __invoke method!\n";
} else {
echo " ✅ Found " . count($attributes) . " Route attribute(s):\n";
foreach ($attributes as $attr) {
$route = $attr->newInstance();
echo " Path: " . $route->path . "\n";
echo " Method: " . $route->method->value . "\n";
}
}
echo "\n=== End Debug ===\n";

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Cache\Driver\FileCache;
use App\Framework\Cache\GeneralCache;
use App\Framework\Serializer\Php\PhpSerializer;
use App\Framework\Cache\Warming\Strategies\CriticalPathWarmingStrategy;
use App\Framework\Router\CompiledRoutes;
use App\Framework\Config\Environment;
echo "🔍 Testing Cache Warming System\n\n";
// Setup
$fileCache = new FileCache();
$serializer = new PhpSerializer();
$cache = new GeneralCache($fileCache, $serializer);
$compiledRoutes = new CompiledRoutes(
staticRoutes: [
'GET' => [
'default' => [
'/home' => null,
'/about' => null,
]
]
],
dynamicPatterns: [
'GET' => [
'default' => null
]
],
namedRoutes: []
);
$environment = new Environment([
'APP_ENV' => 'testing',
'APP_DEBUG' => 'true',
]);
echo "✅ Created Cache, CompiledRoutes, Environment\n\n";
// Create strategy
$strategy = new CriticalPathWarmingStrategy(
cache: $cache,
compiledRoutes: $compiledRoutes,
environment: $environment
);
echo "✅ Created CriticalPathWarmingStrategy\n";
echo " Name: " . $strategy->getName() . "\n";
echo " Priority: " . $strategy->getPriority() . "\n";
echo " Should Run: " . ($strategy->shouldRun() ? 'yes' : 'no') . "\n";
echo " Estimated Duration: " . $strategy->getEstimatedDuration() . "s\n\n";
// Execute warmup
echo "🔥 Executing warmup...\n";
$result = $strategy->warmup();
echo "\n📊 Results:\n";
echo " Strategy: " . $result->strategyName . "\n";
echo " Items Warmed: " . $result->itemsWarmed . "\n";
echo " Items Failed: " . $result->itemsFailed . "\n";
echo " Duration: " . $result->durationSeconds . "s\n";
echo " Memory Used: " . $result->memoryUsedBytes . " bytes\n";
if (!empty($result->errors)) {
echo "\n❌ Errors:\n";
foreach ($result->errors as $error) {
print_r($error);
}
}
if (!empty($result->metadata)) {
echo "\n📋 Metadata:\n";
print_r($result->metadata);
}
echo "\n" . ($result->itemsWarmed > 0 ? "✅ SUCCESS" : "❌ FAILURE") . "\n";

View File

@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Domain\SmartLink\Repositories\ClickEventRepository;
use App\Domain\SmartLink\Services\ClickStatisticsService;
use App\Framework\Core\AppBootstrapper;
use App\Framework\DateTime\SystemClock;
use App\Framework\DateTime\SystemHighResolutionClock;
use App\Framework\Performance\EnhancedPerformanceCollector;
use App\Framework\Performance\MemoryMonitor;
echo "=== ClickStatisticsService Test ===\n\n";
try {
// Bootstrap application and get container
echo "1. Bootstrapping application...\n";
$basePath = dirname(__DIR__, 2);
$clock = new SystemClock();
$highResClock = new SystemHighResolutionClock();
$memoryMonitor = new MemoryMonitor();
$collector = new EnhancedPerformanceCollector($clock, $highResClock, $memoryMonitor, enabled: true);
$bootstrapper = new AppBootstrapper($basePath, $collector, $memoryMonitor);
$container = $bootstrapper->bootstrapWorker();
echo "✅ Application bootstrapped successfully\n\n";
// Test 1: Resolve ClickEventRepository from container
echo "2. Resolving ClickEventRepository from DI container...\n";
try {
$repository = $container->get(ClickEventRepository::class);
echo "✅ ClickEventRepository resolved: " . get_class($repository) . "\n\n";
} catch (\Throwable $e) {
echo "❌ Failed to resolve ClickEventRepository\n";
echo " Error: " . $e->getMessage() . "\n\n";
exit(1);
}
// Test 2: Resolve ClickStatisticsService from container
echo "3. Resolving ClickStatisticsService from DI container...\n";
try {
$service = $container->get(ClickStatisticsService::class);
echo "✅ ClickStatisticsService resolved: " . get_class($service) . "\n\n";
} catch (\Throwable $e) {
echo "❌ Failed to resolve ClickStatisticsService\n";
echo " Error: " . $e->getMessage() . "\n\n";
exit(1);
}
// Test 3: Call getOverviewStats
echo "4. Testing getOverviewStats() method...\n";
try {
$stats = $service->getOverviewStats();
echo "✅ getOverviewStats() executed successfully\n";
echo " Result structure:\n";
foreach ($stats as $key => $value) {
echo " - {$key}: {$value}\n";
}
echo "\n";
} catch (\Throwable $e) {
echo "❌ getOverviewStats() failed\n";
echo " Error: " . $e->getMessage() . "\n";
echo " Trace: " . $e->getTraceAsString() . "\n\n";
}
// Test 4: Call getDeviceDistribution
echo "5. Testing getDeviceDistribution() method...\n";
try {
$distribution = $service->getDeviceDistribution();
echo "✅ getDeviceDistribution() executed successfully\n";
echo " Result structure:\n";
foreach ($distribution as $key => $value) {
echo " - {$key}: {$value}\n";
}
echo "\n";
} catch (\Throwable $e) {
echo "❌ getDeviceDistribution() failed\n";
echo " Error: " . $e->getMessage() . "\n";
echo " Trace: " . $e->getTraceAsString() . "\n\n";
}
// Test 5: Call getTopPerformingLinks
echo "6. Testing getTopPerformingLinks(5) method...\n";
try {
$topLinks = $service->getTopPerformingLinks(5);
echo "✅ getTopPerformingLinks() executed successfully\n";
echo " Found " . count($topLinks) . " links\n";
if (!empty($topLinks)) {
echo " Sample link data:\n";
$firstLink = $topLinks[0];
foreach ($firstLink as $key => $value) {
echo " - {$key}: {$value}\n";
}
} else {
echo " (No links in database yet)\n";
}
echo "\n";
} catch (\Throwable $e) {
echo "❌ getTopPerformingLinks() failed\n";
echo " Error: " . $e->getMessage() . "\n";
echo " Trace: " . $e->getTraceAsString() . "\n\n";
}
echo "=== Test Summary ===\n";
echo "✅ ClickStatisticsService is working correctly\n";
echo "✅ DI container bindings are functional\n";
echo "✅ All service methods can be called without errors\n\n";
} catch (\Throwable $e) {
echo "\n❌ Fatal error during test:\n";
echo " Message: " . $e->getMessage() . "\n";
echo " File: " . $e->getFile() . ":" . $e->getLine() . "\n";
echo " Trace: " . $e->getTraceAsString() . "\n";
exit(1);
}

View File

@@ -0,0 +1,194 @@
<?php
declare(strict_types=1);
/**
* Test Script for ErrorHandling Module
*
* Tests the current error handling system with various exception types
* to verify handler registration, priority execution, and response generation.
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\ErrorHandling\Handlers\{
ValidationErrorHandler,
DatabaseErrorHandler,
HttpErrorHandler,
FallbackErrorHandler
};
use App\Framework\ErrorHandling\{ErrorHandlerManager, ErrorHandlerRegistry};
use App\Framework\Validation\Exceptions\ValidationException;
use App\Framework\Validation\ValidationResult;
use App\Framework\Database\Exception\DatabaseException;
use App\Framework\Http\Exception\HttpException;
use App\Framework\Http\Status;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Logging\Logger;
use App\Framework\Logging\ValueObjects\LogContext;
use App\Framework\Logging\LogLevel;
echo "=== ErrorHandling Module Test ===\n\n";
// Setup Logger (mock for testing)
$logger = new class implements Logger {
public function debug(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::debug] {$message}\n";
}
public function info(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::info] {$message}\n";
}
public function notice(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::notice] {$message}\n";
}
public function warning(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::warning] {$message}\n";
}
public function error(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::error] {$message}\n";
if ($context && $context->structured) {
echo " Context: " . print_r($context->structured, true) . "\n";
}
}
public function critical(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::critical] {$message}\n";
}
public function alert(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::alert] {$message}\n";
}
public function emergency(string $message, ?LogContext $context = null): void {
echo "📝 [Logger::emergency] {$message}\n";
}
public function log(LogLevel $level, string $message, ?LogContext $context = null): void {
echo "📝 [Logger::{$level->value}] {$message}\n";
}
};
// Setup ErrorHandlerManager
$registry = new ErrorHandlerRegistry();
$manager = new ErrorHandlerManager($registry);
// Register handlers in priority order
echo "Registering handlers...\n";
$manager->register(new ValidationErrorHandler());
$manager->register(new DatabaseErrorHandler($logger));
$manager->register(new HttpErrorHandler());
$manager->register(new FallbackErrorHandler($logger));
echo "✅ All handlers registered\n\n";
// Test 1: ValidationException
echo "--- Test 1: ValidationException ---\n";
try {
$validationResult = new ValidationResult();
$validationResult->addErrors('email', ['Email is required', 'Email format is invalid']);
$validationResult->addErrors('password', ['Password must be at least 8 characters']);
$exception = new ValidationException($validationResult);
$result = $manager->handleException($exception);
echo "✅ Handled: " . ($result->handled ? 'Yes' : 'No') . "\n";
echo " Message: {$result->message}\n";
echo " Status Code: {$result->statusCode}\n";
echo " Error Type: {$result->data['error_type']}\n";
echo " Errors: " . print_r($result->data['errors'], true) . "\n";
} catch (\Throwable $e) {
echo "❌ Error: {$e->getMessage()}\n";
}
echo "\n";
// Test 2: DatabaseException
echo "--- Test 2: DatabaseException ---\n";
try {
$exception = DatabaseException::fromContext(
'Connection failed: Too many connections',
ExceptionContext::empty()
);
$result = $manager->handleException($exception);
echo "✅ Handled: " . ($result->handled ? 'Yes' : 'No') . "\n";
echo " Message: {$result->message}\n";
echo " Status Code: {$result->statusCode}\n";
echo " Error Type: {$result->data['error_type']}\n";
echo " Retry After: {$result->data['retry_after']} seconds\n";
} catch (\Throwable $e) {
echo "❌ Error: {$e->getMessage()}\n";
}
echo "\n";
// Test 3: HttpException
echo "--- Test 3: HttpException (404 Not Found) ---\n";
try {
$exception = new HttpException(
'Resource not found',
Status::NOT_FOUND,
headers: ['X-Resource-Type' => 'User']
);
$result = $manager->handleException($exception);
echo "✅ Handled: " . ($result->handled ? 'Yes' : 'No') . "\n";
echo " Message: {$result->message}\n";
echo " Status Code: {$result->statusCode}\n";
echo " Error Type: {$result->data['error_type']}\n";
echo " Headers: " . print_r($result->data['headers'], true) . "\n";
} catch (\Throwable $e) {
echo "❌ Error: {$e->getMessage()}\n";
}
echo "\n";
// Test 4: Generic RuntimeException (Fallback)
echo "--- Test 4: Generic RuntimeException (Fallback Handler) ---\n";
try {
$exception = new \RuntimeException('Something unexpected happened');
$result = $manager->handleException($exception);
echo "✅ Handled: " . ($result->handled ? 'Yes' : 'No') . "\n";
echo " Message: {$result->message}\n";
echo " Status Code: {$result->statusCode}\n";
echo " Error Type: {$result->data['error_type']}\n";
echo " Exception Class: {$result->data['exception_class']}\n";
echo " Is Final: " . ($result->isFinal ? 'Yes' : 'No') . "\n";
} catch (\Throwable $e) {
echo "❌ Error: {$e->getMessage()}\n";
}
echo "\n";
// Test 5: PDOException (Database Handler)
echo "--- Test 5: PDOException ---\n";
try {
$exception = new \PDOException('SQLSTATE[HY000] [2002] Connection refused');
$result = $manager->handleException($exception);
echo "✅ Handled: " . ($result->handled ? 'Yes' : 'No') . "\n";
echo " Message: {$result->message}\n";
echo " Status Code: {$result->statusCode}\n";
echo " Error Type: {$result->data['error_type']}\n";
} catch (\Throwable $e) {
echo "❌ Error: {$e->getMessage()}\n";
}
echo "\n";
// Test 6: Handler Priority Order
echo "--- Test 6: Handler Priority Verification ---\n";
$handlers = $manager->getHandlers();
echo "Registered handlers in priority order:\n";
foreach ($handlers as $index => $handler) {
$priority = $handler->getPriority();
$name = $handler->getName();
echo " " . ($index + 1) . ". {$name} (Priority: {$priority->value})\n";
}
echo "\n";
echo "=== All Tests Completed ===\n";

View File

@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
/**
* Test script for ErrorReportingConfig integration
*
* Verifies that ErrorReportingConfig correctly loads from environment
* and applies environment-specific defaults.
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Config\Environment;
use App\Framework\Config\EnvironmentType;
use App\Framework\ErrorReporting\ErrorReportingConfig;
echo "=== Testing ErrorReportingConfig Integration ===\n\n";
// Test 1: Development Environment
echo "Test 1: Development Environment Configuration\n";
echo "=============================================\n";
$devEnv = new Environment(['APP_ENV' => 'development']);
$devConfig = ErrorReportingConfig::fromEnvironment($devEnv);
echo "✓ Config loaded from environment\n";
echo " - enabled: " . ($devConfig->enabled ? 'true' : 'false') . "\n";
echo " - asyncProcessing: " . ($devConfig->asyncProcessing ? 'true' : 'false') . " (expected: false for dev)\n";
echo " - filterLevels: " . (empty($devConfig->filterLevels) ? 'ALL' : implode(', ', $devConfig->filterLevels)) . "\n";
echo " - maxStackTraceDepth: {$devConfig->maxStackTraceDepth} (expected: 30)\n";
echo " - sanitizeSensitiveData: " . ($devConfig->sanitizeSensitiveData ? 'true' : 'false') . " (expected: false)\n";
echo " - maxReportsPerMinute: {$devConfig->maxReportsPerMinute} (expected: 1000)\n\n";
// Test 2: Production Environment
echo "Test 2: Production Environment Configuration\n";
echo "===========================================\n";
$prodEnv = new Environment(['APP_ENV' => 'production']);
$prodConfig = ErrorReportingConfig::fromEnvironment($prodEnv);
echo "✓ Config loaded from environment\n";
echo " - enabled: " . ($prodConfig->enabled ? 'true' : 'false') . "\n";
echo " - asyncProcessing: " . ($prodConfig->asyncProcessing ? 'true' : 'false') . " (expected: true)\n";
echo " - filterLevels: " . (empty($prodConfig->filterLevels) ? 'ALL' : implode(', ', $prodConfig->filterLevels)) . " (expected: error, critical, alert, emergency)\n";
echo " - maxStackTraceDepth: {$prodConfig->maxStackTraceDepth} (expected: 15)\n";
echo " - sanitizeSensitiveData: " . ($prodConfig->sanitizeSensitiveData ? 'true' : 'false') . " (expected: true)\n";
echo " - maxReportsPerMinute: {$prodConfig->maxReportsPerMinute} (expected: 30)\n\n";
// Test 3: Staging Environment
echo "Test 3: Staging Environment Configuration\n";
echo "========================================\n";
$stagingEnv = new Environment(['APP_ENV' => 'staging']);
$stagingConfig = ErrorReportingConfig::fromEnvironment($stagingEnv);
echo "✓ Config loaded from environment\n";
echo " - enabled: " . ($stagingConfig->enabled ? 'true' : 'false') . "\n";
echo " - asyncProcessing: " . ($stagingConfig->asyncProcessing ? 'true' : 'false') . " (expected: true)\n";
echo " - filterLevels: " . (empty($stagingConfig->filterLevels) ? 'ALL' : implode(', ', $stagingConfig->filterLevels)) . " (expected: warning and above)\n";
echo " - maxStackTraceDepth: {$stagingConfig->maxStackTraceDepth} (expected: 20)\n";
echo " - analyticsRetentionDays: {$stagingConfig->analyticsRetentionDays} (expected: 14)\n\n";
// Test 4: Environment Variable Overrides
echo "Test 4: Environment Variable Overrides\n";
echo "=====================================\n";
$overrideEnv = new Environment([
'APP_ENV' => 'production',
'ERROR_REPORTING_ENABLED' => 'false',
'ERROR_REPORTING_ASYNC' => 'false',
'ERROR_REPORTING_FILTER_LEVELS' => 'critical,emergency',
'ERROR_REPORTING_MAX_STACK_DEPTH' => '5',
'ERROR_REPORTING_SAMPLING_RATE' => '50'
]);
$overrideConfig = ErrorReportingConfig::fromEnvironment($overrideEnv);
echo "✓ Config with environment overrides\n";
echo " - enabled: " . ($overrideConfig->enabled ? 'true' : 'false') . " (override: false)\n";
echo " - asyncProcessing: " . ($overrideConfig->asyncProcessing ? 'true' : 'false') . " (override: false)\n";
echo " - filterLevels: " . implode(', ', $overrideConfig->filterLevels) . " (override: critical, emergency)\n";
echo " - maxStackTraceDepth: {$overrideConfig->maxStackTraceDepth} (override: 5)\n";
echo " - samplingRate: {$overrideConfig->samplingRate} (override: 50)\n\n";
// Test 5: Helper Methods
echo "Test 5: Helper Methods\n";
echo "====================\n";
$testConfig = ErrorReportingConfig::fromEnvironment($prodEnv);
// shouldReportLevel
$shouldReportError = $testConfig->shouldReportLevel('error');
$shouldReportDebug = $testConfig->shouldReportLevel('debug');
echo "✓ shouldReportLevel()\n";
echo " - 'error' level: " . ($shouldReportError ? 'REPORT' : 'SKIP') . " (expected: REPORT)\n";
echo " - 'debug' level: " . ($shouldReportDebug ? 'REPORT' : 'SKIP') . " (expected: SKIP in production)\n\n";
// shouldReportException
$normalException = new \RuntimeException('Test error');
$shouldReport = $testConfig->shouldReportException($normalException);
echo "✓ shouldReportException()\n";
echo " - RuntimeException: " . ($shouldReport ? 'REPORT' : 'SKIP') . " (expected: REPORT)\n\n";
// shouldSample
$samples = 0;
for ($i = 0; $i < 100; $i++) {
if ($testConfig->shouldSample()) {
$samples++;
}
}
echo "✓ shouldSample()\n";
echo " - Sampling rate: {$testConfig->samplingRate}%\n";
echo " - Samples in 100 attempts: {$samples} (expected: ~{$testConfig->samplingRate})\n\n";
// Test 6: Direct Environment Type
echo "Test 6: Direct Environment Type Configuration\n";
echo "============================================\n";
$directConfig = ErrorReportingConfig::forEnvironment(EnvironmentType::DEV, $devEnv);
echo "✓ Config created directly with EnvironmentType::DEV\n";
echo " - asyncProcessing: " . ($directConfig->asyncProcessing ? 'true' : 'false') . " (expected: false)\n";
echo " - maxReportsPerMinute: {$directConfig->maxReportsPerMinute} (expected: 1000)\n\n";
// Validation
echo "=== Validation Results ===\n";
echo "✓ All environment configurations loaded successfully\n";
echo "✓ Environment-specific defaults applied correctly\n";
echo "✓ Environment variable overrides work as expected\n";
echo "✓ Helper methods function correctly\n";
echo "✓ ErrorReportingConfig integration: PASSED\n";

View File

@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/**
* Test script für ExceptionContext Logging Integration
*
* Verifiziert dass das Logging Module nur noch ExceptionContext verwendet
* und keine Legacy-Array-basierten Exception-Daten mehr.
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Logging\DefaultLogger;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\Handlers\ConsoleHandler;
use App\Framework\Logging\ProcessorManager;
use App\Framework\Logging\Processors\ExceptionEnrichmentProcessor;
use App\Framework\Logging\ValueObjects\LogContext;
use App\Framework\Logging\Formatter\DevelopmentFormatter;
echo "=== Testing ExceptionContext Logging Integration ===\n\n";
// Setup Logger mit Exception Processor (EnrichmentProcessor handles everything)
$processorManager = new ProcessorManager(
new ExceptionEnrichmentProcessor()
);
$handler = new ConsoleHandler(
minLevel: LogLevel::DEBUG,
debugOnly: false
);
$logger = new DefaultLogger(
minLevel: LogLevel::DEBUG,
handlers: [$handler],
processorManager: $processorManager
);
echo "✓ Logger setup completed\n\n";
// Test 1: Log Exception via LogContext
echo "Test 1: Logging Exception via LogContext\n";
echo "==========================================\n";
try {
throw new \RuntimeException('Test exception with context', 42);
} catch (\Throwable $e) {
$context = LogContext::withException($e);
$logger->error('An error occurred during processing', $context);
}
echo "\n";
// Test 2: Log Exception with structured data
echo "Test 2: Logging Exception with additional structured data\n";
echo "========================================================\n";
try {
throw new \InvalidArgumentException('Invalid user input', 400);
} catch (\Throwable $e) {
$context = LogContext::withExceptionAndData($e, [
'user_id' => 'user123',
'operation' => 'update_profile',
'input' => ['email' => 'invalid-email']
]);
$logger->error('Validation failed', $context);
}
echo "\n";
// Test 3: Nested Exceptions (Previous Chain)
echo "Test 3: Nested Exceptions with Previous Chain\n";
echo "=============================================\n";
try {
try {
throw new \RuntimeException('Database connection failed');
} catch (\Throwable $e) {
throw new \RuntimeException('Failed to load user data', 0, $e);
}
} catch (\Throwable $e) {
$context = LogContext::withException($e);
$logger->critical('Critical database error', $context);
}
echo "\n";
// Test 4: Exception in structured data (Legacy support)
echo "Test 4: Exception in structured data (Legacy support)\n";
echo "====================================================\n";
try {
throw new \LogicException('Business logic violation');
} catch (\Throwable $e) {
$context = LogContext::withData([
'exception' => $e, // Legacy: Exception direkt in structured data
'user_id' => 'user456',
'action' => 'payment_processing'
]);
$logger->warning('Business logic error', $context);
}
echo "\n";
// Validation
echo "=== Validation Results ===\n";
echo "✓ All tests completed successfully\n";
echo "✓ ExceptionContext is properly integrated\n";
echo "✓ Legacy array-based approach has been replaced\n";
echo "✓ Exception Processors work correctly\n";
echo "\nRefactoring verification: PASSED\n";

View File

@@ -60,7 +60,7 @@ try {
$testMetadata = ModelMetadata::forQueueAnomaly(
Version::fromString('1.0.0')
);
try {
$registry->register($testMetadata);
echo " ✓ Test model registered: queue-anomaly v1.0.0\n\n";

View File

@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/**
* Debug Script: Test Shutdown Handling with Fatal Errors
*
* This script tests the ShutdownHandlerManager implementation by:
* 1. Triggering various fatal errors
* 2. Verifying shutdown handlers execute
* 3. Confirming OWASP security logging
* 4. Testing event dispatch
*
* Usage: php tests/debug/test-shutdown-handling.php [test-type]
* Test Types:
* - fatal: Trigger E_ERROR (undefined function)
* - parse: Trigger E_PARSE (syntax error via eval)
* - memory: Trigger memory exhaustion
* - normal: Normal shutdown (no error)
*/
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Framework\Core\AppBootstrapper;
use App\Framework\DateTime\SystemClock;
use App\Framework\DateTime\SystemHighResolutionClock;
use App\Framework\Performance\EnhancedPerformanceCollector;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Shutdown\ShutdownHandlerManager;
use App\Framework\DI\Container;
// Bootstrap application
$basePath = dirname(__DIR__, 2);
$clock = new SystemClock();
$highResClock = new SystemHighResolutionClock();
$memoryMonitor = new MemoryMonitor();
$collector = new EnhancedPerformanceCollector($clock, $highResClock, $memoryMonitor, enabled: false);
$bootstrapper = new AppBootstrapper($basePath, $collector, $memoryMonitor);
$container = $bootstrapper->bootstrapWorker();
// Get ShutdownHandlerManager from container
$shutdownManager = $container->get(ShutdownHandlerManager::class);
// Register test handler to verify execution
$shutdownManager->registerHandler(function ($event) {
echo "\n[TEST HANDLER] Shutdown handler executed!\n";
echo " - Fatal Error: " . ($event->isFatalError() ? 'YES' : 'NO') . "\n";
echo " - Memory Usage: " . $event->memoryUsage->toHumanReadable() . "\n";
echo " - Peak Memory: " . $event->peakMemoryUsage->toHumanReadable() . "\n";
if ($event->isFatalError()) {
echo " - Error Type: " . $event->getErrorTypeName() . "\n";
echo " - Error Message: " . $event->getErrorMessage() . "\n";
echo " - Error File: " . $event->getErrorFile() . "\n";
echo " - Error Line: " . $event->getErrorLine() . "\n";
}
echo "[TEST HANDLER] Completed successfully\n\n";
}, priority: 100);
// Determine test type from CLI argument
$testType = $argv[1] ?? 'fatal';
echo "\n========================================\n";
echo "Shutdown Handling Test: " . strtoupper($testType) . "\n";
echo "========================================\n\n";
echo "Application bootstrapped successfully.\n";
echo "ShutdownHandlerManager registered.\n";
echo "Test handler added with priority 100.\n\n";
echo "Triggering test scenario in 2 seconds...\n";
sleep(2);
switch ($testType) {
case 'fatal':
echo "\n[TEST] Triggering E_ERROR via undefined function call...\n\n";
// This will trigger E_ERROR: Call to undefined function
undefinedFunction();
break;
case 'parse':
echo "\n[TEST] Triggering E_PARSE via eval syntax error...\n\n";
// This will trigger E_PARSE
eval('this is invalid php syntax');
break;
case 'memory':
echo "\n[TEST] Triggering memory exhaustion...\n\n";
ini_set('memory_limit', '10M');
$data = [];
while (true) {
// Allocate memory until exhaustion
$data[] = str_repeat('x', 1024 * 1024); // 1MB chunks
}
break;
case 'normal':
echo "\n[TEST] Normal shutdown (no error)...\n\n";
echo "Application will exit normally.\n";
echo "Shutdown handlers should still execute.\n\n";
// Normal exit
exit(0);
default:
echo "\nUnknown test type: {$testType}\n";
echo "Valid types: fatal, parse, memory, normal\n";
exit(1);
}
// This code should never be reached for fatal errors
echo "\n[UNEXPECTED] Code execution continued after fatal error!\n";
echo "This should NOT happen.\n\n";

View File

@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use App\Domain\SmartLink\Services\SmartLinkService;
use App\Domain\SmartLink\ValueObjects\{LinkType, LinkTitle, DestinationUrl, Platform};
use App\Framework\Core\AppBootstrapper;
echo "=== SmartLink Deletion Debug Test ===\n\n";
// Bootstrap application
$app = AppBootstrapper::bootstrap(__DIR__ . '/../..');
$container = $app->container;
// Get service
$service = $container->get(SmartLinkService::class);
try {
// Create link with destinations
echo "1. Creating SmartLink...\n";
$link = $service->createLink(
type: LinkType::RELEASE,
title: LinkTitle::fromString('Test Album')
);
echo " Created link: {$link->id->value}\n\n";
// Add destinations
echo "2. Adding destinations...\n";
$service->addDestination(
linkId: $link->id,
platform: Platform::SPOTIFY,
url: DestinationUrl::fromString('https://spotify.com/test')
);
$service->addDestination(
linkId: $link->id,
platform: Platform::APPLE_MUSIC,
url: DestinationUrl::fromString('https://apple.com/test')
);
echo " Added 2 destinations\n\n";
// Get destinations before deletion
echo "3. Getting destinations before deletion...\n";
$beforeDelete = $service->getDestinations($link->id);
echo " Found " . count($beforeDelete) . " destinations\n\n";
// Delete link
echo "4. Deleting link...\n";
$service->deleteLink($link->id);
echo " Link deleted\n\n";
// Try to find deleted link
echo "5. Trying to find deleted link (should throw exception)...\n";
try {
$deletedLink = $service->findById($link->id);
echo " ❌ ERROR: Link found when it should be deleted!\n";
} catch (\App\Domain\SmartLink\Exceptions\SmartLinkNotFoundException $e) {
echo " ✅ Correctly threw SmartLinkNotFoundException: {$e->getMessage()}\n";
} catch (\Throwable $e) {
echo " ❌ ERROR: Unexpected exception type: " . get_class($e) . "\n";
echo " Message: {$e->getMessage()}\n";
echo " Stack trace:\n";
echo $e->getTraceAsString() . "\n";
}
echo "\n✅ Test completed\n";
} catch (\Throwable $e) {
echo "❌ Test failed with exception:\n";
echo "Type: " . get_class($e) . "\n";
echo "Message: {$e->getMessage()}\n";
echo "File: {$e->getFile()}:{$e->getLine()}\n";
echo "\nStack trace:\n";
echo $e->getTraceAsString() . "\n";
exit(1);
}

View File

@@ -0,0 +1,25 @@
<?php
require __DIR__ . '/../../vendor/autoload.php';
use App\Framework\SyntaxHighlighter\FileHighlighter;
$highlighter = new FileHighlighter();
$html = $highlighter('/var/www/html/src/Domain/Media/ImageSlotRepository.php', 12, 5, 14);
// Find line 14 in the output
$lines = explode('<div class="line', $html);
foreach ($lines as $line) {
if (str_contains($line, 'Line 14')) {
echo "Found line 14:\n";
echo '<div class="line' . $line . "\n\n";
// Extract just the code part
preg_match('/<span class="code">(.*?)<\/span>/s', $line, $matches);
if (isset($matches[1])) {
echo "Code content:\n";
echo $matches[1] . "\n";
}
break;
}
}