Addshore has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/368312 )
Change subject: WB: Move injection of RC records to a separate job. ...................................................................... WB: Move injection of RC records to a separate job. Backport for 1.30.0-wmf.10 from https://gerrit.wikimedia.org/r/367328 Bug: T171370 Change-Id: I01776073e8a9fbf440e4030f3493b209beef93cb --- M composer.lock M extensions/Wikibase/client/WikibaseClient.php A extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php M extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php M extensions/Wikibase/client/includes/WikibaseClient.php A extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php M extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php M vendor/composer/autoload_classmap.php M vendor/composer/autoload_static.php M vendor/composer/installed.json 10 files changed, 690 insertions(+), 196 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata refs/changes/12/368312/1 diff --git a/composer.lock b/composer.lock index 29b06e4..bd07d27 100644 --- a/composer.lock +++ b/composer.lock @@ -1026,7 +1026,7 @@ "support": { "issues": "https://phabricator.wikimedia.org/project/profile/1202/" }, - "time": "2017-07-21T19:59:47+00:00" + "time": "2017-07-21T11:21:34+00:00" }, { "name": "wikibase/data-model", @@ -1484,12 +1484,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "48684cef3f4fb79d517a247ddea72f2e4883d07b" + "reference": "467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/48684cef3f4fb79d517a247ddea72f2e4883d07b", - "reference": "48684cef3f4fb79d517a247ddea72f2e4883d07b", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4", + "reference": "467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4", "shasum": "" }, "require": { @@ -1565,7 +1565,7 @@ "wikibaserepo", "wikidata" ], - "time": "2017-07-24T00:47:16+00:00" + "time": "2017-07-27T17:56:33+00:00" }, { "name": "wikibase/wikimedia-badges", diff --git a/extensions/Wikibase/client/WikibaseClient.php b/extensions/Wikibase/client/WikibaseClient.php index fd0fe88..012905d 100644 --- a/extensions/Wikibase/client/WikibaseClient.php +++ b/extensions/Wikibase/client/WikibaseClient.php @@ -182,6 +182,24 @@ // job classes $wgJobClasses['wikibase-addUsagesForPage'] = Wikibase\Client\Store\AddUsagesForPageJob::class; $wgJobClasses['ChangeNotification'] = Wikibase\Client\ChangeNotificationJob::class; + $wgJobClasses['wikibase-InjectRCRecords'] = function ( Title $unused, array $params ) { + $mwServices = MediaWiki\MediaWikiServices::getInstance(); + $wbServices = Wikibase\Client\WikibaseClient::getDefaultInstance(); + + $job = new Wikibase\Client\Changes\InjectRCRecordsJob( + $mwServices->getDBLoadBalancerFactory(), + $wbServices->getStore()->getEntityChangeLookup(), + $wbServices->getRecentChangeFactory(), + $params + ); + + $job->setRecentChangesDuplicateDetector( $wbServices->getStore()->getRecentChangesDuplicateDetector() ); + + $job->setLogger( MediaWiki\Logger\LoggerFactory::getInstance( 'wikibase.client.pageupdates' ) ); + $job->setStats( $mwServices->getStatsdDataFactory() ); + + return $job; + }; // api modules $wgAPIMetaModules['wikibase'] = array( @@ -226,8 +244,8 @@ $wgAPIPropModules['wbentityusage'] = [ 'class' => Wikibase\Client\Api\ApiPropsEntityUsage::class, 'factory' => function ( ApiQuery $query, $moduleName ) { - $repoLinker = \Wikibase\Client\WikibaseClient::getDefaultInstance()->newRepoLinker(); - return new \Wikibase\Client\Api\ApiPropsEntityUsage( + $repoLinker = Wikibase\Client\WikibaseClient::getDefaultInstance()->newRepoLinker(); + return new Wikibase\Client\Api\ApiPropsEntityUsage( $query, $moduleName, $repoLinker diff --git a/extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php b/extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php new file mode 100644 index 0000000..54c4781 --- /dev/null +++ b/extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php @@ -0,0 +1,272 @@ +<?php + +namespace Wikibase\Client\Changes; + +use Job; +use JobSpecification; +use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Title; +use Wikibase\Client\Changes\ChangeHandler; +use Wikibase\Client\RecentChanges\RecentChangeFactory; +use Wikibase\Client\RecentChanges\RecentChangesDuplicateDetector; +use Wikibase\Client\Store\TitleFactory; +use Wikibase\Client\WikibaseClient; +use Wikibase\EntityChange; +use Wikibase\Lib\Store\Sql\EntityChangeLookup; +use Wikimedia\Assert\Assert; +use Wikimedia\Rdbms\LBFactory; + +/** + * Job for injecting RecentChange records representing changes on the Wikibase repository. + * + * @see docs/change-propagation.wiki for an overview of the change propagation mechanism. + * + * @license GPL-2.0+ + * @author Daniel Kinzler + */ +class InjectRCRecordsJob extends Job { + + /** + * @var LBFactory + */ + private $lbFactory; + + /** + * @var EntityChangeLookup + */ + private $changeLookup; + + /** + * @var RecentChangeFactory + */ + private $rcFactory; + + /** + * @var RecentChangesDuplicateDetector|null + */ + private $rcDuplicateDetector = null; + + /** + * @var TitleFactory + */ + private $titleFactory; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var StatsdDataFactoryInterface|null + */ + private $stats = null; + + /** + * @var int Batch size for database operations + */ + private $dbBatchSize = 100; + + /** + * @param Title[] $titles + * @param EntityChange $change + * + * @return JobSpecification + */ + public static function makeJobSpecification( array $titles, EntityChange $change ) { + $pages = []; + + foreach ( $titles as $t ) { + $id = $t->getArticleId(); + $pages[$id] = [ $t->getNamespace(), $t->getDBkey() ]; + } + + $params = [ + 'change' => $change->getId(), + 'pages' => $pages + ]; + + return new JobSpecification( + 'wikibase-InjectRCRecords', + $params + ); + + } + + /** + * Constructs an InjectRCRecordsJob for injecting a change into the recentchanges feed + * for the given pages. + * + * @param LBFactory $lbFactory + * @param EntityChangeLookup $changeLookup + * @param RecentChangeFactory $rcFactory + * @param array $params Needs to have two keys: "change": the id of the change, + * "pages": array of pages, represented as $pageId => [ $namespace, $dbKey ]. + */ + public function __construct( + LBFactory $lbFactory, + EntityChangeLookup $changeLookup, + RecentChangeFactory $rcFactory, + array $params + ) { + $title = Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __CLASS__ ); + parent::__construct( 'wikibase-InjectRCRecords', $title, $params ); + + Assert::parameter( + isset( $params['change'] ), + '$params', + '$params[\'change\'] not set.' + ); + Assert::parameter( + isset( $params['pages'] ), + '$params', + '$params[\'pages\'] not set.' + ); + Assert::parameterElementType( + 'array', + $params['pages'], + '$params[\'pages\']' + ); + + $this->lbFactory = $lbFactory; + $this->changeLookup = $changeLookup; + $this->rcFactory = $rcFactory; + + $this->titleFactory = new TitleFactory(); + $this->logger = new NullLogger(); + } + + /** + * @param RecentChangesDuplicateDetector $rcDuplicateDetector + */ + public function setRecentChangesDuplicateDetector( RecentChangesDuplicateDetector $rcDuplicateDetector ) { + $this->rcDuplicateDetector = $rcDuplicateDetector; + } + + /** + * @param TitleFactory $titleFactory + */ + public function setTitleFactory( TitleFactory $titleFactory ) { + $this->titleFactory = $titleFactory; + } + + /** + * @param LoggerInterface $logger + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + + /** + * @param StatsdDataFactoryInterface $stats + */ + public function setStats( StatsdDataFactoryInterface $stats ) { + $this->stats = $stats; + } + + /** + * @param int $dbBatchSize + */ + public function setDbBatchSize( $dbBatchSize ) { + Assert::parameterType( 'integer', $dbBatchSize, '$dbBatchSize' ); + $this->dbBatchSize = $dbBatchSize; + } + + /** + * Returns the change that should be processed. + * + * EntityChange objects are loaded using a EntityChangeLookup. + * + * @return EntityChange|null the change to process (or none). + */ + private function getChange() { + $params = $this->getParams(); + $changeId = $params['change']; + + $this->logger->debug( __FUNCTION__ . ": loading change $changeId." ); + + $changes = $this->changeLookup->loadByChangeIds( [ $changeId ] ); + + $change = reset( $changes ); + + if ( !$change ) { + $this->logger->error( __FUNCTION__ . ": failed to load change $changeId." ); + } + + return $change; + } + + /** + * Returns the list of Titles to inject RC entries for. + * + * @return Title[] + */ + private function getTitles() { + $params = $this->getParams(); + $pages = $params['pages']; + + $titles = []; + + foreach ( $pages as $pageId => list( $namespace, $dbKey ) ) { + $titles[] = $this->titleFactory->makeTitle( $namespace, $dbKey ); + } + + return $titles; + } + + /** + * @return bool success + */ + public function run() { + $change = $this->getChange(); + $titles = $this->getTitles(); + + if ( !$change || $titles === [] ) { + return false; + } + + $rcAttribs = $this->rcFactory->prepareChangeAttributes( $change ); + + $c = 0; + $trxToken = $this->lbFactory->getEmptyTransactionTicket( __METHOD__ ); + + foreach ( $titles as $title ) { + if ( !$title->exists() ) { + continue; + } + + $rc = $this->rcFactory->newRecentChange( $change, $title, $rcAttribs ); + + if ( $this->rcDuplicateDetector + && $this->rcDuplicateDetector->changeExists( $rc ) + ) { + $this->logger->debug( __FUNCTION__ . ": skipping duplicate RC entry for " . $title->getFullText() ); + } else { + $this->logger->debug( __FUNCTION__ . ": saving RC entry for " . $title->getFullText() ); + $rc->save(); + } + + if ( ++$c >= $this->dbBatchSize ) { + $this->lbFactory->commitAndWaitForReplication( __METHOD__, $trxToken ); + $trxToken = $this->lbFactory->getEmptyTransactionTicket( __METHOD__ ); + $c = 0; + } + } + + if ( $c > 0 ) { + $this->lbFactory->commitAndWaitForReplication( __METHOD__, $trxToken ); + } + + $this->incrementStats( 'InjectRCRecords.run.titles', count( $titles ) ); + + return true; + } + + private function incrementStats( $updateType, $delta ) { + if ( $this->stats ) { + $this->stats->updateCount( 'wikibase.client.pageupdates.' . $updateType, $delta ); + } + } + +} diff --git a/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php b/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php index 6fd4f03..3ab41b1 100644 --- a/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php +++ b/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php @@ -155,40 +155,16 @@ * @param EntityChange $change */ public function injectRCRecords( array $titles, EntityChange $change ) { - $rcAttribs = $this->recentChangeFactory->prepareChangeAttributes( $change ); - - $c = 0; - $trxToken = $this->LBFactory->getEmptyTransactionTicket( __METHOD__ ); - - // TODO: do this via the job queue, in batches, see T107722 - foreach ( $titles as $title ) { - if ( !$title->exists() ) { - continue; - } - - $rc = $this->recentChangeFactory->newRecentChange( $change, $title, $rcAttribs ); - - if ( $this->recentChangesDuplicateDetector - && $this->recentChangesDuplicateDetector->changeExists( $rc ) - ) { - wfDebugLog( __CLASS__, __FUNCTION__ . ": skipping duplicate RC entry for " . $title->getFullText() ); - } else { - wfDebugLog( __CLASS__, __FUNCTION__ . ": saving RC entry for " . $title->getFullText() ); - $rc->save(); - } - - if ( ++$c >= $this->dbBatchSize ) { - $this->LBFactory->commitAndWaitForReplication( __METHOD__, $trxToken ); - $trxToken = $this->LBFactory->getEmptyTransactionTicket( __METHOD__ ); - $c = 0; - } + if ( $titles === [] ) { + return; } - if ( $c > 0 ) { - $this->LBFactory->commitAndWaitForReplication( __METHOD__, $trxToken ); - } + $jobSpec = InjectRCRecordsJob::makeJobSpecification( $titles, $change ); - $this->incrementStats( 'InjectRCRecords', count( $titles ) ); + $this->jobQueueGroup->lazyPush( $jobSpec ); + + $this->incrementStats( 'InjectRCRecords.jobs', 1 ); + $this->incrementStats( 'InjectRCRecords.titles', count( $titles ) ); } } diff --git a/extensions/Wikibase/client/includes/WikibaseClient.php b/extensions/Wikibase/client/includes/WikibaseClient.php index ddc6dad..6b2d353 100644 --- a/extensions/Wikibase/client/includes/WikibaseClient.php +++ b/extensions/Wikibase/client/includes/WikibaseClient.php @@ -1186,7 +1186,7 @@ /** * @return RecentChangeFactory */ - private function getRecentChangeFactory() { + public function getRecentChangeFactory() { return new RecentChangeFactory( $this->getContentLanguage(), new SiteLinkCommentCreator( diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php new file mode 100644 index 0000000..e182b76 --- /dev/null +++ b/extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php @@ -0,0 +1,236 @@ +<?php + +namespace Wikibase\Client\Tests\Changes; + +use PHPUnit_Framework_MockObject_MockObject; +use RecentChange; +use Title; +use Wikibase\Client\Changes\InjectRCRecordsJob; +use Wikibase\Client\RecentChanges\RecentChangeFactory; +use Wikibase\Client\RecentChanges\RecentChangesDuplicateDetector; +use Wikibase\Client\Store\TitleFactory; +use Wikibase\EntityChange; +use Wikibase\Lib\Store\Sql\EntityChangeLookup; +use Wikimedia\Rdbms\LBFactory; + +/** + * @covers Wikibase\Client\Changes\InjectRCRecordsJob + * + * @group Wikibase + * @group WikibaseClient + * @group WikibaseChange + * + * @group Database + * + * @license GPL-2.0+ + * @author Daniel Kinzler + */ +class InjectRCRecordsJobTest extends \MediaWikiTestCase { + + /** + * @return RecentChangeFactory|PHPUnit_Framework_MockObject_MockObject + */ + private function getRCFactoryMock() { + $rcFactory = $this->getMockBuilder( RecentChangeFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + + $rcFactory->expects( $this->any() ) + ->method( 'prepareChangeAttributes' ) + ->will( $this->returnValue( [] ) ); + + return $rcFactory; + } + + /** + * @param EntityChange $change + * + * @return PHPUnit_Framework_MockObject_MockObject|EntityChangeLookup + */ + private function getEntityChangeLookupMock( EntityChange $change ) { + $changeLookup = $this->getMockBuilder( EntityChangeLookup::class ) + ->disableOriginalConstructor() + ->getMock(); + + $changeLookup->expects( $this->any() ) + ->method( 'loadByChangeIds' ) + ->with( [ $change->getId() ] ) + ->will( $this->returnValue( [ $change ] ) ); + + return $changeLookup; + } + + /** + * @return RecentChangesDuplicateDetector|PHPUnit_Framework_MockObject_MockObject + */ + private function getRCDupeDetectorMock() { + $rcDupeDetector = $this->getMockBuilder( RecentChangesDuplicateDetector::class ) + ->disableOriginalConstructor() + ->getMock(); + + return $rcDupeDetector; + } + + /** + * @return TitleFactory|PHPUnit_Framework_MockObject_MockObject + */ + private function getTitleFactoryMock() { + $titleFactory = $this->getMock( TitleFactory::class ); + + $id = 200; + $titleFactory->expects( $this->any() ) + ->method( 'makeTitle' ) + ->will( $this->returnCallback( function( $ns, $text ) use ( &$id ) { + return $this->getTitleMock( $text, $id++ ); + } ) ); + + return $titleFactory; + } + + /** + * @param string $text + * @param int $id + * + * @return Title|PHPUnit_Framework_MockObject_MockObject + */ + private function getTitleMock( $text, $id = 23 ) { + $title = $this->getMockBuilder( Title::class ) + ->disableOriginalConstructor() + ->getMock(); + + $title->expects( $this->any() ) + ->method( 'getArticleID' ) + ->will( $this->returnValue( $id ) ); + + $title->expects( $this->any() ) + ->method( 'exists' ) + ->will( $this->returnValue( true ) ); + + $title->expects( $this->any() ) + ->method( 'getDBkey' ) + ->will( $this->returnValue( $text ) ); + + $title->expects( $this->any() ) + ->method( 'getNamespace' ) + ->will( $this->returnValue( 0 ) ); + + return $title; + } + + /** + * @param int $id + * + * @return PHPUnit_Framework_MockObject_MockObject|EntityChange + */ + private function getEntityChangeMock( $id = 77 ) { + $change = $this->getMockBuilder( EntityChange::class ) + ->disableOriginalConstructor() + ->getMock(); + + $change->expects( $this->any() ) + ->method( 'getId' ) + ->will( $this->returnValue( $id ) ); + + return $change; + } + + /** + * @return RecentChange|PHPUnit_Framework_MockObject_MockObject + */ + private function getRecentChangeMock() { + $change = $this->getMockBuilder( RecentChange::class ) + ->disableOriginalConstructor() + ->getMock(); + + return $change; + } + + /** + * @return LBFactory|PHPUnit_Framework_MockObject_MockObject + */ + private function getLBFactoryMock() { + $LBFactory = $this->getMockBuilder( LBFactory::class ) + ->disableOriginalConstructor() + ->getMock(); + + return $LBFactory; + } + + public function testRun() { + $title = $this->getTitleMock( 'Foo', 21 ); + $change = $this->getEntityChangeMock( 17 ); + $rc = $this->getRecentChangeMock(); + + $changeLookup = $this->getEntityChangeLookupMock( $change ); + + $rcFactory = $this->getRCFactoryMock(); + + $rcFactory->expects( $this->once() ) + ->method( 'newRecentChange' ) + ->with( $change, $title, [] ) + ->will( $this->returnValue( $rc ) ); + + $rcDupeDetector = $this->getRCDupeDetectorMock(); + + $rcDupeDetector->expects( $this->once() ) + ->method( 'changeExists' ) + ->with( $rc ); + + $params = [ + 'change' => $change->getId(), + 'pages' => [ + 21 => [ 0, 'Foo' ] + ] + ]; + + $job = new InjectRCRecordsJob( + $this->getLBFactoryMock(), + $changeLookup, + $rcFactory, + $params + ); + + $job->setTitleFactory( $this->getTitleFactoryMock() ); + $job->setRecentChangesDuplicateDetector( $rcDupeDetector ); + + $job->run(); + } + + public function testRun_batch() { + $change = $this->getEntityChangeMock(); + $rc = $this->getRecentChangeMock(); + $changeLookup = $this->getEntityChangeLookupMock( $change ); + + $rcFactory = $this->getRCFactoryMock(); + + $rcFactory->expects( $this->any() ) + ->method( 'newRecentChange' ) + ->will( $this->returnValue( $rc ) ); + + $lbFactory = $this->getLBFactoryMock(); + $lbFactory->expects( $this->exactly( 2 ) ) + ->method( 'commitAndWaitForReplication' ); + + $params = [ + 'change' => $change->getId(), + 'pages' => [ + 21 => [ 0, 'Foo' ], + 22 => [ 0, 'Bar' ], + 23 => [ 0, 'Cuzz' ], + ] + ]; + + $job = new InjectRCRecordsJob( + $lbFactory, + $changeLookup, + $rcFactory, + $params + ); + + $job->setTitleFactory( $this->getTitleFactoryMock() ); + $job->setDbBatchSize( 2 ); + + $job->run(); + } + +} diff --git a/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php b/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php index f73f61f..2be8d28 100644 --- a/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php +++ b/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php @@ -2,9 +2,10 @@ namespace Wikibase\Client\Tests\Changes; +use IJobSpecification; use Job; use JobQueueGroup; -use RecentChange; +use PHPUnit_Framework_MockObject_MockObject; use RefreshLinksJob; use Title; use Wikibase\Client\Changes\WikiPageUpdater; @@ -28,7 +29,7 @@ class WikiPageUpdaterTest extends \MediaWikiTestCase { /** - * @return JobQueueGroup + * @return JobQueueGroup|PHPUnit_Framework_MockObject_MockObject */ private function getJobQueueGroupMock() { $jobQueueGroup = $this->getMockBuilder( JobQueueGroup::class ) @@ -66,17 +67,18 @@ /** * @param string $text + * @param int $id * - * @return Title + * @return Title|PHPUnit_Framework_MockObject_MockObject */ - private function getTitleMock( $text ) { + private function getTitleMock( $text, $id = 23 ) { $title = $this->getMockBuilder( Title::class ) ->disableOriginalConstructor() ->getMock(); $title->expects( $this->any() ) ->method( 'getArticleID' ) - ->will( $this->returnValue( 23 ) ); + ->will( $this->returnValue( $id ) ); $title->expects( $this->any() ) ->method( 'exists' ) @@ -86,27 +88,38 @@ ->method( 'getPrefixedDBkey' ) ->will( $this->returnValue( $text ) ); + $title->expects( $this->any() ) + ->method( 'getDBkey' ) + ->will( $this->returnValue( $text ) ); + + $title->expects( $this->any() ) + ->method( 'getText' ) + ->will( $this->returnValue( $text ) ); + + $title->expects( $this->any() ) + ->method( 'getNamespace' ) + ->will( $this->returnValue( 0 ) ); + + $title->expects( $this->any() ) + ->method( 'getNsText' ) + ->will( $this->returnValue( '' ) ); + return $title; } /** - * @return EntityChange + * @param int $id + * + * @return PHPUnit_Framework_MockObject_MockObject|EntityChange */ - private function getEntityChangeMock() { + private function getEntityChangeMock( $id = 77 ) { $change = $this->getMockBuilder( EntityChange::class ) ->disableOriginalConstructor() ->getMock(); - return $change; - } - - /** - * @return RecentChange - */ - private function getRecentChangeMock() { - $change = $this->getMockBuilder( RecentChange::class ) - ->disableOriginalConstructor() - ->getMock(); + $change->expects( $this->any() ) + ->method( 'getId' ) + ->will( $this->returnValue( $id ) ); return $change; } @@ -196,68 +209,43 @@ } public function testInjectRCRecords() { - $title = $this->getTitleMock( 'Foo' ); + $titleFoo = $this->getTitleMock( 'Foo', 21 ); + $titleBar = $this->getTitleMock( 'Bar', 22 ); + $titleCuzz = $this->getTitleMock( 'Cuzz', 23 ); + $change = $this->getEntityChangeMock(); - $rc = $this->getRecentChangeMock(); - $rcFactory = $this->getRCFactoryMock(); + $jobQueueGroup = $this->getJobQueueGroupMock(); - $rcFactory->expects( $this->once() ) - ->method( 'newRecentChange' ) - ->with( $change, $title, [] ) - ->will( $this->returnValue( $rc ) ); + $pages = []; + $jobQueueGroup->expects( $this->atLeastOnce() ) + ->method( 'lazyPush' ) + ->will( $this->returnCallback( function( IJobSpecification $job ) use ( &$pages, $change ) { + $params = $job->getParams(); - $rcDupeDetector = $this->getRCDupeDetectorMock(); + $this->assertArrayHasKey( 'change', $params, '$params["change"]' ); + $this->assertArrayHasKey( 'pages', $params, '$params["pages"]' ); - $rcDupeDetector->expects( $this->once() ) - ->method( 'changeExists' ) - ->with( $rc ); + $this->assertSame( $change->getId(), $params["change"] ); + + $pages += $params['pages']; // addition uses keys, array_merge does not + } ) ); $updater = new WikiPageUpdater( - $this->getJobQueueGroupMock(), - $rcFactory, + $jobQueueGroup, + $this->getRCFactoryMock(), $this->getLBFactoryMock(), - $rcDupeDetector + $this->getRCDupeDetectorMock() ); $updater->injectRCRecords( [ - $title + $titleFoo, $titleBar, $titleCuzz, ], $change ); - } - public function testInjectRCRecords_batch() { - $titleFoo = $this->getTitleMock( 'Foo' ); - $titleBar = $this->getTitleMock( 'Bar' ); - $titleCuzz = $this->getTitleMock( 'Cuzz' ); - - $change = $this->getEntityChangeMock(); - $rc = $this->getRecentChangeMock(); - - $rcFactory = $this->getRCFactoryMock(); - - $rcFactory->expects( $this->any() ) - ->method( 'newRecentChange' ) - ->will( $this->returnValue( $rc ) ); - - $rcDupeDetector = $this->getRCDupeDetectorMock(); - - $lbFactory = $this->getLBFactoryMock(); - $lbFactory->expects( $this->exactly( 2 ) ) - ->method( 'commitAndWaitForReplication' ); - - $updater = new WikiPageUpdater( - $this->getJobQueueGroupMock(), - $rcFactory, - $lbFactory, - $rcDupeDetector - ); - - $updater->setDbBatchSize( 2 ); - - $updater->injectRCRecords( - [ $titleFoo, $titleBar, $titleCuzz ], - $change - ); + $this->assertEquals( [ 21, 22, 23 ], array_keys( $pages ) ); + $this->assertEquals( [ 0, 'Foo' ], $pages[21], '$pages[21]' ); + $this->assertEquals( [ 0, 'Bar' ], $pages[22], '$pages[22]' ); + $this->assertEquals( [ 0, 'Cuzz' ], $pages[23], '$pages[23]' ); } } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index e55d96f..37540bf 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -326,6 +326,7 @@ 'Wikibase\\Client\\Changes\\AffectedPagesFinder' => $baseDir . '/extensions/Wikibase/client/includes/Changes/AffectedPagesFinder.php', 'Wikibase\\Client\\Changes\\ChangeHandler' => $baseDir . '/extensions/Wikibase/client/includes/Changes/ChangeHandler.php', 'Wikibase\\Client\\Changes\\ChangeRunCoalescer' => $baseDir . '/extensions/Wikibase/client/includes/Changes/ChangeRunCoalescer.php', + 'Wikibase\\Client\\Changes\\InjectRCRecordsJob' => $baseDir . '/extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php', 'Wikibase\\Client\\Changes\\PageUpdater' => $baseDir . '/extensions/Wikibase/client/includes/Changes/PageUpdater.php', 'Wikibase\\Client\\Changes\\WikiPageUpdater' => $baseDir . '/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php', 'Wikibase\\Client\\DataAccess\\ClientSiteLinkTitleLookup' => $baseDir . '/extensions/Wikibase/client/includes/DataAccess/ClientSiteLinkTitleLookup.php', @@ -406,6 +407,7 @@ 'Wikibase\\Client\\Tests\\Changes\\AffectedPagesFinderTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/AffectedPagesFinderTest.php', 'Wikibase\\Client\\Tests\\Changes\\ChangeHandlerTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/ChangeHandlerTest.php', 'Wikibase\\Client\\Tests\\Changes\\ChangeRunCoalescerTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/ChangeRunCoalescerTest.php', + 'Wikibase\\Client\\Tests\\Changes\\InjectRCRecordsJobTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php', 'Wikibase\\Client\\Tests\\Changes\\MockPageUpdater' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/MockPageUpdater.php', 'Wikibase\\Client\\Tests\\Changes\\WikiPageUpdaterTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php', 'Wikibase\\Client\\Tests\\ClientParserOutputDataUpdaterTest' => $baseDir . '/extensions/Wikibase/client/tests/phpunit/includes/ClientParserOutputDataUpdaterTest.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index e85093b..c5c6ccf 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -618,6 +618,7 @@ 'Wikibase\\Client\\Changes\\AffectedPagesFinder' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/AffectedPagesFinder.php', 'Wikibase\\Client\\Changes\\ChangeHandler' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/ChangeHandler.php', 'Wikibase\\Client\\Changes\\ChangeRunCoalescer' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/ChangeRunCoalescer.php', + 'Wikibase\\Client\\Changes\\InjectRCRecordsJob' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/InjectRCRecordsJob.php', 'Wikibase\\Client\\Changes\\PageUpdater' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/PageUpdater.php', 'Wikibase\\Client\\Changes\\WikiPageUpdater' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/Changes/WikiPageUpdater.php', 'Wikibase\\Client\\DataAccess\\ClientSiteLinkTitleLookup' => __DIR__ . '/../..' . '/extensions/Wikibase/client/includes/DataAccess/ClientSiteLinkTitleLookup.php', @@ -698,6 +699,7 @@ 'Wikibase\\Client\\Tests\\Changes\\AffectedPagesFinderTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/AffectedPagesFinderTest.php', 'Wikibase\\Client\\Tests\\Changes\\ChangeHandlerTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/ChangeHandlerTest.php', 'Wikibase\\Client\\Tests\\Changes\\ChangeRunCoalescerTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/ChangeRunCoalescerTest.php', + 'Wikibase\\Client\\Tests\\Changes\\InjectRCRecordsJobTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php', 'Wikibase\\Client\\Tests\\Changes\\MockPageUpdater' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/MockPageUpdater.php', 'Wikibase\\Client\\Tests\\Changes\\WikiPageUpdaterTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php', 'Wikibase\\Client\\Tests\\ClientParserOutputDataUpdaterTest' => __DIR__ . '/../..' . '/extensions/Wikibase/client/tests/phpunit/includes/ClientParserOutputDataUpdaterTest.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index b03f473..3d8229d 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1617,97 +1617,6 @@ } }, { - "name": "wikibase/wikibase", - "version": "dev-wmf/1.30.0-wmf.10", - "version_normalized": "dev-wmf/1.30.0-wmf.10", - "source": { - "type": "git", - "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "48684cef3f4fb79d517a247ddea72f2e4883d07b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/48684cef3f4fb79d517a247ddea72f2e4883d07b", - "reference": "48684cef3f4fb79d517a247ddea72f2e4883d07b", - "shasum": "" - }, - "require": { - "data-values/common": "^0.3.0", - "data-values/data-types": "^1.0.0", - "data-values/data-values": "^1.0.0", - "data-values/geo": "^2.0.1", - "data-values/interfaces": "^0.2.0|^0.1.5", - "data-values/javascript": "^0.8.3", - "data-values/number": "^0.8.3", - "data-values/serialization": "^1.2.1", - "data-values/time": "^0.8.4", - "data-values/value-view": "^0.19.2", - "diff/diff": "^2.0.0", - "php": ">=5.5.9", - "wikibase/data-model": "^7.0.0", - "wikibase/data-model-javascript": "^3.0.1", - "wikibase/data-model-serialization": "^2.1.0", - "wikibase/data-model-services": "^3.7.0", - "wikibase/internal-serialization": "^2.2.0", - "wikibase/javascript-api": "^2.2.2", - "wikibase/serialization-javascript": "^2.0.8", - "wikimedia/purtle": "^1.0.3" - }, - "conflict": { - "mediawiki/mediawiki": "<1.25" - }, - "require-dev": { - "jakub-onderka/php-console-highlighter": "0.3.2", - "jakub-onderka/php-parallel-lint": ">=0.3 <0.10", - "wikibase/wikibase-codesniffer": "^0.1.0" - }, - "time": "2017-07-24T00:47:16+00:00", - "type": "mediawiki-extension", - "installation-source": "dist", - "autoload": { - "classmap": [ - "client/WikibaseClient.hooks.php", - "client/tests/phpunit/MockClientStore.php", - "lib/includes/", - "lib/WikibaseLib.hooks.php", - "lib/maintenance/", - "repo/includes/", - "repo/maintenance/", - "repo/Wikibase.hooks.php" - ], - "psr-4": { - "Wikibase\\Client\\": "client/includes", - "Wikibase\\Client\\Tests\\": "client/tests/phpunit/includes", - "Wikibase\\DataAccess\\": "data-access/src", - "Wikibase\\DataAccess\\Tests\\": "data-access/tests/phpunit", - "Wikibase\\Lib\\": "lib/includes", - "Wikibase\\Lib\\Tests\\": "lib/tests/phpunit", - "Wikibase\\Repo\\": "repo/includes", - "Wikibase\\Repo\\Tests\\": "repo/tests/phpunit/includes", - "Wikibase\\View\\": "view/src", - "Wikibase\\View\\Tests\\": "view/tests/phpunit" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "The Wikidata team" - } - ], - "description": "Structured data repository for MediaWiki", - "homepage": "http://wikiba.se", - "keywords": [ - "wikibase", - "wikibaseclient", - "wikibaselib", - "wikibaserepo", - "wikidata" - ] - }, - { "name": "wikibase/constraints", "version": "dev-wmf/1.30.0-wmf.10", "version_normalized": "dev-wmf/1.30.0-wmf.10", @@ -1777,5 +1686,96 @@ "support": { "issues": "https://phabricator.wikimedia.org/project/profile/1202/" } + }, + { + "name": "wikibase/wikibase", + "version": "dev-wmf/1.30.0-wmf.10", + "version_normalized": "dev-wmf/1.30.0-wmf.10", + "source": { + "type": "git", + "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", + "reference": "467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4", + "reference": "467e1cd2ddc0073c6ff91eeab42c4eae4386ecf4", + "shasum": "" + }, + "require": { + "data-values/common": "^0.3.0", + "data-values/data-types": "^1.0.0", + "data-values/data-values": "^1.0.0", + "data-values/geo": "^2.0.1", + "data-values/interfaces": "^0.2.0|^0.1.5", + "data-values/javascript": "^0.8.3", + "data-values/number": "^0.8.3", + "data-values/serialization": "^1.2.1", + "data-values/time": "^0.8.4", + "data-values/value-view": "^0.19.2", + "diff/diff": "^2.0.0", + "php": ">=5.5.9", + "wikibase/data-model": "^7.0.0", + "wikibase/data-model-javascript": "^3.0.1", + "wikibase/data-model-serialization": "^2.1.0", + "wikibase/data-model-services": "^3.7.0", + "wikibase/internal-serialization": "^2.2.0", + "wikibase/javascript-api": "^2.2.2", + "wikibase/serialization-javascript": "^2.0.8", + "wikimedia/purtle": "^1.0.3" + }, + "conflict": { + "mediawiki/mediawiki": "<1.25" + }, + "require-dev": { + "jakub-onderka/php-console-highlighter": "0.3.2", + "jakub-onderka/php-parallel-lint": ">=0.3 <0.10", + "wikibase/wikibase-codesniffer": "^0.1.0" + }, + "time": "2017-07-27T17:56:33+00:00", + "type": "mediawiki-extension", + "installation-source": "dist", + "autoload": { + "classmap": [ + "client/WikibaseClient.hooks.php", + "client/tests/phpunit/MockClientStore.php", + "lib/includes/", + "lib/WikibaseLib.hooks.php", + "lib/maintenance/", + "repo/includes/", + "repo/maintenance/", + "repo/Wikibase.hooks.php" + ], + "psr-4": { + "Wikibase\\Client\\": "client/includes", + "Wikibase\\Client\\Tests\\": "client/tests/phpunit/includes", + "Wikibase\\DataAccess\\": "data-access/src", + "Wikibase\\DataAccess\\Tests\\": "data-access/tests/phpunit", + "Wikibase\\Lib\\": "lib/includes", + "Wikibase\\Lib\\Tests\\": "lib/tests/phpunit", + "Wikibase\\Repo\\": "repo/includes", + "Wikibase\\Repo\\Tests\\": "repo/tests/phpunit/includes", + "Wikibase\\View\\": "view/src", + "Wikibase\\View\\Tests\\": "view/tests/phpunit" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0+" + ], + "authors": [ + { + "name": "The Wikidata team" + } + ], + "description": "Structured data repository for MediaWiki", + "homepage": "http://wikiba.se", + "keywords": [ + "wikibase", + "wikibaseclient", + "wikibaselib", + "wikibaserepo", + "wikidata" + ] } ] -- To view, visit https://gerrit.wikimedia.org/r/368312 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I01776073e8a9fbf440e4030f3493b209beef93cb Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikidata Gerrit-Branch: wmf/1.30.0-wmf.10 Gerrit-Owner: Addshore <addshorew...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits