Daniel Kinzler has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/367328 )
Change subject: Move injection of RC records to a separate job.
......................................................................
Move injection of RC records to a separate job.
This should also fix the nested transaction issue introduced by If195a35e9c.
Bug: T107722
Bug: T171370
Change-Id: I9100c174537c56527c2dcec38a69234b7ebe80c9
---
M client/WikibaseClient.php
A client/includes/Changes/InjectRCRecordsJob.php
M client/includes/Changes/WikiPageUpdater.php
M client/includes/WikibaseClient.php
A client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php
M client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php
6 files changed, 589 insertions(+), 98 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase
refs/changes/28/367328/1
diff --git a/client/WikibaseClient.php b/client/WikibaseClient.php
index fd0fe88..1d4a527 100644
--- a/client/WikibaseClient.php
+++ b/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(
diff --git a/client/includes/Changes/InjectRCRecordsJob.php
b/client/includes/Changes/InjectRCRecordsJob.php
new file mode 100644
index 0000000..a00f8dd
--- /dev/null
+++ b/client/includes/Changes/InjectRCRecordsJob.php
@@ -0,0 +1,273 @@
+<?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::parameterType( 'array', $params, '$params' );
+ Assert::parameter(
+ isset( $params['change'] ),
+ '$params',
+ '$params[\'change\'] not set.'
+ );
+ Assert::parameter(
+ isset( $params['pages'] ) && is_array( $params['pages']
),
+ '$params',
+ '$params[\'pages\'] not set or not an array.'
+ );
+ 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/client/includes/Changes/WikiPageUpdater.php
b/client/includes/Changes/WikiPageUpdater.php
index 6fd4f03..3ab41b1 100644
--- a/client/includes/Changes/WikiPageUpdater.php
+++ b/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/client/includes/WikibaseClient.php
b/client/includes/WikibaseClient.php
index ddc6dad..6b2d353 100644
--- a/client/includes/WikibaseClient.php
+++ b/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/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php
b/client/tests/phpunit/includes/Changes/InjectRCRecordsJobTest.php
new file mode 100644
index 0000000..e182b76
--- /dev/null
+++ b/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/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php
b/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php
index f73f61f..2be8d28 100644
--- a/client/tests/phpunit/includes/Changes/WikiPageUpdaterTest.php
+++ b/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]' );
}
}
--
To view, visit https://gerrit.wikimedia.org/r/367328
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9100c174537c56527c2dcec38a69234b7ebe80c9
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Daniel Kinzler <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits