Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
66 / 66
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CompareParserCache
100.00% covered (success)
100.00%
66 / 66
100.00% covered (success)
100.00%
2 / 2
7
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
62 / 62
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 * @ingroup Maintenance
6 */
7
8// @codeCoverageIgnoreStart
9require_once __DIR__ . '/Maintenance.php';
10// @codeCoverageIgnoreEnd
11
12use MediaWiki\Maintenance\Maintenance;
13use MediaWiki\Title\Title;
14use Wikimedia\Diff\Diff;
15use Wikimedia\Diff\UnifiedDiffFormatter;
16
17/**
18 * @ingroup Maintenance
19 */
20class CompareParserCache extends Maintenance {
21    public function __construct() {
22        parent::__construct();
23        $this->addDescription( 'Parse random pages and compare output to cache.' );
24        $this->addOption( 'namespace', 'Page namespace number', true, true );
25        $this->addOption( 'maxpages', 'Number of pages to try', true, true );
26    }
27
28    public function execute() {
29        $pages = $this->getOption( 'maxpages' );
30
31        $dbr = $this->getReplicaDB();
32
33        $totalsec = 0.0;
34        $scanned = 0;
35        $withcache = 0;
36        $withdiff = 0;
37        $services = $this->getServiceContainer();
38        $parserCache = $services->getParserCache();
39        $renderer = $services->getRevisionRenderer();
40        $wikiPageFactory = $services->getWikiPageFactory();
41        while ( $pages-- > 0 ) {
42            $row = $dbr->newSelectQueryBuilder()
43                // @todo Title::selectFields() or Title::getQueryInfo() or something
44                ->select( [
45                    'page_namespace',
46                    'page_title',
47                    'page_id',
48                    'page_len',
49                    'page_is_redirect',
50                    'page_latest',
51                ] )
52                ->from( 'page' )
53                ->where( [
54                    'page_namespace' => $this->getOption( 'namespace' ),
55                    'page_is_redirect' => 0,
56                    $dbr->expr( 'page_random', '>=', wfRandom() ),
57                ] )
58                ->orderBy( 'page_random' )
59                ->caller( __METHOD__ )->fetchRow();
60
61            if ( !$row ) {
62                continue;
63            }
64            ++$scanned;
65
66            $title = Title::newFromRow( $row );
67            $page = $wikiPageFactory->newFromTitle( $title );
68            $revision = $page->getRevisionRecord();
69            $parserOptions = $page->makeParserOptions( 'canonical' );
70            $parserOutputOld = $parserCache->get( $page, $parserOptions );
71
72            if ( $parserOutputOld ) {
73                $t1 = microtime( true );
74                $parserOutputNew = $renderer->getRenderedRevision( $revision, $parserOptions )
75                    ->getRevisionParserOutput();
76
77                $sec = microtime( true ) - $t1;
78                $totalsec += $sec;
79
80                $this->output( "Parsed '{$title->getPrefixedText()}' in $sec seconds.\n" );
81
82                $this->output( "Found cache entry found for '{$title->getPrefixedText()}'..." );
83
84                $oldHtml = trim( preg_replace( '#<!-- .+-->#Us', '',
85                    $parserOutputOld->getContentHolderText() ) );
86                $newHtml = trim( preg_replace( '#<!-- .+-->#Us', '',
87                    $parserOutputNew->getContentHolderText() ) );
88                $diffs = new Diff( explode( "\n", $oldHtml ), explode( "\n", $newHtml ) );
89                $formatter = new UnifiedDiffFormatter();
90                $unifiedDiff = $formatter->format( $diffs );
91
92                if ( $unifiedDiff !== '' ) {
93                    $this->output( "differences found:\n\n$unifiedDiff\n\n" );
94                    ++$withdiff;
95                } else {
96                    $this->output( "No differences found.\n" );
97                }
98                ++$withcache;
99            } else {
100                $this->output( "No parser cache entry found for '{$title->getPrefixedText()}'.\n" );
101            }
102        }
103
104        $ave = $totalsec ? $totalsec / $scanned : 0;
105        $this->output( "Checked $scanned pages; $withcache had prior cache entries.\n" );
106        $this->output( "Pages with differences found: $withdiff\n" );
107        $this->output( "Average parse time: $ave sec\n" );
108    }
109}
110
111// @codeCoverageIgnoreStart
112$maintClass = CompareParserCache::class;
113require_once RUN_MAINTENANCE_IF_MAIN;
114// @codeCoverageIgnoreEnd