Server responds with a default 404 response when request is unhandled
This commit is contained in:
parent
6f247bccfa
commit
f016b74c38
|
|
@ -37,13 +37,14 @@ class Server
|
||||||
* stored with the name. The value will be an array containing all of the
|
* stored with the name. The value will be an array containing all of the
|
||||||
* path variables.
|
* path variables.
|
||||||
*
|
*
|
||||||
* @param array $attributes key-value pairs to register as attributes
|
* @param array $attributes
|
||||||
* with the server request.
|
* Key-value pairs to register as attributes with the server request.
|
||||||
* @param DispatcherInterface $dispatcher Dispatches middleware. If no
|
* @param DispatcherInterface $dispatcher
|
||||||
* object is passed, the Server will create a
|
* Dispatches handlers and middleware. If no object is passed, the
|
||||||
* WellRESTed\Dispatching\Dispatcher
|
* Server will create a WellRESTed\Dispatching\Dispatcher.
|
||||||
* @param string|null $pathVariablesAttributeName Attribute name for
|
* @param string|null $pathVariablesAttributeName
|
||||||
* matched path variables. A null value sets attributes directly.
|
* Attribute name for matched path variables. A null value sets
|
||||||
|
* attributes directly.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
array $attributes = null,
|
array $attributes = null,
|
||||||
|
|
@ -66,7 +67,7 @@ class Server
|
||||||
* Push a new middleware onto the stack.
|
* Push a new middleware onto the stack.
|
||||||
*
|
*
|
||||||
* @param mixed $middleware Middleware to dispatch in sequence
|
* @param mixed $middleware Middleware to dispatch in sequence
|
||||||
* @return self
|
* @return static
|
||||||
*/
|
*/
|
||||||
public function add($middleware)
|
public function add($middleware)
|
||||||
{
|
{
|
||||||
|
|
@ -150,8 +151,8 @@ class Server
|
||||||
$transmitter = $this->getTransmitter();
|
$transmitter = $this->getTransmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
$next = function ($request, $response) {
|
$next = function () {
|
||||||
return $response;
|
return $this->getUnhandledResponse();
|
||||||
};
|
};
|
||||||
$response = $this->dispatch($request, $response, $next);
|
$response = $this->dispatch($request, $response, $next);
|
||||||
$transmitter->transmit($request, $response);
|
$transmitter->transmit($request, $response);
|
||||||
|
|
@ -196,8 +197,7 @@ class Server
|
||||||
/**
|
/**
|
||||||
* Return a "blank" response instance to populate.
|
* Return a "blank" response instance to populate.
|
||||||
*
|
*
|
||||||
* The response will be dispatched through the middleware and eventually
|
* The response will be dispatched through the middleware.
|
||||||
* output to the client.
|
|
||||||
*
|
*
|
||||||
* @return ResponseInterface
|
* @return ResponseInterface
|
||||||
*/
|
*/
|
||||||
|
|
@ -206,5 +206,16 @@ class Server
|
||||||
return new Response();
|
return new Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Response to indicate the server was unable to find any handlers
|
||||||
|
* that handled the request. By default, this is a 404 error.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface
|
||||||
|
*/
|
||||||
|
protected function getUnhandledResponse(): ResponseInterface
|
||||||
|
{
|
||||||
|
return new Response(404);
|
||||||
|
}
|
||||||
|
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,121 +3,108 @@
|
||||||
namespace WellRESTed\Test\Unit;
|
namespace WellRESTed\Test\Unit;
|
||||||
|
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use WellRESTed\Dispatching\DispatcherInterface;
|
||||||
use WellRESTed\Message\Response;
|
use WellRESTed\Message\Response;
|
||||||
use WellRESTed\Message\ServerRequest;
|
use WellRESTed\Message\ServerRequest;
|
||||||
use WellRESTed\Server;
|
use WellRESTed\Server;
|
||||||
use WellRESTed\Test\Doubles\NextMock;
|
|
||||||
use WellRESTed\Test\TestCase;
|
use WellRESTed\Test\TestCase;
|
||||||
|
use WellRESTed\Transmission\TransmitterInterface;
|
||||||
|
|
||||||
class ServerTest extends TestCase
|
class ServerTest extends TestCase
|
||||||
{
|
{
|
||||||
private $dispatcher;
|
|
||||||
private $next;
|
|
||||||
private $request;
|
|
||||||
private $response;
|
|
||||||
private $transmitter;
|
private $transmitter;
|
||||||
private $server;
|
private $server;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->request = new ServerRequest();
|
|
||||||
$this->response = new Response();
|
|
||||||
$this->next = new NextMock();
|
|
||||||
|
|
||||||
$this->transmitter = $this->prophesize('WellRESTed\Transmission\TransmitterInterface');
|
$this->transmitter = $this->prophesize(TransmitterInterface::class);
|
||||||
$this->transmitter->transmit(Argument::cetera())->willReturn();
|
$this->transmitter->transmit(Argument::cetera())->willReturn();
|
||||||
$this->dispatcher = $this->prophesize('WellRESTed\Dispatching\DispatcherInterface');
|
|
||||||
$this->dispatcher->dispatch(Argument::cetera())->will(
|
$this->server = new Server();
|
||||||
function ($args) {
|
}
|
||||||
list($middleware, $request, $response, $next) = $args;
|
|
||||||
return $next($request, $response);
|
private function respond()
|
||||||
}
|
{
|
||||||
|
$this->server->respond(
|
||||||
|
new ServerRequest(),
|
||||||
|
new Response(),
|
||||||
|
$this->transmitter->reveal()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->server = $this->getMockBuilder('WellRESTed\Server')
|
|
||||||
->setMethods(["getDefaultDispatcher", "getRequest", "getResponse", "getTransmitter"])
|
|
||||||
->disableOriginalConstructor()
|
|
||||||
->getMock();
|
|
||||||
$this->server->expects($this->any())
|
|
||||||
->method("getDefaultDispatcher")
|
|
||||||
->will($this->returnValue($this->dispatcher->reveal()));
|
|
||||||
$this->server->expects($this->any())
|
|
||||||
->method("getRequest")
|
|
||||||
->will($this->returnValue($this->request));
|
|
||||||
$this->server->expects($this->any())
|
|
||||||
->method("getResponse")
|
|
||||||
->will($this->returnValue($this->response));
|
|
||||||
$this->server->expects($this->any())
|
|
||||||
->method("getTransmitter")
|
|
||||||
->will($this->returnValue($this->transmitter->reveal()));
|
|
||||||
$this->server->__construct();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreatesInstances()
|
// ------------------------------------------------------------------------
|
||||||
{
|
|
||||||
$server = new Server();
|
|
||||||
$this->assertNotNull($server);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAddIsFluid()
|
|
||||||
{
|
|
||||||
$server = new Server();
|
|
||||||
$this->assertSame($server, $server->add("middleware"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testReturnsDispatcher()
|
public function testReturnsDispatcher()
|
||||||
{
|
{
|
||||||
$this->assertSame($this->dispatcher->reveal(), $this->server->getDispatcher());
|
$this->assertNotNull($this->server->getDispatcher());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDispatchesMiddlewareStack()
|
public function testDispatchesMiddlewareStack()
|
||||||
{
|
{
|
||||||
$this->server->add("first");
|
// This test will add a string to this array from each middleware.
|
||||||
$this->server->add("second");
|
|
||||||
$this->server->add("third");
|
|
||||||
|
|
||||||
$this->server->dispatch($this->request, $this->response, $this->next);
|
$steps = [];
|
||||||
|
|
||||||
$this->dispatcher->dispatch(
|
$this->server->add(
|
||||||
["first", "second", "third"],
|
function ($rqst, $resp, $next) use (&$steps) {
|
||||||
$this->request,
|
$steps[] = 'first';
|
||||||
$this->response,
|
return $next($rqst, $resp);
|
||||||
$this->next
|
}
|
||||||
)->shouldHaveBeenCalled();
|
);
|
||||||
|
|
||||||
|
$this->server->add(
|
||||||
|
function ($rqst, $resp, $next) use (&$steps) {
|
||||||
|
$steps[] = 'second';
|
||||||
|
return $next($rqst, $resp);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->server->add(
|
||||||
|
function ($rqst, $resp, $next) use (&$steps) {
|
||||||
|
$steps[] = 'third';
|
||||||
|
return $next($rqst, $resp);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->respond();
|
||||||
|
|
||||||
|
$this->assertEquals(['first', 'second', 'third'], $steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Respond
|
// Respond
|
||||||
|
|
||||||
public function testRespondDispatchesRequest()
|
public function testRespondSendsResponseToTransmitter()
|
||||||
{
|
{
|
||||||
$this->server->respond();
|
$expectedResponse = new Response(200);
|
||||||
$this->dispatcher->dispatch(
|
|
||||||
Argument::any(),
|
|
||||||
$this->request,
|
|
||||||
Argument::any(),
|
|
||||||
Argument::any()
|
|
||||||
)->shouldHaveBeenCalled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testRespondDispatchesResponse()
|
$this->server->add(
|
||||||
{
|
function ($rqst, $resp, $next) {
|
||||||
$this->server->respond();
|
return $next($rqst, $resp);
|
||||||
$this->dispatcher->dispatch(
|
}
|
||||||
Argument::any(),
|
);
|
||||||
Argument::any(),
|
|
||||||
$this->response,
|
$this->server->add(
|
||||||
Argument::any()
|
function ($rqst, $resp, $next) {
|
||||||
)->shouldHaveBeenCalled();
|
return $next($rqst, $resp);
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->server->add(
|
||||||
|
function () use ($expectedResponse) {
|
||||||
|
return $expectedResponse;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->respond();
|
||||||
|
|
||||||
public function testRespondSendsResponseToResponder()
|
|
||||||
{
|
|
||||||
$this->server->respond();
|
|
||||||
$this->transmitter->transmit(
|
$this->transmitter->transmit(
|
||||||
$this->request,
|
Argument::any(),
|
||||||
$this->response
|
$expectedResponse
|
||||||
)->shouldHaveBeenCalled();
|
)->shouldHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,20 +113,30 @@ class ServerTest extends TestCase
|
||||||
|
|
||||||
public function testCreatesRouterWithDispatcher()
|
public function testCreatesRouterWithDispatcher()
|
||||||
{
|
{
|
||||||
$this->request = $this->request
|
$dispatcher = $this->prophesize(DispatcherInterface::class);
|
||||||
|
$dispatcher->dispatch(Argument::cetera())->will(
|
||||||
|
function ($args) {
|
||||||
|
list($middleware, $request, $response, $next) = $args;
|
||||||
|
return $next($request, $response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$server = new Server(null, $dispatcher->reveal());
|
||||||
|
|
||||||
|
$request = (new ServerRequest())
|
||||||
->withMethod("GET")
|
->withMethod("GET")
|
||||||
->withRequestTarget("/");
|
->withRequestTarget("/");
|
||||||
|
$response = new Response();
|
||||||
|
$next = function ($rqst, $resp) {
|
||||||
|
return $resp;
|
||||||
|
};
|
||||||
|
|
||||||
$router = $this->server->createRouter();
|
$router = $server->createRouter();
|
||||||
$router->register("GET", "/", "middleware");
|
$router->register("GET", "/", "middleware");
|
||||||
$router($this->request, $this->response, $this->next);
|
$router($request, $response, $next);
|
||||||
|
|
||||||
$this->dispatcher->dispatch(
|
$dispatcher->dispatch(Argument::cetera())
|
||||||
"middleware",
|
->shouldHaveBeenCalled();
|
||||||
$this->request,
|
|
||||||
$this->response,
|
|
||||||
$this->next
|
|
||||||
)->shouldHaveBeenCalled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -148,21 +145,107 @@ class ServerTest extends TestCase
|
||||||
public function testAddsAttributesToRequest()
|
public function testAddsAttributesToRequest()
|
||||||
{
|
{
|
||||||
$attributes = [
|
$attributes = [
|
||||||
"name" => "value"
|
'name' => 'value'
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->server->__construct($attributes);
|
$server = new Server($attributes);
|
||||||
$this->server->respond();
|
|
||||||
|
|
||||||
$isRequestWithExpectedAttribute = function ($request) {
|
$spyMiddleware = function ($rqst, $resp) use (&$capturedRequest) {
|
||||||
return $request->getAttribute("name") === "value";
|
$capturedRequest = $rqst;
|
||||||
|
return $resp;
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->dispatcher->dispatch(
|
$server->add($spyMiddleware);
|
||||||
|
|
||||||
|
$server->respond(
|
||||||
|
new ServerRequest(),
|
||||||
|
new Response(),
|
||||||
|
$this->transmitter->reveal()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('value', $capturedRequest->getAttribute('name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// End of Stack
|
||||||
|
|
||||||
|
public function testRespondsWithDefaultHandlerWhenReachingEndOfStack()
|
||||||
|
{
|
||||||
|
$this->respond();
|
||||||
|
|
||||||
|
$has404StatusCode = function ($response) {
|
||||||
|
return $response->getStatusCode() === 404;
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->transmitter->transmit(
|
||||||
Argument::any(),
|
Argument::any(),
|
||||||
Argument::that($isRequestWithExpectedAttribute),
|
Argument::that($has404StatusCode)
|
||||||
Argument::any(),
|
|
||||||
Argument::any()
|
|
||||||
)->shouldHaveBeenCalled();
|
)->shouldHaveBeenCalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Defaults
|
||||||
|
|
||||||
|
public function testUsesDefaultRequestResponseAndTransmitter()
|
||||||
|
{
|
||||||
|
$request = new ServerRequest();
|
||||||
|
$response = new Response();
|
||||||
|
|
||||||
|
$server = new TestServer(
|
||||||
|
$request,
|
||||||
|
$response,
|
||||||
|
$this->transmitter->reveal()
|
||||||
|
);
|
||||||
|
$server->add(function ($rqst, $resp) {
|
||||||
|
return $resp;
|
||||||
|
});
|
||||||
|
$server->respond();
|
||||||
|
|
||||||
|
$this->transmitter->transmit($request, $response)
|
||||||
|
->shouldHaveBeenCalled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestServer extends Server
|
||||||
|
{
|
||||||
|
/** @var ServerRequestInterface */
|
||||||
|
private $request;
|
||||||
|
/** @var ResponseInterface */
|
||||||
|
private $response;
|
||||||
|
/** @var TransmitterInterface */
|
||||||
|
private $transmitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TestServer constructor.
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @param TransmitterInterface $transmitter
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
ResponseInterface $response,
|
||||||
|
TransmitterInterface $transmitter
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->request = $request;
|
||||||
|
$this->response = $response;
|
||||||
|
$this->transmitter = $transmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRequest()
|
||||||
|
{
|
||||||
|
return $this->request;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTransmitter()
|
||||||
|
{
|
||||||
|
return $this->transmitter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue