- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
202 lines
6.5 KiB
PHP
202 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Framework\Http;
|
|
|
|
use App\Framework\Http\HttpMiddleware;
|
|
use App\Framework\Http\HttpResponse;
|
|
use App\Framework\Http\Method;
|
|
use App\Framework\Http\MiddlewareContext;
|
|
use App\Framework\Http\MiddlewareManager;
|
|
use App\Framework\Http\Next;
|
|
use App\Framework\Http\Request;
|
|
use App\Framework\Http\RequestStateManager;
|
|
use App\Framework\Http\Status;
|
|
|
|
test('middleware pipeline executes in order', function () {
|
|
$executionOrder = [];
|
|
|
|
$middleware1 = new class ($executionOrder) implements HttpMiddleware {
|
|
public function __construct(private array &$order)
|
|
{
|
|
}
|
|
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$this->order[] = 'before-1';
|
|
$context = $next($context);
|
|
$this->order[] = 'after-1';
|
|
|
|
return $context;
|
|
}
|
|
};
|
|
|
|
$middleware2 = new class ($executionOrder) implements HttpMiddleware {
|
|
public function __construct(private array &$order)
|
|
{
|
|
}
|
|
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$this->order[] = 'before-2';
|
|
$context = $next($context);
|
|
$this->order[] = 'after-2';
|
|
|
|
return $context;
|
|
}
|
|
};
|
|
|
|
$manager = new MiddlewareManager();
|
|
$manager->addMiddleware($middleware1, 100);
|
|
$manager->addMiddleware($middleware2, 50);
|
|
|
|
$request = new Request(Method::GET, '/test', [], '', []);
|
|
$stateManager = new RequestStateManager();
|
|
|
|
$finalHandler = function (MiddlewareContext $context) use (&$executionOrder) {
|
|
$executionOrder[] = 'handler';
|
|
|
|
return $context->withResponse(new HttpResponse(Status::OK));
|
|
};
|
|
|
|
$context = $manager->process(new MiddlewareContext($request), $finalHandler, $stateManager);
|
|
|
|
expect($executionOrder)->toBe([
|
|
'before-1',
|
|
'before-2',
|
|
'handler',
|
|
'after-2',
|
|
'after-1',
|
|
]);
|
|
});
|
|
|
|
test('middleware can short-circuit pipeline', function () {
|
|
$executed = [];
|
|
|
|
$middleware1 = new class ($executed) implements HttpMiddleware {
|
|
public function __construct(private array &$executed)
|
|
{
|
|
}
|
|
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$this->executed[] = 'middleware-1';
|
|
|
|
// Short-circuit by not calling next
|
|
return $context->withResponse(new HttpResponse(Status::FORBIDDEN));
|
|
}
|
|
};
|
|
|
|
$middleware2 = new class ($executed) implements HttpMiddleware {
|
|
public function __construct(private array &$executed)
|
|
{
|
|
}
|
|
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$this->executed[] = 'middleware-2';
|
|
|
|
return $next($context);
|
|
}
|
|
};
|
|
|
|
$manager = new MiddlewareManager();
|
|
$manager->addMiddleware($middleware1, 100);
|
|
$manager->addMiddleware($middleware2, 50);
|
|
|
|
$request = new Request(Method::GET, '/test', [], '', []);
|
|
$stateManager = new RequestStateManager();
|
|
|
|
$finalHandler = function (MiddlewareContext $context) use (&$executed) {
|
|
$executed[] = 'handler';
|
|
|
|
return $context->withResponse(new HttpResponse(Status::OK));
|
|
};
|
|
|
|
$context = $manager->process(new MiddlewareContext($request), $finalHandler, $stateManager);
|
|
|
|
expect($executed)->toBe(['middleware-1']);
|
|
expect($context->response?->status)->toBe(Status::FORBIDDEN);
|
|
});
|
|
|
|
test('middleware can modify request', function () {
|
|
$modifyMiddleware = new class () implements HttpMiddleware {
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$modifiedHeaders = $context->request->headers;
|
|
$modifiedHeaders['X-Custom-Header'] = 'test-value';
|
|
|
|
$modifiedRequest = new Request(
|
|
$context->request->method,
|
|
$context->request->path,
|
|
$modifiedHeaders,
|
|
$context->request->body,
|
|
$context->request->server
|
|
);
|
|
|
|
return $next($context->withRequest($modifiedRequest));
|
|
}
|
|
};
|
|
|
|
$manager = new MiddlewareManager();
|
|
$manager->addMiddleware($modifyMiddleware);
|
|
|
|
$request = new Request(Method::GET, '/test', [], '', []);
|
|
$stateManager = new RequestStateManager();
|
|
|
|
$receivedRequest = null;
|
|
$finalHandler = function (MiddlewareContext $context) use (&$receivedRequest) {
|
|
$receivedRequest = $context->request;
|
|
|
|
return $context->withResponse(new HttpResponse(Status::OK));
|
|
};
|
|
|
|
$manager->process(new MiddlewareContext($request), $finalHandler, $stateManager);
|
|
|
|
expect($receivedRequest?->headers['X-Custom-Header'] ?? null)->toBe('test-value');
|
|
});
|
|
|
|
test('middleware state management works', function () {
|
|
$stateManager = new RequestStateManager();
|
|
|
|
$middleware1 = new class () implements HttpMiddleware {
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
$stateManager->set('key1', 'value1');
|
|
$stateManager->set('shared', 'from-middleware-1');
|
|
|
|
return $next($context);
|
|
}
|
|
};
|
|
|
|
$middleware2 = new class () implements HttpMiddleware {
|
|
public function __invoke(MiddlewareContext $context, Next $next, RequestStateManager $stateManager): MiddlewareContext
|
|
{
|
|
expect($stateManager->get('key1'))->toBe('value1');
|
|
expect($stateManager->get('shared'))->toBe('from-middleware-1');
|
|
|
|
$stateManager->set('key2', 'value2');
|
|
$stateManager->set('shared', 'from-middleware-2');
|
|
|
|
return $next($context);
|
|
}
|
|
};
|
|
|
|
$manager = new MiddlewareManager();
|
|
$manager->addMiddleware($middleware1);
|
|
$manager->addMiddleware($middleware2);
|
|
|
|
$request = new Request(Method::GET, '/test', [], '', []);
|
|
|
|
$finalHandler = function (MiddlewareContext $context) use ($stateManager) {
|
|
expect($stateManager->get('key1'))->toBe('value1');
|
|
expect($stateManager->get('key2'))->toBe('value2');
|
|
expect($stateManager->get('shared'))->toBe('from-middleware-2');
|
|
|
|
return $context->withResponse(new HttpResponse(Status::OK));
|
|
};
|
|
|
|
$manager->process(new MiddlewareContext($request), $finalHandler, $stateManager);
|
|
});
|