Refactor tests to shorten HTTP requests

Multiple tests now provide JSON request bodies, and others copy cookies
from previous responses, so let's provide convenient helpers for these.
This commit is contained in:
Franz Liedke 2019-06-12 22:57:38 +02:00
parent 7f7484e790
commit c126b95451
No known key found for this signature in database
GPG Key ID: 9A0231A879B055F4
2 changed files with 128 additions and 103 deletions

View File

@ -11,8 +11,13 @@
namespace Flarum\Tests\integration; namespace Flarum\Tests\integration;
use Dflydev\FigCookies\SetCookie;
use Flarum\Foundation\InstalledSite; use Flarum\Foundation\InstalledSite;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\CallbackStream;
use Zend\Diactoros\ServerRequest;
abstract class TestCase extends \PHPUnit\Framework\TestCase abstract class TestCase extends \PHPUnit\Framework\TestCase
{ {
@ -88,4 +93,69 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase
// And finally, turn on foreign key checks again. // And finally, turn on foreign key checks again.
$this->database()->getSchemaBuilder()->enableForeignKeyConstraints(); $this->database()->getSchemaBuilder()->enableForeignKeyConstraints();
} }
/**
* Send a full HTTP request through Flarum's middleware stack.
*/
protected function send(ServerRequestInterface $request): ResponseInterface
{
return $this->server->handle($request);
}
/**
* Build a HTTP request that can be passed through middleware.
*
* This method simplifies building HTTP request for use in our HTTP-level
* integration tests. It provides options for all features repeatedly being
* used in those tests.
*
* @param string $method
* @param string $path
* @param array $options
* An array of optional request properties.
* Currently supported:
* - "json" should point to a JSON-serializable object that will be
* serialized and used as request body. The corresponding Content-Type
* header will be set automatically.
* - "cookiesFrom" should hold a response object from a previous HTTP
* interaction. All cookies returned from the server in that response
* (via the "Set-Cookie" header) will be copied to the cookie params of
* the new request.
* @return ServerRequestInterface
*/
protected function request(string $method, string $path, array $options = []): ServerRequestInterface
{
$request = new ServerRequest([], [], $path, $method);
// Do we want a JSON request body?
if (isset($options['json'])) {
$request = $request
->withHeader('Content-Type', 'application/json')
->withBody(
new CallbackStream(function () use ($options) {
return json_encode($options['json']);
})
);
}
// Let's copy the cookies from a previous response
if (isset($options['cookiesFrom'])) {
/** @var ResponseInterface $previousResponse */
$previousResponse = $options['cookiesFrom'];
$cookies = array_reduce(
$previousResponse->getHeader('Set-Cookie'),
function ($memo, $setCookieString) {
$setCookie = SetCookie::fromSetCookieString($setCookieString);
$memo[$setCookie->getName()] = $setCookie->getValue();
return $memo;
},
[]
);
$request = $request->withCookieParams($cookies);
}
return $request;
}
} }

View File

