Files
michaelschiemer/tests/Framework/Core/DynamicRoutingTest.php
Michael Schiemer 36ef2a1e2c
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled
fix: Gitea Traefik routing and connection pool optimization
- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
2025-11-09 14:46:15 +01:00

335 lines
12 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Attributes\Route;
use App\Framework\Core\DynamicRoute;
use App\Framework\Core\RouteCompiler;
use App\Framework\Discovery\Visitors\UnifiedRouteVisitor;
use App\Framework\Router\Result\FileResult;
use App\Framework\Router\Result\JsonResult;
// Test Controller Klassen für Dynamic Routing Tests
class TestDynamicController
{
#[Route('/test/{id}')]
public function showById(int $id): JsonResult
{
return new JsonResult(['id' => $id]);
}
#[Route('/images/{filename}')]
public function showImage(string $filename): FileResult
{
return new FileResult("/path/to/{$filename}");
}
#[Route('/user/{userId}/post/{postId}')]
public function showUserPost(int $userId, string $postId): JsonResult
{
return new JsonResult(['userId' => $userId, 'postId' => $postId]);
}
#[Route('/api/search/{query?}')]
public function search(?string $query = null): JsonResult
{
return new JsonResult(['query' => $query]);
}
}
describe('Dynamic Routing Parameter Extraction', function () {
beforeEach(function () {
$this->discoveryVisitor = new UnifiedRouteVisitor();
$this->routeCompiler = new RouteCompiler();
});
test('discovers routes with dynamic parameters', function () {
$this->discoveryVisitor->onScanStart();
// UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$this->discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $this->discoveryVisitor->getResults();
expect($routes)->toHaveCount(4);
// Test route with single parameter
$singleParamRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/test/{id}') {
$singleParamRoute = $route;
break;
}
}
expect($singleParamRoute)->not->toBeNull();
expect($singleParamRoute['controller'])->toBe(TestDynamicController::class);
expect($singleParamRoute['action'])->toBe('showById');
// Test image route (the problematic one)
$imageRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/images/{filename}') {
$imageRoute = $route;
break;
}
}
expect($imageRoute)->not->toBeNull();
expect($imageRoute['controller'])->toBe(TestDynamicController::class);
expect($imageRoute['action'])->toBe('showImage');
// Test route with multiple parameters
$multiParamRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/user/{userId}/post/{postId}') {
$multiParamRoute = $route;
break;
}
}
expect($multiParamRoute)->not->toBeNull();
});
test('extracts parameter information correctly', function () {
$this->discoveryVisitor->onScanStart();
// UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$this->discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $this->discoveryVisitor->getResults();
// Suche die Image Route
$imageRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/images/{filename}') {
$imageRoute = $route;
break;
}
}
// Prüfe ob Parameter-Informationen vorhanden sind
if (isset($imageRoute['parameters'])) {
expect($imageRoute['parameters'])->toBeArray();
// Debug: Zeige Parameter-Struktur
error_log('Image Route Parameters: ' . json_encode($imageRoute['parameters']));
// Suche nach filename Parameter
$filenameParam = null;
foreach ($imageRoute['parameters'] as $param) {
if ($param['name'] === 'filename') {
$filenameParam = $param;
break;
}
}
if ($filenameParam) {
expect($filenameParam['name'])->toBe('filename');
expect($filenameParam['type'])->toBe('string'); // Das ist wahrscheinlich null!
expect($filenameParam['isBuiltin'])->toBeTrue();
} else {
error_log('Filename parameter not found in parameters array');
}
} else {
error_log('No parameters found in route array');
expect($imageRoute)->toHaveKey('parameters'); // Dieser Test wird wahrscheinlich fehlschlagen
}
});
test('compiles dynamic routes with parameter names', function () {
$this->discoveryVisitor->onScanStart();
// UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$this->discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $this->discoveryVisitor->getResults();
$compiledRoutes = $this->routeCompiler->compile($routes);
// Prüfe GET routes
expect($compiledRoutes)->toHaveKey('GET');
expect($compiledRoutes['GET'])->toHaveKey('dynamic');
$dynamicRoutes = $compiledRoutes['GET']['dynamic'];
expect($dynamicRoutes)->toBeArray();
expect(count($dynamicRoutes))->toBeGreaterThan(0);
// Suche Image Route in compilierten Routes
$imageRoute = null;
foreach ($dynamicRoutes as $route) {
if ($route instanceof DynamicRoute && $route->path === '/images/{filename}') {
$imageRoute = $route;
break;
}
}
expect($imageRoute)->not->toBeNull();
expect($imageRoute)->toBeInstanceOf(DynamicRoute::class);
// Prüfe Parameter Names
expect($imageRoute->paramNames)->toBe(['filename']);
// Prüfe compiled regex
expect($imageRoute->regex)->toBeString();
expect($imageRoute->regex)->toMatch('/^~.*\/images\/.*\$~/'); // Regex für /images/{filename}
// Prüfe Parameter Details
error_log('Compiled Image Route Parameters: ' . json_encode($imageRoute->parameters));
if (! empty($imageRoute->parameters)) {
$filenameParam = null;
foreach ($imageRoute->parameters as $param) {
if ($param['name'] === 'filename') {
$filenameParam = $param;
break;
}
}
if ($filenameParam) {
expect($filenameParam['type'])->not->toBeNull(); // Das sollte nicht null sein!
expect($filenameParam['type'])->toBe('string');
}
}
});
test('handles multiple parameter types correctly', function () {
$this->discoveryVisitor->onScanStart();
// UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$this->discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $this->discoveryVisitor->getResults();
// Test verschiedene Parameter-Typen
$userPostRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/user/{userId}/post/{postId}') {
$userPostRoute = $route;
break;
}
}
if (isset($userPostRoute['parameters'])) {
$parameters = $userPostRoute['parameters'];
// Suche nach userId (int) und postId (string) Parametern
$userIdParam = null;
$postIdParam = null;
foreach ($parameters as $param) {
if ($param['name'] === 'userId') {
$userIdParam = $param;
} elseif ($param['name'] === 'postId') {
$postIdParam = $param;
}
}
if ($userIdParam) {
expect($userIdParam['type'])->toBe('int');
expect($userIdParam['isBuiltin'])->toBeTrue();
}
if ($postIdParam) {
expect($postIdParam['type'])->toBe('string');
expect($postIdParam['isBuiltin'])->toBeTrue();
}
}
});
test('handles optional parameters correctly', function () {
$this->discoveryVisitor->onScanStart();
// UnifiedRouteVisitor benötigt ClassName und FilePath Value Objects
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$this->discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $this->discoveryVisitor->getResults();
// Test optionale Parameter
$searchRoute = null;
foreach ($routes as $route) {
if ($route['path'] === '/api/search/{query?}') {
$searchRoute = $route;
break;
}
}
if (isset($searchRoute['parameters'])) {
$parameters = $searchRoute['parameters'];
$queryParam = null;
foreach ($parameters as $param) {
if ($param['name'] === 'query') {
$queryParam = $param;
break;
}
}
if ($queryParam) {
expect($queryParam['type'])->toBe('string');
expect($queryParam['isOptional'])->toBeTrue();
expect($queryParam['hasDefault'])->toBeTrue();
expect($queryParam['default'])->toBeNull();
}
}
});
});
describe('Dynamic Route Parameter Processing Debug', function () {
test('shows current parameter extraction workflow', function () {
$discoveryVisitor = new UnifiedRouteVisitor();
$discoveryVisitor->onScanStart();
$className = \App\Framework\Core\ValueObjects\ClassName::fromString(TestDynamicController::class);
$filePath = \App\Framework\Filesystem\FilePath::create('test-file.php');
$reflection = new \App\Framework\ReflectionLegacy\WrappedReflectionClass(new \ReflectionClass(TestDynamicController::class));
$discoveryVisitor->visitClass($className, $filePath, $reflection);
$routes = $discoveryVisitor->getResults();
// Debug: Zeige alle gefundenen Routes
error_log('=== All discovered routes ===');
foreach ($routes as $i => $route) {
error_log("Route {$i}: " . json_encode([
'path' => $route['path'],
'controller' => $route['controller'],
'action' => $route['action'],
'has_parameters' => isset($route['parameters']),
'parameter_count' => isset($route['parameters']) ? count($route['parameters']) : 0,
]));
if (isset($route['parameters'])) {
foreach ($route['parameters'] as $j => $param) {
error_log(" Parameter {$j}: " . json_encode($param));
}
}
}
// Debug: Zeige RouteDiscoveryVisitor interne Struktur
error_log('=== RouteDiscoveryVisitor internals ===');
// Wir können nicht auf private Properties zugreifen, aber wir können testen
expect(true)->toBeTrue(); // Placeholder - der Test ist für Debug-Zwecke
});
});