aboutsummaryrefslogtreecommitdiffstats
path: root/tests/phpunit/structure/RestStructureTest.php
diff options
context:
space:
mode:
authordaniel <dkinzler@wikimedia.org>2023-10-30 17:04:41 +0100
committerdaniel <dkinzler@wikimedia.org>2024-05-08 16:12:30 +0200
commit91a1741787aed472abe9cb24eaacd40a76f9f894 (patch)
treeae8ed939c55fbb0f284e2eba1760fe8b3f72ad05 /tests/phpunit/structure/RestStructureTest.php
parent4d4d2a15a9d3901fcad7db840026feafedfd9ba9 (diff)
downloadmediawikicore-91a1741787aed472abe9cb24eaacd40a76f9f894.tar.gz
mediawikicore-91a1741787aed472abe9cb24eaacd40a76f9f894.zip
Introduce Modules into the REST framework
Modules group together endpoints by a shared prefix. The idea is that each module has its own version and can generated self-contained self-documentation. This allows clients to have clear expectations about the endpoints of each module, no matter what wiki they are accessing. So far, each wiki may be exposing a different set of endpoints, with no way to provide a spec that describes that set of endpoints in a way that would be consistent across wikis and stable over time. Bug: T362480 Change-Id: Iebcde4645d472d27eee5a30adb6eee12cc7d046b
Diffstat (limited to 'tests/phpunit/structure/RestStructureTest.php')
-rw-r--r--tests/phpunit/structure/RestStructureTest.php113
1 files changed, 68 insertions, 45 deletions
diff --git a/tests/phpunit/structure/RestStructureTest.php b/tests/phpunit/structure/RestStructureTest.php
index c3d617d55311..0196969a86b5 100644
--- a/tests/phpunit/structure/RestStructureTest.php
+++ b/tests/phpunit/structure/RestStructureTest.php
@@ -72,11 +72,7 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
return $services;
}
- /**
- * Return all routes. Safe to use in data providers.
- * @return Iterator<array>
- */
- private function getAllRoutes(): Iterator {
+ private function getRouterForDataProviders(): Router {
static $router = null;
if ( !$router ) {
@@ -86,13 +82,8 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
$title = Title::makeTitle( NS_SPECIAL, 'Badtitle/dummy title for RestStructureTest' );
$authority = new SimpleAuthority( new UserIdentityValue( 0, 'Testor' ), [] );
- $request = $this->createNoOpMock(
- WebRequest::class,
- [ 'getSession' ]
- );
- $request->method( 'getSession' )->willReturn(
- $this->createNoOpMock( Session::class )
- );
+ $request = $this->createNoOpMock( WebRequest::class, [ 'getSession' ] );
+ $request->method( 'getSession' )->willReturn( $this->createNoOpMock( Session::class ) );
$context = $this->createNoOpMock(
RequestContext::class,
@@ -109,11 +100,17 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
$services = $this->getFakeServiceContainer();
// NOTE: createRouter() implements the logic for determining the list of route files to load.
- $router = EntryPoint::createRouter( $services, $context, new RequestData(), $responseFactory, $cors );
- $router = TestingAccessWrapper::newFromObject( $router );
+ $entryPoint = TestingAccessWrapper::newFromClass( EntryPoint::class );
+ $router = $entryPoint->createRouter(
+ $services,
+ $context,
+ new RequestData(),
+ $responseFactory,
+ $cors
+ );
}
- return $router->getAllRoutes();
+ return $router;
}
/**
@@ -121,7 +118,7 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
* @warning Must not be called in data providers!
* @return Router
*/
- private function getRouter(): Router {
+ private function getTestRouter(): Router {
if ( !$this->router ) {
$context = new DerivativeContext( RequestContext::getMain() );
$context->setLanguage( 'en' );
@@ -142,18 +139,20 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
/**
* @dataProvider provideRoutes
*/
- public function testPathParameters( array $spec ): void {
- $router = TestingAccessWrapper::newFromObject( $this->getRouter() );
- $request = new RequestData();
- $handler = $router->createHandler( $request, $spec );
- $params = $handler->getParamSettings();
+ public function testPathParameters( string $moduleName, string $method, string $path ): void {
+ $router = $this->getTestRouter();
+ $module = $router->getModule( $moduleName );
+
+ $request = new RequestData( [ 'method' => $method ] );
+ $handler = $module->getHandlerForPath( $path, $request, false );
+ $params = $handler->getParamSettings();
$dataName = $this->dataName();
// Test that all parameters in the path exist and are declared as such
$matcher = TestingAccessWrapper::newFromObject( new PathMatcher );
$pathParams = [];
- foreach ( explode( '/', $spec['path'] ) as $part ) {
+ foreach ( explode( '/', $path ) as $part ) {
$param = $matcher->getParamName( $part );
if ( $param !== false ) {
$this->assertArrayHasKey( $param, $params, "Path parameter $param exists" );
@@ -182,10 +181,12 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
/**
* @dataProvider provideRoutes
*/
- public function testBodyParameters( array $spec ): void {
- $router = TestingAccessWrapper::newFromObject( $this->getRouter() );
- $request = new RequestData();
- $handler = $router->createHandler( $request, $spec );
+ public function testBodyParameters( string $moduleName, string $method, string $path ): void {
+ $router = $this->getTestRouter();
+ $module = $router->getModule( $moduleName );
+
+ $request = new RequestData( [ 'method' => $method ] );
+ $handler = $module->getHandlerForPath( $path, $request, false );
$paramSettings = $handler->getParamSettings();
$bodySettings = $handler->getBodyParamSettings();
@@ -219,35 +220,53 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
}
}
+ public function provideModules(): Iterator {
+ $router = $this->getRouterForDataProviders();
+
+ foreach ( $router->getModuleNames() as $name ) {
+ yield "Module '$name'" => [ $name ];
+ }
+ }
+
public function provideRoutes(): Iterator {
- foreach ( $this->getAllRoutes() as $spec ) {
- $method = $spec['method'] ?? 'GET';
- $method = implode( ",", (array)$method );
+ $router = $this->getRouterForDataProviders();
+
+ foreach ( $router->getModuleNames() as $moduleName ) {
+ $module = $router->getModule( $moduleName );
- yield "Handler {$method} {$spec['path']}" => [ $spec ];
+ foreach ( $module->getDefinedPaths() as $path => $methods ) {
+
+ foreach ( $methods as $method ) {
+ // NOTE: we can't use the $module object directly, since it
+ // may hold references to incorrect service instance.
+ yield "Handler in module '$moduleName' for $method $path"
+ => [ $moduleName, $method, $path ];
+ }
+ }
}
}
/**
* @dataProvider provideRoutes
*/
- public function testParameters( array $routeSpec ): void {
- $router = TestingAccessWrapper::newFromObject( $this->getRouter() );
+ public function testParameters( string $moduleName, string $method, string $path ): void {
+ $router = $this->getTestRouter();
+ $module = $router->getModule( $moduleName );
- $request = new RequestData();
- $handler = $router->createHandler( $request, $routeSpec );
+ $request = new RequestData( [ 'method' => $method ] );
+ $handler = $module->getHandlerForPath( $path, $request, false );
$params = $handler->getParamSettings();
foreach ( $params as $param => $settings ) {
$method = $routeSpec['method'] ?? 'GET';
$method = implode( ",", (array)$method );
- $this->assertParameter( $param, $settings, "Handler {$method} {$routeSpec['path']}, parameter $param" );
+ $this->assertParameter( $param, $settings, "Handler {$method} {$path}, parameter $param" );
}
}
private function assertParameter( string $name, $settings, $msg ) {
- $router = TestingAccessWrapper::newFromObject( $this->getRouter() );
+ $router = TestingAccessWrapper::newFromObject( $this->getTestRouter() );
$dataName = $this->dataName();
$this->assertNotSame( '', $name, "$msg: $dataName: Name cannot be empty" );
@@ -295,20 +314,24 @@ class RestStructureTest extends MediaWikiIntegrationTestCase {
}
public function testRoutePathAndMethodForDuplicates() {
- $router = TestingAccessWrapper::newFromObject( $this->getRouter() );
+ $router = $this->getTestRouter();
$routes = [];
- foreach ( $router->getAllRoutes() as $spec ) {
- $method = $spec['method'] ?? 'GET';
- $method = (array)$method;
+ foreach ( $router->getModuleNames() as $moduleName ) {
+ $module = $router->getModule( $moduleName );
+ $paths = $module->getDefinedPaths();
- foreach ( $method as $m ) {
- $key = "{$m} {$spec['path']}";
+ foreach ( $paths as $path => $methods ) {
+ foreach ( $methods as $method ) {
+ // NOTE: we can't use the $module object directly, since it
+ // may hold references to incorrect service instance.
+ $key = "$moduleName: $method $path";
- $this->assertArrayNotHasKey( $key, $routes, "{$key} already exists in routes" );
-
- $routes[$key] = true;
+ $this->assertArrayNotHasKey( $key, $routes, "{$key} already exists in routes" );
+ $routes[$key] = true;
+ }
}
}
}
+
}