1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
<?php
use MediaWiki\Config\ServiceOptions;
use MediaWiki\MediaWikiServices;
use MediaWiki\OutputTransform\Stages\RenderDebugInfo;
use MediaWiki\Page\PageIdentity;
use MediaWiki\Page\PageIdentityValue;
use MediaWiki\Page\PageRecord;
use MediaWiki\Parser\ParserOptions;
use Psr\Log\NullLogger;
use Wikimedia\TestingAccessWrapper;
/**
* @group JobQueue
* @group Database
*
* @license GPL-2.0-or-later
*/
class ParsoidCachePrewarmJobTest extends MediaWikiIntegrationTestCase {
private const NON_JOB_QUEUE_EDIT = 'parsoid edit not executed by job queue';
private const JOB_QUEUE_EDIT = 'parsoid edit executed by job queue';
private function getPageIdentity( PageRecord $page ): PageIdentityValue {
return PageIdentityValue::localIdentity(
$page->getId(),
$page->getNamespace(),
$page->getDBkey()
);
}
private function getPageRecord( PageIdentity $page ): PageRecord {
return $this->getServiceContainer()->getPageStore()
->getPageByReference( $page );
}
/**
* @covers \ParsoidCachePrewarmJob::doParsoidCacheUpdate
* @covers \ParsoidCachePrewarmJob::newSpec
* @covers \ParsoidCachePrewarmJob::run
*/
public function testRun() {
$page = $this->getExistingTestPage( 'ParsoidPrewarmJob' )->toPageRecord();
$rev1 = $this->editPage( $page, self::NON_JOB_QUEUE_EDIT )->getNewRevision();
$parsoidPrewarmJob = new ParsoidCachePrewarmJob(
[ 'revId' => $rev1->getId(), 'pageId' => $page->getId() ],
$this->getServiceContainer()->getParserOutputAccess(),
$this->getServiceContainer()->getPageStore(),
$this->getServiceContainer()->getRevisionLookup(),
$this->getServiceContainer()->getParsoidSiteConfig()
);
// NOTE: calling ->run() will not run the job scheduled in the queue but will
// instead call doParsoidCacheUpdate() directly. Will run the job and assert
// below.
$execStatus = $parsoidPrewarmJob->run();
$this->assertTrue( $execStatus );
$popts = ParserOptions::newFromAnon();
$popts->setUseParsoid();
$parsoidOutput = $this->getServiceContainer()->getParserOutputAccess()->getCachedParserOutput(
$this->getPageRecord( $this->getPageIdentity( $page ) ),
$popts,
$rev1
);
// Ensure we have the parsoid output in parser cache as an HTML document
$this->assertStringContainsString( '<html', $parsoidOutput->getRawText() );
$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.
$this->resetServices();
$parsoidPrewarmJob = new ParsoidCachePrewarmJob(
[ 'revId' => $rev2->getId(), 'pageId' => $page->getId(), 'causeAction' => 'just for testing' ],
$this->getServiceContainer()->getParserOutputAccess(),
$this->getServiceContainer()->getPageStore(),
$this->getServiceContainer()->getRevisionLookup(),
$this->getServiceContainer()->getParsoidSiteConfig()
);
$jobQueueGroup = $this->getServiceContainer()->getJobQueueGroup();
$jobQueueGroup->get( $parsoidPrewarmJob->getType() )->delete();
$jobQueueGroup->push( $parsoidPrewarmJob );
// At this point, we have 1 job scheduled for this job type.
$this->assertSame( 1, $jobQueueGroup->getQueueSizes()['parsoidCachePrewarm'] );
// doParsoidCacheUpdate() now with a job queue instead of calling directly.
$this->runJobs( [ 'maxJobs' => 1 ], [ 'type' => 'parsoidCachePrewarm' ] );
// At this point, we have 0 jobs scheduled for this job type.
$this->assertSame( 0, $jobQueueGroup->getQueueSizes()['parsoidCachePrewarm'] );
$parsoidOutput = $this->getServiceContainer()->getParserOutputAccess()->getCachedParserOutput(
$this->getPageRecord( $this->getPageIdentity( $page ) ),
$popts,
$rev2
);
// Ensure we have the parsoid output in parser cache as an HTML document
$this->assertStringContainsString( '<html', $parsoidOutput->getRawText() );
$this->assertStringContainsString( self::JOB_QUEUE_EDIT, $parsoidOutput->getRawText() );
$services = MediaWikiServices::getInstance();
$servicesOptions = new ServiceOptions(
RenderDebugInfo::CONSTRUCTOR_OPTIONS, $services->getMainConfig()
);
$rdi = TestingAccessWrapper::newFromObject(
new RenderDebugInfo( $servicesOptions, new NullLogger(), $services->getHookContainer() )
);
// Check that the causeAction was looped through as the render reason
$this->assertStringContainsString(
'triggered because: just for testing',
$rdi->debugInfo( $parsoidOutput )
);
}
/**
* @covers \ParsoidCachePrewarmJob::newSpec
*/
public function testEnqueueSpec() {
$page = $this->getExistingTestPage( 'ParsoidPrewarmJob' )->toPageRecord();
$rev1 = $this->editPage( $page, self::NON_JOB_QUEUE_EDIT )->getNewRevision();
$parsoidPrewarmSpec = ParsoidCachePrewarmJob::newSpec(
$rev1->getId(), $page,
);
$this->assertSame( 'parsoidCachePrewarm', $parsoidPrewarmSpec->getType(), 'getType' );
$dedupeInfo = $parsoidPrewarmSpec->getDeduplicationInfo();
$this->assertTrue( $dedupeInfo['params']['rootJobIsSelf'] );
$this->assertSame( $page->getTouched(), $dedupeInfo['params']['page_touched'] );
$this->assertSame( $rev1->getId(), $dedupeInfo['params']['revId'] );
$this->assertSame( $page->getId(), $dedupeInfo['params']['pageId'] );
$jobQueueGroup = $this->getServiceContainer()->getJobQueueGroup();
$jobQueueGroup->get( $parsoidPrewarmSpec->getType() )->delete();
$jobQueueGroup->push( $parsoidPrewarmSpec );
// At this point, we have 1 job scheduled for this job type.
$this->assertSame( 1, $jobQueueGroup->getQueueSizes()['parsoidCachePrewarm'] );
// Push again times, deduplication should apply!
$jobQueueGroup->push( $parsoidPrewarmSpec );
$jobQueueGroup->push( $parsoidPrewarmSpec );
// We should still have just 1 job scheduled for this job type.
$this->assertSame( 1, $jobQueueGroup->getQueueSizes()['parsoidCachePrewarm'] );
}
}
|