diff options
author | jenkins-bot <jenkins-bot@gerrit.wikimedia.org> | 2020-05-26 10:53:00 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@wikimedia.org> | 2020-05-26 10:53:00 +0000 |
commit | 9d1bd65aa27a234079fe4959fa13cb0daf5a22a5 (patch) | |
tree | 9762c2cef5869cfd9bd4dc261f5192462f5944c0 /tests/phpunit | |
parent | 4602f8db2dcc486ead043a9b882c9dc1ff35343f (diff) | |
parent | ad6879e6b64affc8f40121ec53c29fb4474e4adc (diff) | |
download | mediawikicore-9d1bd65aa27a234079fe4959fa13cb0daf5a22a5.tar.gz mediawikicore-9d1bd65aa27a234079fe4959fa13cb0daf5a22a5.zip |
Merge "REST Handler: add unit tests for base class"
Diffstat (limited to 'tests/phpunit')
-rw-r--r-- | tests/phpunit/unit/includes/Rest/Handler/HandlerTest.php | 235 | ||||
-rw-r--r-- | tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php | 47 |
2 files changed, 269 insertions, 13 deletions
diff --git a/tests/phpunit/unit/includes/Rest/Handler/HandlerTest.php b/tests/phpunit/unit/includes/Rest/Handler/HandlerTest.php new file mode 100644 index 000000000000..4847ef9209c4 --- /dev/null +++ b/tests/phpunit/unit/includes/Rest/Handler/HandlerTest.php @@ -0,0 +1,235 @@ +<?php + +namespace MediaWiki\Tests\Rest\Handler; + +use MediaWiki\Rest\ConditionalHeaderUtil; +use MediaWiki\Rest\Handler; +use MediaWiki\Rest\LocalizedHttpException; +use MediaWiki\Rest\RequestData; +use MediaWiki\Rest\ResponseFactory; +use MediaWiki\Rest\ResponseInterface; +use MediaWiki\Rest\Router; +use MediaWiki\Rest\Validator\BodyValidator; +use MediaWiki\Rest\Validator\Validator; +use PHPUnit\Framework\MockObject\MockObject; +use Wikimedia\ParamValidator\ParamValidator; +use Wikimedia\TestingAccessWrapper; + +/** + * @covers \MediaWiki\Rest\Handler\SearchHandler + */ +class HandlerTest extends \MediaWikiUnitTestCase { + + use HandlerTestTrait; + + /** + * @param string[] $methods + * + * @return Handler|MockObject + */ + private function newHandler( $methods = [] ) { + $methods = array_merge( $methods, [ 'execute' ] ); + /** @var Handler|MockObject $handler */ + $handler = $this->getMockBuilder( Handler::class ) + ->onlyMethods( $methods ) + ->getMock(); + $handler->method( 'execute' )->willReturn( (object)[] ); + + return $handler; + } + + public function testGetRouter() { + $handler = $this->newHandler(); + $this->initHandler( $handler, new RequestData() ); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertInstanceOf( Router::class, $handler->getRouter() ); + } + + public function testGetResponseFactory() { + $handler = $this->newHandler(); + $this->initHandler( $handler, new RequestData() ); + + $this->assertInstanceOf( ResponseFactory::class, $handler->getResponseFactory() ); + } + + public function testGetConditionalHeaderUtil() { + $handler = $this->newHandler(); + $this->initHandler( $handler, new RequestData() ); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertInstanceOf( ConditionalHeaderUtil::class, $handler->getConditionalHeaderUtil() ); + } + + public function provideCheckPreconditions() { + yield 'no status' => [ null ]; + yield 'a status' => [ 444 ]; + } + + /** + * @dataProvider provideCheckPreconditions + */ + public function testCheckPreconditions( $status ) { + $request = new RequestData(); + + $util = $this->createNoOpMock( ConditionalHeaderUtil::class, [ 'checkPreconditions' ] ); + $util->method( 'checkPreconditions' )->with( $request )->willReturn( $status ); + + $handler = $this->newHandler( [ 'getConditionalHeaderUtil' ] ); + $handler->method( 'getConditionalHeaderUtil' )->willReturn( $util ); + + $this->initHandler( $handler, $request ); + $resp = $handler->checkPreconditions(); + + $responseStatus = $resp ? $resp->getStatusCode() : null; + $this->assertSame( $status, $responseStatus ); + } + + public function testApplyConditionalResponseHeaders() { + $util = $this->createNoOpMock( ConditionalHeaderUtil::class, [ 'applyResponseHeaders' ] ); + $util->method( 'applyResponseHeaders' )->willReturnCallback( + function ( ResponseInterface $response ) { + $response->setHeader( 'Testing', 'foo' ); + } + ); + + $handler = $this->newHandler( [ 'getConditionalHeaderUtil' ] ); + $handler->method( 'getConditionalHeaderUtil' )->willReturn( $util ); + + $this->initHandler( $handler, new RequestData() ); + $response = $handler->getResponseFactory()->create(); + $handler->applyConditionalResponseHeaders( $response ); + + $this->assertSame( 'foo', $response->getHeaderLine( 'Testing' ) ); + } + + public function provideValidate() { + yield 'empty' => [ [], new RequestData(), [] ]; + + yield 'parameter' => [ + [ + 'foo' => [ + ParamValidator::PARAM_TYPE => 'string', + ParamValidator::PARAM_REQUIRED => true, + Handler::PARAM_SOURCE => 'query', + ] + ], + new RequestData( [ 'queryParams' => [ 'foo' => 'kittens' ] ] ), + [ 'foo' => 'kittens' ] + ]; + } + + /** + * @dataProvider provideValidate + */ + public function testValidate( $paramSettings, $request, $expected ) { + $handler = $this->newHandler( [ 'getParamSettings' ] ); + $handler->method( 'getParamSettings' )->willReturn( $paramSettings ); + + $this->initHandler( $handler, $request ); + $this->validateHandler( $handler ); + + $params = $handler->getValidatedParams(); + $this->assertSame( $expected, $params ); + } + + public function provideValidate_invalid() { + $paramSettings = [ + 'foo' => [ + ParamValidator::PARAM_TYPE => 'string', + ParamValidator::PARAM_REQUIRED => true, + Handler::PARAM_SOURCE => 'query', + ] + ]; + + $request = new RequestData( [ 'queryParams' => [ 'bar' => 'kittens' ] ] ); + + $handler = $this->newHandler( [ 'getParamSettings' ] ); + $handler->method( 'getParamSettings' )->willReturn( $paramSettings ); + + try { + $this->initHandler( $handler, $request ); + $this->validateHandler( $handler ); + $this->fail( 'Expected LocalizedHttpException' ); + } catch ( LocalizedHttpException $ex ) { + $this->assertSame( 'paramvalidator-missingparam', $ex->getMessageValue()->getKey() ); + } + } + + public function testGetValidatedBody() { + $validator = $this->createMock( Validator::class ); + $validator->method( 'validateBody' )->willReturn( 'VALIDATED BODY' ); + + $handler = $this->newHandler(); + $this->initHandler( $handler, new RequestData() ); + $handler->validate( $validator ); + + $body = $handler->getValidatedBody(); + $this->assertSame( 'VALIDATED BODY', $body ); + } + + public function testGetRequest() { + $handler = $this->newHandler(); + $request = new RequestData(); + $this->initHandler( $handler, $request ); + + $this->assertSame( $request, $handler->getRequest() ); + } + + public function testGetConfig() { + $handler = $this->newHandler(); + $config = [ 'foo' => 'bar' ]; + $this->initHandler( $handler, new RequestData(), $config ); + + $this->assertSame( $config, $handler->getConfig() ); + } + + public function testGetBodyValidator() { + $handler = $this->newHandler(); + $this->assertInstanceOf( + BodyValidator::class, + $handler->getBodyValidator( 'unknown/unknown' ) + ); + } + + public function testThatGetParamSettingsReturnsNothingPerDefault() { + $handler = $this->newHandler(); + $this->assertSame( [], $handler->getParamSettings() ); + } + + public function testThatGetLastModifiedReturnsNullPerDefault() { + $handler = $this->newHandler(); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertNull( $handler->getLastModified() ); + } + + public function testThatGetETagReturnsNullPerDefault() { + $handler = $this->newHandler(); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertNull( $handler->getETag() ); + } + + public function testThatHasRepresentationReturnsNullPerDefault() { + $handler = $this->newHandler(); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertNull( $handler->hasRepresentation() ); + } + + public function testThatNeedsReadAccessReturnsTruePerDefault() { + $handler = $this->newHandler(); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertTrue( $handler->needsReadAccess() ); + } + + public function testThatNeedsWriteAccessReturnsTruePerDefault() { + $handler = $this->newHandler(); + + $handler = TestingAccessWrapper::newFromObject( $handler ); + $this->assertTrue( $handler->needsWriteAccess() ); + } + +} diff --git a/tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php b/tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php index 16ad9411cd82..46d288f3afd4 100644 --- a/tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php +++ b/tests/phpunit/unit/includes/Rest/Handler/HandlerTestTrait.php @@ -52,15 +52,13 @@ trait HandlerTestTrait { abstract protected function createMock( $originalClassName ): MockObject; /** - * Executes the given Handler on the given request. + * Calls init() on the Handler, supplying a mock Router and ResponseFactory. * * @param Handler $handler * @param RequestInterface $request * @param array $config - * - * @return ResponseInterface */ - private function executeHandler( Handler $handler, RequestInterface $request, $config = [] ) { + private function initHandler( Handler $handler, RequestInterface $request, $config = [] ) { $formatter = $this->createMock( ITextFormatter::class ); $formatter->method( 'format' )->willReturnCallback( function ( MessageValue $msg ) { return $msg->dump(); @@ -69,6 +67,21 @@ trait HandlerTestTrait { /** @var ResponseFactory|MockObject $responseFactory */ $responseFactory = new ResponseFactory( [ 'qqx' => $formatter ] ); + /** @var Router|MockObject $router */ + $router = $this->createNoOpMock( Router::class, [ 'getRouteUrl' ] ); + $router->method( 'getRouteUrl' )->willReturnCallback( function ( $route, $query = [] ) { + return wfAppendQuery( 'https://wiki.example.com/rest' . $route, $query ); + } ); + + $handler->init( $router, $request, $config, $responseFactory ); + } + + /** + * Calls validate() on the Handler, with an appropriate Validator supplied. + * + * @param Handler $handler + */ + private function validateHandler( Handler $handler ) { /** @var PermissionManager|MockObject $permissionManager */ $permissionManager = $this->createNoOpMock( PermissionManager::class, [ 'userCan', 'userHasRight' ] @@ -81,16 +94,24 @@ trait HandlerTestTrait { $objectFactory = new ObjectFactory( $serviceContainer ); $user = new UserIdentityValue( 0, 'Fake User', 0 ); - $validator = new Validator( $objectFactory, $permissionManager, $request, $user ); - - /** @var Router|MockObject $router */ - $router = $this->createNoOpMock( Router::class, [ 'getRouteUrl' ] ); - $router->method( 'getRouteUrl' )->willReturnCallback( function ( $route, $query = [] ) { - return wfAppendQuery( 'https://wiki.example.com/rest' . $route, $query ); - } ); + $validator = + new Validator( $objectFactory, $permissionManager, $handler->getRequest(), $user ); - $handler->init( $router, $request, $config, $responseFactory ); $handler->validate( $validator ); + } + + /** + * Executes the given Handler on the given request. + * + * @param Handler $handler + * @param RequestInterface $request + * @param array $config + * + * @return ResponseInterface + */ + private function executeHandler( Handler $handler, RequestInterface $request, $config = [] ) { + $this->initHandler( $handler, $request, $config ); + $this->validateHandler( $handler ); // Check conditional request headers $earlyResponse = $handler->checkPreconditions(); @@ -101,7 +122,7 @@ trait HandlerTestTrait { $ret = $handler->execute(); $response = $ret instanceof Response ? $ret - : $responseFactory->createFromReturnValue( $ret ); + : $handler->getResponseFactory()->createFromReturnValue( $ret ); // Set Last-Modified and ETag headers in the response if available $handler->applyConditionalResponseHeaders( $response ); |