Since I72c5e6f86b7f081ab5ce7a56f5365d2f75067a78 it is part of the contract of ContentRenderer::getParserOutput() that the render ID (and other cache parameters) will be set when it returns. (ContentHandler::getParserOutput() can set them even earlier if it has custom content-based overrides.) We had a lot of temporary backward-compatibility code "later" in the parse process to try to close the barn door if some code path "forgot" to set them, but these are unnecessary now. This patch removes that backward-compatibility code in ParsoidParser; there is similar remaining code in ParserCache etc. which can be addressed in follow ups. (For compatibility we do have to temporarily copy the render ID code inside ParsoidOutputAccess::parseUncachable, but that class is deprecated and will be removed.) The HtmlOutputRendererHelper path which used to call ParsoidParser::parseFakeRevision() is now replaced with a codepath that goes through RevisionRenderer. In order to maintain the same behavior of the ParsoidHandler, we have also added 'useParsoid' handling to the JsonContentHandler. This support can perhaps be deprecated eventually. Bug: T350538 Change-Id: I0853624cf785f72fd956c6c2336f979f4402a68f
246 lines
7.5 KiB
PHP
246 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Tests\Rest\Handler;
|
|
|
|
use File;
|
|
use FileRepo;
|
|
use MediaWiki\Config\ServiceOptions;
|
|
use MediaWiki\MainConfigNames;
|
|
use MediaWiki\MainConfigSchema;
|
|
use MediaWiki\Parser\Parsoid\ParsoidParser;
|
|
use MediaWiki\Parser\Parsoid\ParsoidParserFactory;
|
|
use MediaWiki\Rest\Handler\Helper\HtmlMessageOutputHelper;
|
|
use MediaWiki\Rest\Handler\Helper\HtmlOutputRendererHelper;
|
|
use MediaWiki\Rest\Handler\Helper\PageContentHelper;
|
|
use MediaWiki\Rest\Handler\Helper\PageRedirectHelper;
|
|
use MediaWiki\Rest\Handler\Helper\PageRestHelperFactory;
|
|
use MediaWiki\Rest\Handler\LanguageLinksHandler;
|
|
use MediaWiki\Rest\Handler\PageHistoryCountHandler;
|
|
use MediaWiki\Rest\Handler\PageHistoryHandler;
|
|
use MediaWiki\Rest\Handler\PageHTMLHandler;
|
|
use MediaWiki\Rest\Handler\PageSourceHandler;
|
|
use MediaWiki\Rest\RequestData;
|
|
use MediaWiki\Rest\RequestInterface;
|
|
use MediaWiki\Rest\ResponseFactory;
|
|
use MediaWiki\Rest\Router;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use RepoGroup;
|
|
use WANObjectCache;
|
|
use Wikimedia\Parsoid\Parsoid;
|
|
|
|
/**
|
|
* A trait providing utility functions for testing Page Handler classes.
|
|
* This trait is intended to be used on subclasses of MediaWikiUnitTestCase
|
|
* or MediaWikiIntegrationTestCase.
|
|
*
|
|
* @stable to use
|
|
*/
|
|
trait PageHandlerTestTrait {
|
|
|
|
private function newRouterForPageHandler( $baseUrl, $rootPath = '' ): Router {
|
|
$router = $this->createNoOpMock( Router::class, [ 'getRoutePath', 'getRouteUrl' ] );
|
|
$router->method( 'getRoutePath' )
|
|
->willReturnCallback( static function (
|
|
string $route,
|
|
array $pathParams = [],
|
|
array $queryParams = []
|
|
) use ( $rootPath ) {
|
|
foreach ( $pathParams as $param => $value ) {
|
|
// NOTE: we use rawurlencode here, since execute() uses rawurldecode().
|
|
// Spaces in path params must be encoded to %20 (not +).
|
|
// Slashes must be encoded as %2F.
|
|
$route = str_replace( '{' . $param . '}', rawurlencode( (string)$value ), $route );
|
|
}
|
|
|
|
$url = $rootPath . $route;
|
|
return wfAppendQuery( $url, $queryParams );
|
|
} );
|
|
$router->method( 'getRouteUrl' )
|
|
->willReturnCallback( static function (
|
|
string $route,
|
|
array $pathParams = [],
|
|
array $queryParams = []
|
|
) use ( $baseUrl, $router ) {
|
|
return $baseUrl . $router->getRoutePath( $route, $pathParams, $queryParams );
|
|
} );
|
|
|
|
return $router;
|
|
}
|
|
|
|
/**
|
|
* @param Parsoid|MockObject $mockParsoid
|
|
*/
|
|
public function resetServicesWithMockedParsoid( $mockParsoid ): void {
|
|
$services = $this->getServiceContainer();
|
|
$parsoidParser = new ParsoidParser(
|
|
$mockParsoid,
|
|
$services->getParsoidPageConfigFactory(),
|
|
$services->getLanguageConverterFactory(),
|
|
$services->getParserFactory(),
|
|
$services->getGlobalIdGenerator()
|
|
);
|
|
|
|
// Create a mock Parsoid factory that returns the ParsoidParser object
|
|
// with the mocked Parsoid object.
|
|
$mockParsoidParserFactory = $this->createNoOpMock( ParsoidParserFactory::class, [ 'create' ] );
|
|
$mockParsoidParserFactory->method( 'create' )->willReturn( $parsoidParser );
|
|
|
|
$this->setService( 'ParsoidParserFactory', $mockParsoidParserFactory );
|
|
}
|
|
|
|
/**
|
|
* @return PageHTMLHandler
|
|
*/
|
|
public function newPageHtmlHandler( ?RequestInterface $request = null ) {
|
|
$services = $this->getServiceContainer();
|
|
$config = [
|
|
MainConfigNames::RightsUrl => 'https://example.com/rights',
|
|
MainConfigNames::RightsText => 'some rights',
|
|
MainConfigNames::ParsoidCacheConfig =>
|
|
MainConfigSchema::getDefaultValue( MainConfigNames::ParsoidCacheConfig )
|
|
];
|
|
|
|
$helperFactory = $this->createNoOpMock(
|
|
PageRestHelperFactory::class,
|
|
[ 'newPageContentHelper', 'newHtmlOutputRendererHelper', 'newHtmlMessageOutputHelper', 'newPageRedirectHelper' ]
|
|
);
|
|
|
|
$helperFactory->method( 'newPageContentHelper' )
|
|
->willReturn( new PageContentHelper(
|
|
new ServiceOptions( PageContentHelper::CONSTRUCTOR_OPTIONS, $config ),
|
|
$services->getRevisionLookup(),
|
|
$services->getTitleFormatter(),
|
|
$services->getPageStore()
|
|
) );
|
|
|
|
$parsoidOutputStash = $this->getParsoidOutputStash();
|
|
$helperFactory->method( 'newHtmlOutputRendererHelper' )
|
|
->willReturnCallback( static function ( $page, $parameters, $authority, $revision, $lenientRevHandling ) use ( $services, $parsoidOutputStash ) {
|
|
return new HtmlOutputRendererHelper(
|
|
$parsoidOutputStash,
|
|
$services->getStatsdDataFactory(),
|
|
$services->getParserOutputAccess(),
|
|
$services->getPageStore(),
|
|
$services->getRevisionLookup(),
|
|
$services->getRevisionRenderer(),
|
|
$services->getParsoidSiteConfig(),
|
|
$services->getHtmlTransformFactory(),
|
|
$services->getContentHandlerFactory(),
|
|
$services->getLanguageFactory(),
|
|
$page,
|
|
$parameters,
|
|
$authority,
|
|
$revision,
|
|
$lenientRevHandling
|
|
);
|
|
} );
|
|
$helperFactory->method( 'newHtmlMessageOutputHelper' )
|
|
->willReturnCallback( static function ( $page ) {
|
|
return new HtmlMessageOutputHelper( $page );
|
|
} );
|
|
|
|
$request ??= new RequestData( [] );
|
|
$responseFactory = new ResponseFactory( [] );
|
|
$helperFactory->method( 'newPageRedirectHelper' )
|
|
->willReturn(
|
|
new PageRedirectHelper(
|
|
$services->getRedirectStore(),
|
|
$services->getTitleFormatter(),
|
|
$responseFactory,
|
|
$this->newRouterForPageHandler( 'https://example.test/api' ),
|
|
'/test/{title}',
|
|
$request,
|
|
$services->getLanguageConverterFactory()
|
|
)
|
|
);
|
|
|
|
return new PageHTMLHandler(
|
|
$helperFactory
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return PageSourceHandler
|
|
*/
|
|
public function newPageSourceHandler() {
|
|
$services = $this->getServiceContainer();
|
|
return new PageSourceHandler(
|
|
$services->getTitleFormatter(),
|
|
$services->getPageRestHelperFactory()
|
|
);
|
|
}
|
|
|
|
public function newPageHistoryHandler() {
|
|
$services = $this->getServiceContainer();
|
|
return new PageHistoryHandler(
|
|
$services->getRevisionStore(),
|
|
$services->getNameTableStoreFactory(),
|
|
$services->getGroupPermissionsLookup(),
|
|
$services->getConnectionProvider(),
|
|
$services->getPageStore(),
|
|
$services->getTitleFormatter(),
|
|
$services->getPageRestHelperFactory()
|
|
);
|
|
}
|
|
|
|
public function newPageHistoryCountHandler() {
|
|
$services = $this->getServiceContainer();
|
|
return new PageHistoryCountHandler(
|
|
$services->getRevisionStore(),
|
|
$services->getNameTableStoreFactory(),
|
|
$services->getGroupPermissionsLookup(),
|
|
$services->getConnectionProvider(),
|
|
new WANObjectCache( [ 'cache' => $this->parserCacheBagOStuff, ] ),
|
|
$services->getPageStore(),
|
|
$services->getPageRestHelperFactory(),
|
|
$services->getTempUserConfig()
|
|
);
|
|
}
|
|
|
|
public function newLanguageLinksHandler() {
|
|
$services = $this->getServiceContainer();
|
|
return new LanguageLinksHandler(
|
|
$services->getConnectionProvider(),
|
|
$services->getLanguageNameUtils(),
|
|
$services->getTitleFormatter(),
|
|
$services->getTitleParser(),
|
|
$services->getPageStore(),
|
|
$services->getPageRestHelperFactory()
|
|
);
|
|
}
|
|
|
|
private function installMockFileRepo( string $fileName, ?string $redirectedFrom = null ): void {
|
|
$repo = $this->createNoOpMock(
|
|
FileRepo::class,
|
|
[]
|
|
);
|
|
$file = $this->createNoOpMock(
|
|
File::class,
|
|
[
|
|
'isLocal',
|
|
'exists',
|
|
'getRepo',
|
|
'getRedirected',
|
|
'getName',
|
|
]
|
|
);
|
|
$file->method( 'isLocal' )->willReturn( false );
|
|
$file->method( 'exists' )->willReturn( true );
|
|
$file->method( 'getRepo' )->willReturn( $repo );
|
|
$file->method( 'getRedirected' )->willReturn( $redirectedFrom );
|
|
$file->method( 'getName' )->willReturn( $fileName );
|
|
|
|
$repoGroup = $this->createNoOpMock(
|
|
RepoGroup::class,
|
|
[ 'findFile' ]
|
|
);
|
|
$repoGroup->expects( $this->atLeastOnce() )->method( 'findFile' )
|
|
->willReturn( $file );
|
|
|
|
$this->setService(
|
|
'RepoGroup',
|
|
$repoGroup
|
|
);
|
|
}
|
|
|
|
}
|