File: ParsoidCachePrewarmJobTest.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (159 lines) | stat: -rw-r--r-- 6,115 bytes parent folder | download
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'] );
	}

}