so it can be targeted
+ // with CSS (T37247)
+ $class = $options->getWrapOutputClass();
+ if ( $class !== false && !$options->getInterfaceMessage() ) {
+ $parserOutput->addWrapperDivClass( $class );
+ }
+
+ $this->makeLimitReport( $options, $parserOutput );
+
+ // Record Parsoid version in extension data; this allows
+ // us to use the onRejectParserCacheValue hook to selectively
+ // expire "bad" generated content in the event of a rollback.
+ $parserOutput->setExtensionData(
+ 'core:parsoid-version', Parsoid::version()
+ );
+
+ return $parserOutput;
}
/**
@@ -116,59 +245,38 @@ class ParsoidParser /* eventually this will extend \Parser */ {
);
}
- // FIXME: Right now, ParsoidOutputAccess uses $lang and does not compute a
- // $preferredVariant for $lang. So, when switching over to ParserOutputAccess,
- // we need to reconcile that difference.
- //
- // The REST interfaces will disable content conversion here
- // via ParserOptions. The enable/disable logic here matches
- // that in Parser::internalParseHalfParsed(), although
- // __NOCONTENTCONVERT__ is handled internal to Parsoid.
- $preferredVariant = null;
- if ( !( $options->getDisableContentConversion() || $options->getInterfaceMessage() ) ) {
- $langFactory = MediaWikiServices::getInstance()->getLanguageFactory();
- $lang = $langFactory->getLanguage( $pageConfig->getPageLanguageBcp47() );
- $langConv = $this->languageConverterFactory->getLanguageConverter( $lang );
- $preferredVariant = $langFactory->getLanguage( $langConv->getPreferredVariant() );
+ return $this->genParserOutput( $pageConfig, $options );
+ }
+
+ /**
+ * @internal
+ *
+ * Convert custom wikitext (stored in main slot of the $fakeRev arg) to HTML.
+ * Callers are expected NOT to stuff the result into ParserCache.
+ *
+ * @param RevisionRecord $fakeRev Revision to parse
+ * @param PageReference $page
+ * @param ParserOptions $options
+ * @return ParserOutput
+ * @unstable since 1.41
+ */
+ public function parseFakeRevision(
+ RevisionRecord $fakeRev, PageReference $page, ParserOptions $options
+ ): ParserOutput {
+ $title = Title::newFromPageReference( $page );
+ $lang = $options->getTargetLanguage();
+ if ( $lang === null && $options->getInterfaceMessage() ) {
+ $lang = $options->getUserLangObj();
}
-
- $parserOutput = new ParserOutput();
- // NOTE: This is useless until the time Parsoid uses the
- // $options ParserOptions object. But if/when it does, this
- // will ensure that we track used options correctly.
- $options->registerWatcher( [ $parserOutput, 'recordOption' ] );
-
- $pageBundle = $this->parsoid->wikitext2html( $pageConfig, [
- 'pageBundle' => true,
- 'wrapSections' => true,
- 'htmlVariantLanguage' => $preferredVariant,
- 'outputContentVersion' => Parsoid::defaultHTMLVersion(),
- 'logLinterData' => true
- ], $headers, $parserOutput );
- $parserOutput = PageBundleParserOutputConverter::parserOutputFromPageBundle( $pageBundle, $parserOutput );
- // Register a watcher again because the $parserOuptut arg
- // and $parserOutput return value above are different objects!
- $options->registerWatcher( [ $parserOutput, 'recordOption' ] );
-
- # Copied from Parser.php::parse and should probably be abstracted
- # into the parent base class (probably as part of T236809)
- # Wrap non-interface parser output in a
so it can be targeted
- # with CSS (T37247)
- $class = $options->getWrapOutputClass();
- if ( $class !== false && !$options->getInterfaceMessage() ) {
- $parserOutput->addWrapperDivClass( $class );
- }
-
- $this->makeLimitReport( $options, $parserOutput );
-
- // Record Parsoid version in extension data; this allows
- // us to use the onRejectParserCacheValue hook to selectively
- // expire "bad" generated content in the event of a rollback.
- $parserOutput->setExtensionData(
- 'core:parsoid-version', Parsoid::version()
+ $pageConfig = $this->pageConfigFactory->create(
+ $title,
+ $options->getUserIdentity(),
+ $fakeRev,
+ null, // unused
+ $lang // defaults to title page language if null
);
- return $parserOutput;
+ return $this->genParserOutput( $pageConfig, $options );
}
/**
diff --git a/includes/parser/Parsoid/ParsoidParserFactory.php b/includes/parser/Parsoid/ParsoidParserFactory.php
index 48a0a29608b..955a3df74ef 100644
--- a/includes/parser/Parsoid/ParsoidParserFactory.php
+++ b/includes/parser/Parsoid/ParsoidParserFactory.php
@@ -8,6 +8,7 @@ use ParserFactory;
use Wikimedia\Parsoid\Config\DataAccess;
use Wikimedia\Parsoid\Config\SiteConfig;
use Wikimedia\Parsoid\Parsoid;
+use Wikimedia\UUID\GlobalIdGenerator;
/**
* ParserFactory which uses a ParsoidParser.
@@ -39,6 +40,9 @@ class ParsoidParserFactory /* eventually this may extend \ParserFactory */ {
/** @var ParserFactory */
private $legacyParserFactory;
+ /** @var GlobalIdGenerator */
+ private $globalIdGenerator;
+
/**
* @param SiteConfig $siteConfig
* @param DataAccess $dataAccess
@@ -51,13 +55,15 @@ class ParsoidParserFactory /* eventually this may extend \ParserFactory */ {
DataAccess $dataAccess,
PageConfigFactory $pageConfigFactory,
LanguageConverterFactory $languageConverterFactory,
- ParserFactory $legacyParserFactory
+ ParserFactory $legacyParserFactory,
+ GlobalIdGenerator $globalIdGenerator
) {
$this->siteConfig = $siteConfig;
$this->dataAccess = $dataAccess;
$this->pageConfigFactory = $pageConfigFactory;
$this->languageConverterFactory = $languageConverterFactory;
$this->legacyParserFactory = $legacyParserFactory;
+ $this->globalIdGenerator = $globalIdGenerator;
}
/**
@@ -71,7 +77,8 @@ class ParsoidParserFactory /* eventually this may extend \ParserFactory */ {
new Parsoid( $this->siteConfig, $this->dataAccess ),
$this->pageConfigFactory,
$this->languageConverterFactory,
- $this->legacyParserFactory
+ $this->legacyParserFactory,
+ $this->globalIdGenerator
);
}
}
diff --git a/maintenance/prewarmParsoidParserCache.php b/maintenance/prewarmParsoidParserCache.php
index 6cb4333575a..9ca96870ed9 100644
--- a/maintenance/prewarmParsoidParserCache.php
+++ b/maintenance/prewarmParsoidParserCache.php
@@ -1,6 +1,7 @@
forceParse | ParsoidOutputAccess::OPT_LOG_LINT_DATA
+ $this->forceParse
);
}
@@ -110,7 +111,7 @@ class PrewarmParsoidParserCache extends Maintenance {
if ( $force !== null ) {
// If --force is supplied, for a parse for supported pages or supported
// pages in the specified batch.
- $this->forceParse = ParsoidOutputAccess::OPT_FORCE_PARSE;
+ $this->forceParse = ParserOutputAccess::OPT_FORCE_PARSE;
}
$startFrom = (int)$startFrom;
diff --git a/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php b/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php
index 27a21b3cb62..f13a92d0148 100644
--- a/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php
+++ b/tests/phpunit/includes/Storage/DerivedPageDataUpdaterTest.php
@@ -1312,7 +1312,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiIntegrationTestCase {
// Assert cache update after edit ----------
$parserCacheFactory = $this->getServiceContainer()->getParserCacheFactory();
$parserCache = $parserCacheFactory->getParserCache( ParserCacheFactory::DEFAULT_NAME );
- $parsoidCache = $parserCacheFactory->getParserCache( ParsoidOutputAccess::PARSOID_PARSER_CACHE_NAME );
+ $parsoidCache = $parserCacheFactory->getParserCache( "parsoid-" . ParserCacheFactory::DEFAULT_NAME );
$parserCache->deleteOptionsKey( $page );
$parsoidCache->deleteOptionsKey( $page );
@@ -1331,7 +1331,7 @@ class DerivedPageDataUpdaterTest extends MediaWikiIntegrationTestCase {
// Parsoid cache should have an entry
$parserOptions = ParserOptions::newFromAnon();
-
+ $parserOptions->setUseParsoid();
$parsoidCached = $parsoidCache->get( $page, $parserOptions, true );
$this->assertIsObject( $parsoidCached );
$this->assertStringContainsString( 'first', $parsoidCached->getRawText() );
@@ -1344,6 +1344,8 @@ class DerivedPageDataUpdaterTest extends MediaWikiIntegrationTestCase {
$this->getServiceContainer()->getParsoidOutputAccess()->getParsoidRenderID( $parsoidCached );
// The cached ParserOutput should not use the revision timestamp
+ // Create nwe ParserOptions object since we setUseParsoid() above
+ $parserOptions = ParserOptions::newFromAnon();
$cached = $parserCache->get( $page, $parserOptions, true );
$this->assertIsObject( $cached );
$this->assertNotSame( $parsoidCached, $cached );
diff --git a/tests/phpunit/includes/jobqueue/jobs/ParsoidCachePrewarmJobTest.php b/tests/phpunit/includes/jobqueue/jobs/ParsoidCachePrewarmJobTest.php
index 604240e517e..ce935172a0f 100644
--- a/tests/phpunit/includes/jobqueue/jobs/ParsoidCachePrewarmJobTest.php
+++ b/tests/phpunit/includes/jobqueue/jobs/ParsoidCachePrewarmJobTest.php
@@ -55,6 +55,12 @@ class ParsoidCachePrewarmJobTest extends MediaWikiIntegrationTestCase {
$this->assertStringContainsString( self::NON_JOB_QUEUE_EDIT, $parsoidOutput->getRawText() );
$rev2 = $this->editPage( $page, self::JOB_QUEUE_EDIT )->getNewRevision();
+ // Post-edit, reset all services!
+ // ParserOutputAccess has a localCache which can incorrectly return stale
+ // content for the previous revision! Resetting ensures that ParsoidCachePrewarmJob
+ // gets a fresh copy of ParserOutputAccess and ParsoidOutputAccess.
+ $this->resetServices();
+
$parsoidPrewarmJob = new ParsoidCachePrewarmJob(
[ 'revId' => $rev2->getId(), 'pageId' => $page->getId(), 'causeAction' => 'just for testing' ],
$this->getServiceContainer()->getParsoidOutputAccess(),
diff --git a/tests/phpunit/integration/includes/Rest/Handler/Helper/HtmlOutputRendererHelperTest.php b/tests/phpunit/integration/includes/Rest/Handler/Helper/HtmlOutputRendererHelperTest.php
index 17e68356c24..9bd93d65093 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/Helper/HtmlOutputRendererHelperTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/Helper/HtmlOutputRendererHelperTest.php
@@ -13,13 +13,17 @@ use MediaWiki\Config\ServiceOptions;
use MediaWiki\Content\IContentHandlerFactory;
use MediaWiki\Edit\SimpleParsoidOutputStash;
use MediaWiki\Hook\ParserLogLinterDataHook;
+use MediaWiki\Logger\Spi as LoggerSpi;
use MediaWiki\MainConfigNames;
use MediaWiki\Page\PageIdentity;
use MediaWiki\Page\PageIdentityValue;
use MediaWiki\Page\PageRecord;
+use MediaWiki\Page\ParserOutputAccess;
use MediaWiki\Parser\ParserCacheFactory;
use MediaWiki\Parser\Parsoid\PageBundleParserOutputConverter;
use MediaWiki\Parser\Parsoid\ParsoidOutputAccess;
+use MediaWiki\Parser\Parsoid\ParsoidParser;
+use MediaWiki\Parser\Parsoid\ParsoidParserFactory;
use MediaWiki\Parser\Parsoid\ParsoidRenderID;
use MediaWiki\Parser\RevisionOutputCache;
use MediaWiki\Rest\Handler\Helper\HtmlOutputRendererHelper;
@@ -40,6 +44,7 @@ use ParserOptions;
use ParserOutput;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\MockObject\Rule\InvocationOrder;
+use Psr\Log\NullLogger;
use Wikimedia\Bcp47Code\Bcp47CodeValue;
use Wikimedia\Message\MessageValue;
use Wikimedia\Parsoid\Core\ClientError;
@@ -82,13 +87,25 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
return new ParsoidRenderID( $pout->getCacheRevisionId(), $pout->getCacheTime() );
}
+ /**
+ * @param LoggerInterface|null $logger
+ *
+ * @return LoggerSpi
+ */
+ private function getLoggerSpi( $logger = null ) {
+ $logger = $logger ?: new NullLogger();
+ $spi = $this->createNoOpMock( LoggerSpi::class, [ 'getLogger' ] );
+ $spi->method( 'getLogger' )->willReturn( $logger );
+ return $spi;
+ }
+
/**
* @return MockObject|ParsoidOutputAccess
*/
public function newMockParsoidOutputAccess(): ParsoidOutputAccess {
$expectedCalls = [
'getParserOutput' => null,
- 'parse' => null,
+ 'parseUncacheable' => null,
'getParsoidRenderID' => null
];
@@ -114,13 +131,13 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$parsoid->method( 'getParsoidRenderID' )
->willReturnCallback( [ $this, 'getParsoidRenderID' ] );
- $parsoid->expects( $this->exactlyOrAny( $expectedCalls[ 'parse' ] ) )
- ->method( 'parse' )
+ $parsoid->expects( $this->exactlyOrAny( $expectedCalls[ 'parseUncacheable' ] ) )
+ ->method( 'parseUncacheable' )
->willReturnCallback( function (
PageIdentity $page,
ParserOptions $parserOpts,
- array $envOptions,
- $rev
+ $rev,
+ array $envOptions = []
) {
$html = $this->getMockHtml( $rev, $envOptions );
@@ -366,14 +383,13 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
// Calling setParsoidOptions must disable caching and force the ETag to null
$helper->setOutputProfileVersion( '999.0.0' );
- $helper->setOffsetType( 'ucs2' );
$pb = $helper->getPageBundle();
// NOTE: Check that the options are present in the HTML.
// We don't do real parsing, so this is how they are represented in the output.
$this->assertStringContainsString( '"outputContentVersion":"999.0.0"', $pb->html );
- $this->assertStringContainsString( '"offsetType":"ucs2"', $pb->html );
+ $this->assertStringContainsString( '"offsetType":"byte"', $pb->html );
$response = new Response();
$helper->putHeaders( $response, true );
@@ -512,9 +528,9 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$htmlresult = $helper->getHtml()->getRawText();
$this->assertStringContainsString( 'fragment', $helper->getETag() );
-
$this->assertStringContainsString( self::MOCK_HTML, $htmlresult );
- $this->assertStringContainsString( '"body_only":true', $htmlresult );
+ $this->assertStringNotContainsString( "assertStringNotContainsString( "getNonExistingPageWithFakeRevision( __METHOD__ );
$poa = $this->createMock( ParsoidOutputAccess::class );
$poa->expects( $this->once() )
- ->method( 'parse' )
+ ->method( 'parseUncacheable' )
->willReturnCallback( function (
PageIdentity $page,
ParserOptions $parserOpts,
- array $envOptions,
- $rev = null
+ $rev,
+ array $envOptions = []
) use ( $fakePage, $fakeRevision ) {
self::assertSame( $page, $fakePage, '$page and $fakePage should be the same' );
self::assertSame( $rev, $fakeRevision, '$rev and $fakeRevision should be the same' );
@@ -705,15 +721,36 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
];
}
- private function newRealParsoidOutputAccess( $overrides = [] ) {
- if ( isset( $overrides['parsoid'] ) ) {
- $parsoid = $overrides['parsoid'];
- } else {
- $parsoid = $this->createNoOpMock( Parsoid::class, [ 'wikitext2html' ] );
- $parsoid->method( 'wikitext2html' )
+ private function resetServicesWithMockedParsoid( ?Parsoid $mockParsoid = null ): void {
+ $services = $this->getServiceContainer();
+
+ // Init mock Parsoid object
+ if ( !$mockParsoid ) {
+ $mockParsoid = $this->createNoOpMock( Parsoid::class, [ 'wikitext2html' ] );
+ $mockParsoid->method( 'wikitext2html' )
->willReturn( new PageBundle( 'This is HTML' ) );
}
+ // Install it in the ParsoidParser object
+ $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 );
+ }
+
+ private function newRealParsoidOutputAccess( $overrides = [] ): ParsoidOutputAccess {
+ $services = $this->getServiceContainer();
+
if ( isset( $overrides['parserCache'] ) ) {
$parserCache = $overrides['parserCache'];
} else {
@@ -736,8 +773,17 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
);
$parserCacheFactory->method( 'getParserCache' )->willReturn( $parserCache );
$parserCacheFactory->method( 'getRevisionOutputCache' )->willReturn( $revisionCache );
-
- $services = $this->getServiceContainer();
+ $parserOutputAccess = new ParserOutputAccess(
+ $parserCacheFactory,
+ $services->getRevisionLookup(),
+ $services->getRevisionRenderer(),
+ new NullStatsdDataFactory(),
+ $services->getDBLoadBalancerFactory(),
+ $services->getChronologyProtector(),
+ $this->getLoggerSpi(),
+ $services->getWikiPageFactory(),
+ $services->getTitleFormatter()
+ );
return new ParsoidOutputAccess(
new ServiceOptions(
@@ -745,14 +791,11 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$services->getMainConfig(),
[ 'ParsoidWikiID' => 'MyWiki' ]
),
- $parserCacheFactory,
+ $services->getParsoidParserFactory(),
+ $parserOutputAccess,
$services->getPageStore(),
$services->getRevisionLookup(),
- $services->getGlobalIdGenerator(),
- new NullStatsdDataFactory(),
- $parsoid,
$services->getParsoidSiteConfig(),
- $services->getParsoidPageConfigFactory(),
$services->getContentHandlerFactory()
);
}
@@ -770,10 +813,13 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$parsoid->method( 'wikitext2html' )
->willThrowException( $parsoidException );
- /** @var ParsoidOutputAccess|MockObject $access */
- $access = $this->newRealParsoidOutputAccess( [
- 'parsoid' => $parsoid
- ] );
+ $parserCache = $this->createNoOpMock( ParserCache::class, [ 'get', 'makeParserOutputKey', 'getMetadata' ] );
+ $parserCache->method( 'get' )->willReturn( false );
+ $parserCache->expects( $this->once() )->method( 'getMetadata' );
+ $parserCache->expects( $this->atLeastOnce() )->method( 'makeParserOutputKey' );
+
+ $this->resetServicesWithMockedParsoid( $parsoid );
+ $access = $this->newRealParsoidOutputAccess( [ 'parserCache' => $parserCache ] );
$helper = $this->newHelper( null, $access );
$helper->init( $page, self::PARAM_DEFAULTS, $this->newUser() );
@@ -790,13 +836,18 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$page = PageIdentityValue::localIdentity( $page->getId(), $page->getNamespace(), $page->getDBkey() );
// This is the key assertion in this test case: get() and save() are both called.
- $parserCache = $this->createNoOpMock( ParserCache::class, [ 'get', 'save' ] );
- $parserCache->expects( $this->once() )->method( 'get' )->willReturn( false );
+ $parserCache = $this->createNoOpMock( ParserCache::class, [ 'get', 'save', 'getMetadata', 'makeParserOutputKey' ] );
+ // Second call is for the fallback cache for hacks added to ParserCache
+ // (T347632 tracks removal of this hack)
+ $parserCache->expects( $this->exactly( 2 ) )->method( 'get' )->willReturn( false );
$parserCache->expects( $this->once() )->method( 'save' );
+ $parserCache->expects( $this->once() )->method( 'getMetadata' );
+ $parserCache->expects( $this->atLeastOnce() )->method( 'makeParserOutputKey' );
+ $this->resetServicesWithMockedParsoid();
$access = $this->newRealParsoidOutputAccess( [
'parserCache' => $parserCache,
- 'revisionCache' => $this->createNoOpMock( RevisionOutputCache::class ),
+ 'revisionCache' => $this->createNoOpMock( RevisionOutputCache::class )
] );
$helper = $this->newHelper( null, $access );
@@ -810,10 +861,12 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
// NOTE: The save() method is not supported and will throw!
// The point of this test case is asserting that save() isn't called.
- $parserCache = $this->createNoOpMock( ParserCache::class, [ 'get' ] );
+ $parserCache = $this->createNoOpMock( ParserCache::class, [ 'get', 'getMetadata', 'makeParserOutputKey' ] );
$parserCache->method( 'get' )->willReturn( false );
+ $parserCache->expects( $this->once() )->method( 'getMetadata' );
+ $parserCache->expects( $this->atLeastOnce() )->method( 'makeParserOutputKey' );
- /** @var ParsoidOutputAccess|MockObject $access */
+ $this->resetServicesWithMockedParsoid();
$access = $this->newRealParsoidOutputAccess( [
'parserCache' => $parserCache,
'revisionCache' => $this->createNoOpMock( RevisionOutputCache::class ),
@@ -833,10 +886,12 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
// NOTE: The get() method is not supported and will throw!
// The point of this test case is asserting that get() isn't called.
// We also check that save() is still called.
- $parserCache = $this->createNoOpMock( ParserCache::class, [ 'save' ] );
+ $parserCache = $this->createNoOpMock( ParserCache::class, [ 'save', 'getMetadata', 'makeParserOutputKey' ] );
$parserCache->expects( $this->once() )->method( 'save' );
+ $parserCache->expects( $this->once() )->method( 'getMetadata' );
+ $parserCache->expects( $this->atLeastOnce() )->method( 'makeParserOutputKey' );
- /** @var ParsoidOutputAccess|MockObject $access */
+ $this->resetServicesWithMockedParsoid();
$access = $this->newRealParsoidOutputAccess( [
'parserCache' => $parserCache,
'revisionCache' => $this->createNoOpMock( RevisionOutputCache::class ),
@@ -1057,13 +1112,17 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
public static function provideFlavorsForBadModelOutput() {
yield 'view' => [ 'view' ];
yield 'edit' => [ 'edit' ];
- yield 'fragment' => [ 'fragment' ];
+ // fragment mode is only for posted wikitext fragments not part of a revision
+ // and should not be used with real revisions
+ //
+ // yield 'fragment' => [ 'fragment' ];
}
/**
* @dataProvider provideFlavorsForBadModelOutput
*/
public function testDummyContentForBadModel( string $flavor ) {
+ $this->resetServicesWithMockedParsoid();
$helper = $this->newHelper( new HashBagOStuff(), $this->newRealParsoidOutputAccess() );
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -1098,7 +1157,7 @@ class HtmlOutputRendererHelperTest extends MediaWikiIntegrationTestCase {
$first = false;
} else {
$version = Parsoid::defaultHTMLVersion();
- $this->assertGreaterThan( 0, $options & ParsoidOutputAccess::OPT_FORCE_PARSE );
+ $this->assertGreaterThan( 0, $options & ParserOutputAccess::OPT_FORCE_PARSE );
}
$html = $this->getMockHtml( $revision );
$pout = $this->makeParserOutput( $parserOpts, $html, $revision, $page, $version );
diff --git a/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
index 78196c06600..eca3a33d24f 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/PageHTMLHandlerTest.php
@@ -60,7 +60,10 @@ class PageHTMLHandlerTest extends MediaWikiIntegrationTestCase {
* @return PageHTMLHandler
*/
private function newHandler( ?Parsoid $parsoid = null ): PageHTMLHandler {
- return $this->newPageHtmlHandler( $parsoid );
+ if ( $parsoid ) {
+ $this->resetServicesWithMockedParsoid( $parsoid );
+ }
+ return $this->newPageHtmlHandler();
}
public function testExecuteWithHtml() {
diff --git a/tests/phpunit/integration/includes/Rest/Handler/PageRedirectHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/PageRedirectHandlerTest.php
index 37074da31c0..740da69647e 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/PageRedirectHandlerTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/PageRedirectHandlerTest.php
@@ -48,9 +48,9 @@ class PageRedirectHandlerTest extends MediaWikiIntegrationTestCase {
case 'bare':
return $this->newPageSourceHandler();
case 'html':
- return $this->newPageHtmlHandler( null, $request );
+ return $this->newPageHtmlHandler( $request );
case 'with_html':
- return $this->newPageHtmlHandler( null, $request );
+ return $this->newPageHtmlHandler( $request );
case 'history':
return $this->newPageHistoryHandler();
case 'history_count':
diff --git a/tests/phpunit/integration/includes/Rest/Handler/ParsoidHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/ParsoidHandlerTest.php
index bddae78f7a9..28457dd2199 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/ParsoidHandlerTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/ParsoidHandlerTest.php
@@ -1906,12 +1906,10 @@ class ParsoidHandlerTest extends MediaWikiIntegrationTestCase {
$attribs = [
'oldid' => 1, // will be replaced by a real revision id
'opts' => [ 'format' => ParsoidFormatHelper::FORMAT_PAGEBUNDLE ],
- 'envOptions' => [
- // Ensure this is ucs2 so we have a ucs2 offsetType test since
- // Parsoid's rt-testing script is node.js based and hence needs
- // ucs2 offsets to function correctly!
- 'offsetType' => 'ucs2', // make sure this is looped through to data-parsoid attribute
- ]
+ // Ensure this is ucs2 so we have a ucs2 offsetType test since
+ // Parsoid's rt-testing script is node.js based and hence needs
+ // ucs2 offsets to function correctly!
+ 'offsetType' => 'ucs2', // make sure this is looped through to data-parsoid attribute
];
yield 'should get from a title and revision (pagebundle)' => [
$attribs,
@@ -2090,12 +2088,15 @@ class ParsoidHandlerTest extends MediaWikiIntegrationTestCase {
$page = $this->getExistingTestPage();
$pageConfig = $this->getPageConfig( $page );
- $parserCache = $this->createNoOpMock( ParserCache::class, [ 'save', 'get' ] );
+ $parserCache = $this->createNoOpMock( ParserCache::class, [ 'save', 'get', 'makeParserOutputKey', 'getMetadata' ] );
// This is the critical assertion in this test case: the save() method should
// be called exactly once!
$parserCache->expects( $this->once() )->method( 'save' );
$parserCache->method( 'get' )->willReturn( false );
+ // These methods will be called by ParserOutputAccess:qa
+ $parserCache->expects( $this->atLeastOnce() )->method( 'makeParserOutputKey' );
+ $parserCache->expects( $this->atLeastOnce() )->method( 'getMetadata' );
$parserCacheFactory = $this->createNoOpMock(
ParserCacheFactory::class,
diff --git a/tests/phpunit/integration/includes/Rest/Handler/ParsoidOutputAccessTest.php b/tests/phpunit/integration/includes/Rest/Handler/ParsoidOutputAccessTest.php
index 8bce60dd88b..608717d2780 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/ParsoidOutputAccessTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/ParsoidOutputAccessTest.php
@@ -1,13 +1,14 @@
getServiceContainer();
$parsoidCacheConfig += [
@@ -97,22 +97,41 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$services->getWikiPageFactory()
);
+ $mockParsoid = $this->newMockParsoid( $expectedParses );
+ $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->expects( $this->exactly( $expectedParses ) )
+ ->method( 'create' )
+ ->willReturn( $parsoidParser );
+
+ $this->setService( 'ParsoidParserFactory', $mockParsoidParserFactory );
+ }
+
+ /**
+ * @return ParsoidOutputAccess
+ */
+ private function getParsoidOutputAccessWithCache(): ParsoidOutputAccess {
+ $services = $this->getServiceContainer();
return new ParsoidOutputAccess(
new ServiceOptions(
ParsoidOutputAccess::CONSTRUCTOR_OPTIONS,
- [
- 'ParsoidCacheConfig' => $parsoidCacheConfig,
- 'ParsoidWikiID' => 'MyWiki'
- ]
+ $services->getMainConfig(),
+ [ 'ParsoidWikiID' => 'MyWiki' ]
),
- $parserCacheFactory,
+ $services->getParsoidParserFactory(),
+ $services->getParserOutputAccess(),
$services->getPageStore(),
$services->getRevisionLookup(),
- $services->getGlobalIdGenerator(),
- $stats,
- $this->newMockParsoid( $expectedParses ),
$services->getParsoidSiteConfig(),
- $services->getParsoidPageConfigFactory(),
$services->getContentHandlerFactory()
);
}
@@ -153,7 +172,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
* @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testGetParserOutputThrowsIfRevisionNotFound() {
- $access = $this->getParsoidOutputAccessWithCache( 0 );
+ $this->resetServicesWithMockedParsoid( 0 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -168,7 +188,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
public function testGetParserOutputThrowsIfNotWikitext() {
$this->markTestSkipped( 'Broken by fix for T324711. Restore once we have T311728.' );
- $access = $this->getParsoidOutputAccessWithCache( 0 );
+ $this->resetServicesWithMockedParsoid( 0 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -190,7 +211,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
* @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParsoidRenderID
*/
public function testGetParserOutput() {
- $access = $this->getParsoidOutputAccessWithCache( 1 );
+ $this->resetServicesWithMockedParsoid( 1 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -223,10 +245,10 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
* in the parsoid parser cache.
*
* @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getCachedParserOutputInternal
*/
public function testLatestRevisionIsCached() {
- $access = $this->getParsoidOutputAccessWithCache( 1 );
+ $this->resetServicesWithMockedParsoid( 1 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -259,7 +281,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
* @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testLatestRevisionWithForceParse() {
- $access = $this->getParsoidOutputAccessWithCache( 2 );
+ $this->resetServicesWithMockedParsoid( 2 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -275,41 +298,12 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$page,
$parserOptions,
null,
- ParsoidOutputAccess::OPT_FORCE_PARSE
+ ParserOutputAccess::OPT_FORCE_PARSE
);
$this->assertContainsHtml( self::MOCKED_HTML . ' of ' . self::WIKITEXT, $status );
$this->checkMetadata( $status );
}
- /**
- * Tests that the ParserLogLinterData hook is triggered when the OPT_LOG_LINT_DATA
- * flag is set.
- *
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
- */
- public function testLatestRevisionWithLogLint() {
- $this->overrideConfigValue( MainConfigNames::ParsoidSettings, [
- 'linting' => true
- ] );
-
- $mockHandler = $this->createMock( ParserLogLinterDataHook::class );
- $mockHandler->expects( $this->once() ) // this is the critical assertion in this test case!
- ->method( 'onParserLogLinterData' );
-
- $this->setTemporaryHook(
- 'ParserLogLinterData',
- $mockHandler
- );
-
- // Use the real ParsoidOutputAccess, so we use the real hook container.
- $access = $this->getServiceContainer()->getParsoidOutputAccess();
- $parserOptions = $this->getParserOptions();
-
- $page = $this->getExistingTestPage( __METHOD__ );
-
- $access->getParserOutput( $page, $parserOptions, null, ParsoidOutputAccess::OPT_LOG_LINT_DATA );
- }
-
/**
* Tests that getParserOutput() will force a parse since we know that
* the revision is not in the cache.
@@ -317,7 +311,15 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
* @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testLatestRevisionWithNoUpdateCache() {
- $access = $this->getParsoidOutputAccessWithCache( 2 );
+ $cacheBag = $this->getMockBuilder( HashBagOStuff::class )
+ ->onlyMethods( [ 'set', 'setMulti' ] )
+ ->getMock();
+ $cacheBag->expects( $this->never() )->method( 'set' );
+ $cacheBag->expects( $this->never() )->method( 'setMulti' );
+
+ // ParserCache should not get anything stored in it.
+ $this->resetServicesWithMockedParsoid( 1, [], $cacheBag );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -327,16 +329,10 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$page,
$parserOptions,
null,
- ParsoidOutputAccess::OPT_NO_UPDATE_CACHE
+ ParserOutputAccess::OPT_NO_UPDATE_CACHE
);
$this->assertContainsHtml( self::MOCKED_HTML . ' of ' . self::WIKITEXT, $status );
$this->checkMetadata( $status );
-
- // Get the ParserOutput again, this should trigger a new parse
- // since we suppressed caching above.
- $status = $access->getParserOutput( $page, $parserOptions );
- $this->assertContainsHtml( self::MOCKED_HTML . ' of ' . self::WIKITEXT, $status );
- $this->checkMetadata( $status );
}
/**
@@ -354,7 +350,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$cacheBag->expects( $this->never() )->method( 'setMulti' );
// Expect no calls to parsoid!
- $access = $this->getParsoidOutputAccessWithCache( 0, [], $cacheBag );
+ $this->resetServicesWithMockedParsoid( 0, [], $cacheBag );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -376,6 +373,9 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$this->assertContainsHtml( 'Dummy output', $status );
}
+ /**
+ * Unsupported functionality at this point
+ */
public static function provideCacheThresholdData() {
return [
yield "fast parse" => [ 1, 2 ], // high threshold, no caching
@@ -390,13 +390,16 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$cacheThresholdTime,
$expectedCalls
) {
+ $this->markTestSkipped( 'Supported removed. Will be fixed by T346398.' );
+
$page = $this->getExistingTestPage( __METHOD__ );
$parsoidCacheConfig = [
'CacheThresholdTime' => $cacheThresholdTime
];
$parserOptions = $this->getParserOptions();
- $access = $this->getParsoidOutputAccessWithCache( $expectedCalls, $parsoidCacheConfig );
+ $this->resetServicesWithMockedParsoid( $expectedCalls, $parsoidCacheConfig );
+ $access = $this->getParsoidOutputAccessWithCache();
$status = $access->getParserOutput( $page, $parserOptions );
$this->assertContainsHtml( self::MOCKED_HTML, $status );
$this->checkMetadata( $status );
@@ -407,7 +410,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
public function testOldRevisionIsCached() {
- $access = $this->getParsoidOutputAccessWithCache( 1 );
+ $this->resetServicesWithMockedParsoid( 1 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -437,7 +441,8 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
public function testGetParserOutputWithOldRevision() {
- $access = $this->getParsoidOutputAccessWithCache( 2 );
+ $this->resetServicesWithMockedParsoid( 2 );
+ $access = $this->getParsoidOutputAccessWithCache();
$parserOptions = $this->getParserOptions();
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -483,20 +488,20 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
} ],
] + $contentHandlers );
- $access = $this->getParsoidOutputAccessWithCache( 0 );
+ $this->resetServicesWithMockedParsoid( 0 );
+ $access = $this->getParsoidOutputAccessWithCache();
$this->assertSame( $expected, $access->supportsContentModel( $model ) );
}
/**
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parse
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseInternal
+ * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testParseWithPageRecordAndNoRevision() {
$pageRecord = $this->getExistingTestPage( __METHOD__ )->toPageRecord();
$pOpts = ParserOptions::newFromAnon();
$parsoidOutputAccess = $this->getServiceContainer()->getParsoidOutputAccess();
- $status = $parsoidOutputAccess->parse( $pageRecord, $pOpts, self::ENV_OPTS, null );
+ $status = $parsoidOutputAccess->getParserOutput( $pageRecord, $pOpts, null );
$this->assertInstanceOf( Status::class, $status );
$this->assertTrue( $status->isOK() );
@@ -520,8 +525,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
/**
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parse
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseInternal
+ * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testParseWithPageRecordAndRevision() {
$page = $this->getExistingTestPage( __METHOD__ );
@@ -530,7 +534,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$revRecord = $page->getRevisionRecord();
$parsoidOutputAccess = $this->getServiceContainer()->getParsoidOutputAccess();
- $status = $parsoidOutputAccess->parse( $pageRecord, $pOpts, self::ENV_OPTS, $revRecord );
+ $status = $parsoidOutputAccess->getParserOutput( $pageRecord, $pOpts, $revRecord );
$this->assertInstanceOf( Status::class, $status );
$this->assertTrue( $status->isOK() );
@@ -545,8 +549,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
/**
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parse
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseInternal
+ * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::getParserOutput
*/
public function testParseWithPageIdentityAndRevisionId() {
$page = $this->getExistingTestPage( __METHOD__ );
@@ -554,7 +557,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$revId = $page->getLatest();
$parsoidOutputAccess = $this->getServiceContainer()->getParsoidOutputAccess();
- $status = $parsoidOutputAccess->parse( $page->getTitle(), $pOpts, self::ENV_OPTS, $revId );
+ $status = $parsoidOutputAccess->getParserOutput( $page->getTitle(), $pOpts, $revId );
$this->assertInstanceOf( Status::class, $status );
$this->assertTrue( $status->isOK() );
@@ -569,8 +572,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
/**
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parse
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseInternal
+ * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseUncacheable
*/
public function testParseWithNonExistingPageAndFakeRevision() {
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -586,7 +588,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
);
$parsoidOutputAccess = $this->getServiceContainer()->getParsoidOutputAccess();
- $status = $parsoidOutputAccess->parse( $page->getTitle(), $pOpts, self::ENV_OPTS, $revRecord );
+ $status = $parsoidOutputAccess->parseUncacheable( $page->getTitle(), $pOpts, $revRecord );
$this->assertInstanceOf( Status::class, $status );
$this->assertTrue( $status->isOK() );
@@ -602,7 +604,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
}
/**
- * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parse
+ * @covers \MediaWiki\Parser\Parsoid\ParsoidOutputAccess::parseUncacheable
*/
public function testParseDeletedRevision() {
$page = $this->getNonexistingTestPage( __METHOD__ );
@@ -620,7 +622,7 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
$revRecord->setVisibility( RevisionRecord::DELETED_TEXT );
$parsoidOutputAccess = $this->getServiceContainer()->getParsoidOutputAccess();
- $status = $parsoidOutputAccess->parse( $page->getTitle(), $pOpts, self::ENV_OPTS, $revRecord );
+ $status = $parsoidOutputAccess->parseUncacheable( $page->getTitle(), $pOpts, $revRecord );
$this->assertStatusError( 'parsoid-revision-access', $status );
$this->assertSame(
@@ -653,18 +655,24 @@ class ParsoidOutputAccessTest extends MediaWikiIntegrationTestCase {
/** @return Generator */
public function provideParserOptionsWithLanguageOverride() {
$parserOptions = $this->createMock( ParserOptions::class );
+ $parserOptions->method( 'optionsHash' )->willReturn( '' );
+ $parserOptions->method( 'getUseParsoid' )->willReturn( true );
$parserOptions->method( 'getTargetLanguage' )
->willReturn( null );
yield 'ParserOptions with no language' => [ $parserOptions, 'en' ];
$langCode = 'de';
$parserOptions = $this->createMock( ParserOptions::class );
+ $parserOptions->method( 'optionsHash' )->willReturn( '' );
+ $parserOptions->method( 'getUseParsoid' )->willReturn( true );
$parserOptions->method( 'getTargetLanguage' )
->willReturn( $this->getLanguageMock( $langCode ) );
yield 'ParserOptions for "de" language' => [ $parserOptions, $langCode ];
$langCode = 'ar';
$parserOptions = $this->createMock( ParserOptions::class );
+ $parserOptions->method( 'optionsHash' )->willReturn( '' );
+ $parserOptions->method( 'getUseParsoid' )->willReturn( true );
$parserOptions->method( 'getTargetLanguage' )
->willReturn( $this->getLanguageMock( $langCode ) );
yield 'ParserOptions for "ar" language' => [ $parserOptions, $langCode ];
diff --git a/tests/phpunit/integration/includes/Rest/Handler/RevisionHTMLHandlerTest.php b/tests/phpunit/integration/includes/Rest/Handler/RevisionHTMLHandlerTest.php
index ea90305e13f..df5ec801bf4 100644
--- a/tests/phpunit/integration/includes/Rest/Handler/RevisionHTMLHandlerTest.php
+++ b/tests/phpunit/integration/includes/Rest/Handler/RevisionHTMLHandlerTest.php
@@ -6,11 +6,11 @@ use DeferredUpdates;
use Exception;
use HashBagOStuff;
use MediaWiki\Config\ServiceOptions;
-use MediaWiki\Json\JsonCodec;
use MediaWiki\MainConfigNames;
use MediaWiki\MainConfigSchema;
use MediaWiki\Parser\ParserCacheFactory;
use MediaWiki\Parser\Parsoid\ParsoidOutputAccess;
+use MediaWiki\Parser\Parsoid\ParsoidParserFactory;
use MediaWiki\Rest\Handler\Helper\HtmlOutputRendererHelper;
use MediaWiki\Rest\Handler\Helper\PageRestHelperFactory;
use MediaWiki\Rest\Handler\Helper\RevisionContentHelper;
@@ -20,10 +20,8 @@ use MediaWiki\Rest\RequestData;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Utils\MWTimestamp;
use MediaWikiIntegrationTestCase;
-use NullStatsdDataFactory;
use Psr\Http\Message\StreamInterface;
-use Psr\Log\NullLogger;
-use WANObjectCache;
+use ReflectionClass;
use Wikimedia\Message\MessageValue;
use Wikimedia\Parsoid\Core\ClientError;
use Wikimedia\Parsoid\Core\ResourceLimitExceededException;
@@ -63,29 +61,15 @@ class RevisionHTMLHandlerTest extends MediaWikiIntegrationTestCase {
}
/**
- * @param ?Parsoid $parsoid
- *
* @return RevisionHTMLHandler
*/
- private function newHandler( ?Parsoid $parsoid = null ): RevisionHTMLHandler {
+ private function newHandler(): RevisionHTMLHandler {
$parserCacheFactoryOptions = new ServiceOptions( ParserCacheFactory::CONSTRUCTOR_OPTIONS, [
'CacheEpoch' => '20200202112233',
'OldRevisionParserCacheExpireTime' => 60 * 60,
] );
$services = $this->getServiceContainer();
- $parserCacheFactory = new ParserCacheFactory(
- $this->parserCacheBagOStuff,
- new WANObjectCache( [ 'cache' => $this->parserCacheBagOStuff, ] ),
- $this->createHookContainer(),
- new JsonCodec(),
- new NullStatsdDataFactory(),
- new NullLogger(),
- $parserCacheFactoryOptions,
- $services->getTitleFactory(),
- $services->getWikiPageFactory()
- );
-
$config = [
'RightsUrl' => 'https://example.com/rights',
'RightsText' => 'some rights',
@@ -99,17 +83,11 @@ class RevisionHTMLHandlerTest extends MediaWikiIntegrationTestCase {
$services->getMainConfig(),
[ 'ParsoidWikiID' => 'MyWiki' ]
),
- $parserCacheFactory,
+ $services->getParsoidParserFactory(),
+ $services->getParserOutputAccess(),
$services->getPageStore(),
$services->getRevisionLookup(),
- $services->getGlobalIdGenerator(),
- $services->getStatsdDataFactory(),
- $parsoid ?? new Parsoid(
- $services->get( 'ParsoidSiteConfig' ),
- $services->get( 'ParsoidDataAccess' )
- ),
$services->getParsoidSiteConfig(),
- $services->getParsoidPageConfigFactory(),
$services->getContentHandlerFactory()
);
@@ -286,12 +264,38 @@ class RevisionHTMLHandlerTest extends MediaWikiIntegrationTestCase {
[ 'pathParams' => [ 'id' => $revisions['first']->getId() ] ]
);
- $parsoid = $this->createNoOpMock( Parsoid::class, [ 'wikitext2html' ] );
- $parsoid->expects( $this->once() )
+ $services = $this->getServiceContainer();
+ $parsoidParser = $services->getParsoidParserFactory()->create();
+
+ // Mock Parsoid
+ $mockParsoid = $this->createNoOpMock( Parsoid::class, [ 'wikitext2html' ] );
+ $mockParsoid->expects( $this->once() )
->method( 'wikitext2html' )
->willThrowException( $parsoidException );
- $handler = $this->newHandler( $parsoid );
+ // Install it in the ParsoidParser object
+ $reflector = new ReflectionClass( 'MediaWiki\Parser\Parsoid\ParsoidParser' );
+ $prop = $reflector->getProperty( 'parsoid' );
+ $prop->setAccessible( true );
+ $prop->setValue( $parsoidParser, $mockParsoid );
+ $this->assertEquals( $prop->getValue( $parsoidParser ), $mockParsoid );
+
+ // Create a mock Parsoid factory that returns the ParsoidParser object
+ // with the mocked Parsoid object.
+ $mockParsoidParserFactory = $this->createNoOpMock( ParsoidParserFactory::class, [ 'create' ] );
+ $mockParsoidParserFactory->expects( $this->once() )
+ ->method( 'create' )
+ ->willReturn( $parsoidParser );
+
+ // Ensure WiktiextContentHandler has the mock ParsoidParserFactory
+ $wtHandler = $services->getContentHandlerFactory()->getContentHandler( 'wikitext' );
+ $reflector = new ReflectionClass( 'WikitextContentHandler' );
+ $prop = $reflector->getProperty( 'parsoidParserFactory' );
+ $prop->setAccessible( true );
+ $prop->setValue( $wtHandler, $mockParsoidParserFactory );
+ $this->assertEquals( $prop->getValue( $wtHandler ), $mockParsoidParserFactory );
+
+ $handler = $this->newHandler();
$this->expectExceptionObject( $expectedException );
$this->executeHandler( $handler, $request, [
'format' => 'html'
diff --git a/tests/phpunit/unit/includes/Rest/Handler/PageHandlerTestTrait.php b/tests/phpunit/unit/includes/Rest/Handler/PageHandlerTestTrait.php
index 59ec3c60ab1..5f49dd1c2a4 100644
--- a/tests/phpunit/unit/includes/Rest/Handler/PageHandlerTestTrait.php
+++ b/tests/phpunit/unit/includes/Rest/Handler/PageHandlerTestTrait.php
@@ -8,6 +8,8 @@ use MediaWiki\MainConfigNames;
use MediaWiki\MainConfigSchema;
use MediaWiki\Parser\ParserCacheFactory;
use MediaWiki\Parser\Parsoid\ParsoidOutputAccess;
+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;
@@ -61,11 +63,35 @@ trait PageHandlerTestTrait {
}
/**
- * @param Parsoid|MockObject|null $parsoid
- *
+ * @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( ?Parsoid $parsoid = null, ?RequestInterface $request = null ) {
+ public function newPageHtmlHandler( ?RequestInterface $request = null ) {
+ // ParserOutputAccess has a localCache which can return stale content.
+ // Resetting ensures that ParsoidCachePrewarmJob gets a fresh copy
+ // of ParserOutputAccess and ParsoidOutputAccess without these problems!
+ $this->resetServices();
+
$parserCacheFactoryOptions = new ServiceOptions( ParserCacheFactory::CONSTRUCTOR_OPTIONS, [
'CacheEpoch' => '20200202112233',
'OldRevisionParserCacheExpireTime' => 60 * 60,
@@ -97,17 +123,11 @@ trait PageHandlerTestTrait {
$services->getMainConfig(),
[ 'ParsoidWikiID' => 'MyWiki' ]
),
- $parserCacheFactory,
+ $services->getParsoidParserFactory(),
+ $services->getParserOutputAccess(),
$services->getPageStore(),
$services->getRevisionLookup(),
- $services->getGlobalIdGenerator(),
- $services->getStatsdDataFactory(),
- $parsoid ?? new Parsoid(
- $services->get( 'ParsoidSiteConfig' ),
- $services->get( 'ParsoidDataAccess' )
- ),
$services->getParsoidSiteConfig(),
- $services->getParsoidPageConfigFactory(),
$services->getContentHandlerFactory()
);