<?php
+use MediaWiki\MediaWikiServices;
+
class DeferredUpdatesTest extends MediaWikiTestCase {
+ /**
+ * @covers DeferredUpdates::addUpdate
+ * @covers DeferredUpdates::push
+ * @covers DeferredUpdates::doUpdates
+ * @covers DeferredUpdates::execute
+ * @covers DeferredUpdates::runUpdate
+ */
+ public function testAddAndRun() {
+ $update = $this->getMockBuilder( DeferrableUpdate::class )
+ ->setMethods( [ 'doUpdate' ] )->getMock();
+ $update->expects( $this->once() )->method( 'doUpdate' );
+
+ DeferredUpdates::addUpdate( $update );
+ DeferredUpdates::doUpdates();
+ }
+
+ /**
+ * @covers DeferredUpdates::addUpdate
+ * @covers DeferredUpdates::push
+ */
+ public function testAddMergeable() {
+ $this->setMwGlobals( 'wgCommandLineMode', false );
+
+ $update1 = $this->getMockBuilder( MergeableUpdate::class )
+ ->setMethods( [ 'merge', 'doUpdate' ] )->getMock();
+ $update1->expects( $this->once() )->method( 'merge' );
+ $update1->expects( $this->never() )->method( 'doUpdate' );
+
+ $update2 = $this->getMockBuilder( MergeableUpdate::class )
+ ->setMethods( [ 'merge', 'doUpdate' ] )->getMock();
+ $update2->expects( $this->never() )->method( 'merge' );
+ $update2->expects( $this->never() )->method( 'doUpdate' );
+
+ DeferredUpdates::addUpdate( $update1 );
+ DeferredUpdates::addUpdate( $update2 );
+ }
+
+ /**
+ * @covers DeferredUpdates::addCallableUpdate
+ * @covers MWCallableUpdate::getOrigin
+ */
+ public function testAddCallableUpdate() {
+ $this->setMwGlobals( 'wgCommandLineMode', true );
+
+ $ran = 0;
+ DeferredUpdates::addCallableUpdate( function () use ( &$ran ) {
+ $ran++;
+ } );
+ DeferredUpdates::doUpdates();
+
+ $this->assertSame( 1, $ran, 'Update ran' );
+ }
+
/**
* @covers DeferredUpdates::getPendingUpdates
+ * @covers DeferredUpdates::clearPendingUpdates
*/
public function testGetPendingUpdates() {
- # Prevent updates from running
+ // Prevent updates from running
$this->setMwGlobals( 'wgCommandLineMode', false );
$pre = DeferredUpdates::PRESEND;
$this->assertCount( 0, DeferredUpdates::getPendingUpdates() );
}
+ /**
+ * @covers DeferredUpdates::doUpdates
+ * @covers DeferredUpdates::execute
+ * @covers DeferredUpdates::addUpdate
+ */
public function testDoUpdatesWeb() {
$this->setMwGlobals( 'wgCommandLineMode', false );
$this->assertEquals( "Marychu", $y, "POSTSEND update ran" );
}
+ /**
+ * @covers DeferredUpdates::doUpdates
+ * @covers DeferredUpdates::execute
+ * @covers DeferredUpdates::addUpdate
+ */
public function testDoUpdatesCLI() {
$this->setMwGlobals( 'wgCommandLineMode', true );
$updates = [
'3-2-1' => "deferred update 1 within deferred update 2 with deferred update 3;\n",
];
- wfGetLBFactory()->commitMasterChanges( __METHOD__ ); // clear anything
+ // clear anything
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory->commitMasterChanges( __METHOD__ );
DeferredUpdates::addCallableUpdate(
function () use ( $updates ) {
DeferredUpdates::doUpdates();
}
+ /**
+ * @covers DeferredUpdates::doUpdates
+ * @covers DeferredUpdates::execute
+ * @covers DeferredUpdates::addUpdate
+ */
public function testPresendAddOnPostsendRun() {
$this->setMwGlobals( 'wgCommandLineMode', true );
$x = false;
$y = false;
- wfGetLBFactory()->commitMasterChanges( __METHOD__ ); // clear anything
+ // clear anything
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory->commitMasterChanges( __METHOD__ );
DeferredUpdates::addCallableUpdate(
function () use ( &$x, &$y ) {
$this->assertTrue( $x, "Outer POSTSEND update ran" );
$this->assertTrue( $y, "Nested PRESEND update ran" );
}
+
+ /**
+ * @covers DeferredUpdates::runUpdate
+ */
+ public function testRunUpdateTransactionScope() {
+ $this->setMwGlobals( 'wgCommandLineMode', false );
+
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $this->assertFalse( $lbFactory->hasTransactionRound(), 'Initial state' );
+
+ $ran = 0;
+ DeferredUpdates::addCallableUpdate( function () use ( &$ran, $lbFactory ) {
+ $ran++;
+ $this->assertTrue( $lbFactory->hasTransactionRound(), 'Has transaction' );
+ } );
+ DeferredUpdates::doUpdates();
+
+ $this->assertSame( 1, $ran, 'Update ran' );
+ $this->assertFalse( $lbFactory->hasTransactionRound(), 'Final state' );
+ }
+
+ /**
+ * @covers DeferredUpdates::runUpdate
+ * @covers TransactionRoundDefiningUpdate::getOrigin
+ */
+ public function testRunOuterScopeUpdate() {
+ $this->setMwGlobals( 'wgCommandLineMode', false );
+
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $this->assertFalse( $lbFactory->hasTransactionRound(), 'Initial state' );
+
+ $ran = 0;
+ DeferredUpdates::addUpdate( new TransactionRoundDefiningUpdate(
+ function () use ( &$ran, $lbFactory ) {
+ $ran++;
+ $this->assertFalse( $lbFactory->hasTransactionRound(), 'No transaction' );
+ } )
+ );
+ DeferredUpdates::doUpdates();
+
+ $this->assertSame( 1, $ran, 'Update ran' );
+ }
+
+ /**
+ * @covers DeferredUpdates::tryOpportunisticExecute
+ */
+ public function testTryOpportunisticExecute() {
+ $calls = [];
+ $callback1 = function () use ( &$calls ) {
+ $calls[] = 1;
+ };
+ $callback2 = function () use ( &$calls ) {
+ $calls[] = 2;
+ };
+
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory->beginMasterChanges( __METHOD__ );
+
+ DeferredUpdates::addCallableUpdate( $callback1 );
+ $this->assertEquals( [], $calls );
+
+ DeferredUpdates::tryOpportunisticExecute( 'run' );
+ $this->assertEquals( [], $calls );
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->onTransactionIdle( function () use ( &$calls, $callback2 ) {
+ DeferredUpdates::addCallableUpdate( $callback2 );
+ $this->assertEquals( [], $calls );
+ $calls[] = 'oti';
+ } );
+ $this->assertEquals( 1, $dbw->trxLevel() );
+ $this->assertEquals( [], $calls );
+
+ $lbFactory->commitMasterChanges( __METHOD__ );
+
+ $this->assertEquals( [ 'oti' ], $calls );
+
+ DeferredUpdates::tryOpportunisticExecute( 'run' );
+ $this->assertEquals( [ 'oti', 1, 2 ], $calls );
+ }
}