Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
201
tests/Unit/Framework/Http/MiddlewarePipelineTest.php
Normal file
201
tests/Unit/Framework/Http/MiddlewarePipelineTest.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?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);
|
||||
});
|
||||
Reference in New Issue
Block a user