@ -11,12 +11,9 @@
namespace Flarum\Tests\integration\api\csrf_protection; namespace Flarum\Tests\integration\api\csrf_protection;
use Dflydev\FigCookies\SetCookie;
use Flarum\Foundation\Application; use Flarum\Foundation\Application;
use Flarum\Tests\integration\RetrievesAuthorizedUsers; use Flarum\Tests\integration\RetrievesAuthorizedUsers;
use Flarum\Tests\integration\TestCase; use Flarum\Tests\integration\TestCase;
use Zend\Diactoros\CallbackStream;
use Zend\Diactoros\ServerRequest;
class RequireCsrfTokenTest extends TestCase class RequireCsrfTokenTest extends TestCase
{ {
@ -54,31 +51,23 @@ class RequireCsrfTokenTest extends TestCase
*/ */
public function error_when_doing_cookie_auth_without_csrf_token() public function error_when_doing_cookie_auth_without_csrf_token()
{ {
$auth = $this->server->handle( $auth = $this->send(
(new ServerRequest([], [], '/login', 'POST')) $this->request(
->withBody(new CallbackStream(function () { 'POST', '/login',
return '{"identification": "admin", "password": "password"}'; [
})) 'json' => ['identification' => 'admin', 'password' => 'password'],
->withHeader('Content-Type', 'application/json') ]
)
); );
$cookies = array_reduce( $response = $this->send(
$auth->getHeader('Set-Cookie'), $this->request(
function ($memo, $setCookieString) { 'POST', '/api/settings',
$setCookie = SetCookie::fromSetCookieString($setCookieString); [
$memo[$setCookie->getName()] = $setCookie->getValue(); 'cookiesFrom' => $auth,
return $memo; 'json' => ['mail_driver' => 'log'],
}, ]
[] )
);
$response = $this->server->handle(
(new ServerRequest([], [], '/api/settings', 'POST'))
->withBody(new CallbackStream(function () {
return '{"mail_driver": "log"}';
}))
->withCookieParams($cookies)
->withHeader('Content-Type', 'application/json')
); );
// Response should be "HTTP 400 Bad Request" // Response should be "HTTP 400 Bad Request"
@ -99,50 +88,32 @@ class RequireCsrfTokenTest extends TestCase
*/ */
public function cookie_auth_succeeds_with_csrf_token_in_header() public function cookie_auth_succeeds_with_csrf_token_in_header()
{ {
$initial = $this->server->handle( $initial = $this->send(
(new ServerRequest([], [], '/', 'GET')) $this->request('GET', '/')
); );
$token = $initial->getHeaderLine('X-CSRF-Token'); $token = $initial->getHeaderLine('X-CSRF-Token');
$cookies = array_reduce(
$initial->getHeader('Set-Cookie'),
function ($memo, $setCookieString) {
$setCookie = SetCookie::fromSetCookieString($setCookieString);
$memo[$setCookie->getName()] = $setCookie->getValue();
return $memo;
},
[]
);
$auth = $this->server->handle( $auth = $this->send(
(new ServerRequest([], [], '/login', 'POST')) $this->request(
->withBody(new CallbackStream(function () { 'POST', '/login',
return '{"identification": "admin", "password": "password"}'; [
})) 'cookiesFrom' => $initial,
->withCookieParams($cookies) 'json' => ['identification' => 'admin', 'password' => 'password'],
->withHeader('Content-Type', 'application/json') ]
->withHeader('X-CSRF-Token', $token) )->withHeader('X-CSRF-Token', $token)
); );
$token = $auth->getHeaderLine('X-CSRF-Token'); $token = $auth->getHeaderLine('X-CSRF-Token');
$cookies = array_reduce(
$auth->getHeader('Set-Cookie'),
function ($memo, $setCookieString) {
$setCookie = SetCookie::fromSetCookieString($setCookieString);
$memo[$setCookie->getName()] = $setCookie->getValue();
return $memo;
},
[]
);
$response = $this->server->handle( $response = $this->send(
(new ServerRequest([], [], '/api/settings', 'POST')) $this->request(
->withBody(new CallbackStream(function () { 'POST', '/api/settings',
return '{"mail_driver": "log"}'; [
})) 'cookiesFrom' => $auth,
->withCookieParams($cookies) 'json' => ['mail_driver' => 'log'],
->withHeader('Content-Type', 'application/json') ]
->withHeader('X-CSRF-Token', $token) )->withHeader('X-CSRF-Token', $token)
); );
// Successful response? // Successful response?
@ -160,48 +131,32 @@ class RequireCsrfTokenTest extends TestCase
*/ */
public function cookie_auth_succeeds_with_csrf_token_in_body() public function cookie_auth_succeeds_with_csrf_token_in_body()
{ {
$initial = $this->server->handle( $initial = $this->send(
(new ServerRequest([], [], '/', 'GET')) $this->request('GET', '/')
); );
$token = $initial->getHeaderLine('X-CSRF-Token'); $token = $initial->getHeaderLine('X-CSRF-Token');
$cookies = array_reduce(
$initial->getHeader('Set-Cookie'),
function ($memo, $setCookieString) {
$setCookie = SetCookie::fromSetCookieString($setCookieString);
$memo[$setCookie->getName()] = $setCookie->getValue();
return $memo;
},
[]
);
$auth = $this->server->handle( $auth = $this->send(
(new ServerRequest([], [], '/login', 'POST')) $this->request(
->withBody(new CallbackStream(function () use ($token) { 'POST', '/login',
return '{"identification": "admin", "password": "password", "csrfToken": "'.$token.'"}'; [
})) 'cookiesFrom' => $initial,
->withCookieParams($cookies) 'json' => ['identification' => 'admin', 'password' => 'password', 'csrfToken' => $token],
->withHeader('Content-Type', 'application/json') ]
)
); );
$token = $auth->getHeaderLine('X-CSRF-Token'); $token = $auth->getHeaderLine('X-CSRF-Token');
$cookies = array_reduce(
$auth->getHeader('Set-Cookie'),
function ($memo, $setCookieString) {
$setCookie = SetCookie::fromSetCookieString($setCookieString);
$memo[$setCookie->getName()] = $setCookie->getValue();
return $memo;
},
[]
);
$response = $this->server->handle( $response = $this->send(
(new ServerRequest([], [], '/api/settings', 'POST')) $this->request(
->withBody(new CallbackStream(function () use ($token) { 'POST', '/api/settings',
return '{"mail_driver": "log", "csrfToken": "'.$token.'"}'; [
})) 'cookiesFrom' => $auth,
->withCookieParams($cookies) 'json' => ['mail_driver' => 'log', 'csrfToken' => $token],
->withHeader('Content-Type', 'application/json') ]
)
); );
// Successful response? // Successful response?
@ -219,13 +174,13 @@ class RequireCsrfTokenTest extends TestCase
*/ */
public function master_api_token_does_not_need_csrf_token() public function master_api_token_does_not_need_csrf_token()
{ {
$response = $this->server->handle( $response = $this->send(
(new ServerRequest([], [], '/api/settings', 'POST')) $this->request(
->withBody(new CallbackStream(function () { 'POST', '/api/settings',
return '{"mail_driver": "log"}'; [
})) 'json' => ['mail_driver' => 'log'],
->withHeader('Authorization', 'Token superadmin') ]
->withHeader('Content-Type', 'application/json') )->withHeader('Authorization', 'Token superadmin')
); );
// Successful response? // Successful response?