diff options
Diffstat (limited to 'www/wiki/tests/phpunit/includes/deferred/DeferredUpdatesTest.php')
-rw-r--r-- | www/wiki/tests/phpunit/includes/deferred/DeferredUpdatesTest.php | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/www/wiki/tests/phpunit/includes/deferred/DeferredUpdatesTest.php b/www/wiki/tests/phpunit/includes/deferred/DeferredUpdatesTest.php new file mode 100644 index 00000000..6b417073 --- /dev/null +++ b/www/wiki/tests/phpunit/includes/deferred/DeferredUpdatesTest.php @@ -0,0 +1,338 @@ +<?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 + $this->setMwGlobals( 'wgCommandLineMode', false ); + + $pre = DeferredUpdates::PRESEND; + $post = DeferredUpdates::POSTSEND; + $all = DeferredUpdates::ALL; + + $update = $this->getMock( DeferrableUpdate::class ); + $update->expects( $this->never() ) + ->method( 'doUpdate' ); + + DeferredUpdates::addUpdate( $update, $pre ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates( $pre ) ); + $this->assertCount( 0, DeferredUpdates::getPendingUpdates( $post ) ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates( $all ) ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates() ); + DeferredUpdates::clearPendingUpdates(); + $this->assertCount( 0, DeferredUpdates::getPendingUpdates() ); + + DeferredUpdates::addUpdate( $update, $post ); + $this->assertCount( 0, DeferredUpdates::getPendingUpdates( $pre ) ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates( $post ) ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates( $all ) ); + $this->assertCount( 1, DeferredUpdates::getPendingUpdates() ); + DeferredUpdates::clearPendingUpdates(); + $this->assertCount( 0, DeferredUpdates::getPendingUpdates() ); + } + + /** + * @covers DeferredUpdates::doUpdates + * @covers DeferredUpdates::execute + * @covers DeferredUpdates::addUpdate + */ + public function testDoUpdatesWeb() { + $this->setMwGlobals( 'wgCommandLineMode', false ); + + $updates = [ + '1' => "deferred update 1;\n", + '2' => "deferred update 2;\n", + '2-1' => "deferred update 1 within deferred update 2;\n", + '2-2' => "deferred update 2 within deferred update 2;\n", + '3' => "deferred update 3;\n", + '3-1' => "deferred update 1 within deferred update 3;\n", + '3-2' => "deferred update 2 within deferred update 3;\n", + '3-1-1' => "deferred update 1 within deferred update 1 within deferred update 3;\n", + '3-2-1' => "deferred update 1 within deferred update 2 with deferred update 3;\n", + ]; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['1']; + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2-1']; + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2-2']; + } + ); + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-1']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-1-1']; + } + ); + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-2']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-2-1']; + } + ); + } + ); + } + ); + + $this->assertEquals( 3, DeferredUpdates::pendingUpdatesCount() ); + + $this->expectOutputString( implode( '', $updates ) ); + + DeferredUpdates::doUpdates(); + + $x = null; + $y = null; + DeferredUpdates::addCallableUpdate( + function () use ( &$x ) { + $x = 'Sherity'; + }, + DeferredUpdates::PRESEND + ); + DeferredUpdates::addCallableUpdate( + function () use ( &$y ) { + $y = 'Marychu'; + }, + DeferredUpdates::POSTSEND + ); + + $this->assertNull( $x, "Update not run yet" ); + $this->assertNull( $y, "Update not run yet" ); + + DeferredUpdates::doUpdates( 'run', DeferredUpdates::PRESEND ); + $this->assertEquals( "Sherity", $x, "PRESEND update ran" ); + $this->assertNull( $y, "POSTSEND update not run yet" ); + + DeferredUpdates::doUpdates( 'run', DeferredUpdates::POSTSEND ); + $this->assertEquals( "Marychu", $y, "POSTSEND update ran" ); + } + + /** + * @covers DeferredUpdates::doUpdates + * @covers DeferredUpdates::execute + * @covers DeferredUpdates::addUpdate + */ + public function testDoUpdatesCLI() { + $this->setMwGlobals( 'wgCommandLineMode', true ); + $updates = [ + '1' => "deferred update 1;\n", + '2' => "deferred update 2;\n", + '2-1' => "deferred update 1 within deferred update 2;\n", + '2-2' => "deferred update 2 within deferred update 2;\n", + '3' => "deferred update 3;\n", + '3-1' => "deferred update 1 within deferred update 3;\n", + '3-2' => "deferred update 2 within deferred update 3;\n", + '3-1-1' => "deferred update 1 within deferred update 1 within deferred update 3;\n", + '3-2-1' => "deferred update 1 within deferred update 2 with deferred update 3;\n", + ]; + + // clear anything + $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); + $lbFactory->commitMasterChanges( __METHOD__ ); + + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['1']; + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2-1']; + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['2-2']; + } + ); + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-1']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-1-1']; + } + ); + } + ); + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-2']; + DeferredUpdates::addCallableUpdate( + function () use ( $updates ) { + echo $updates['3-2-1']; + } + ); + } + ); + } + ); + + $this->expectOutputString( implode( '', $updates ) ); + + DeferredUpdates::doUpdates(); + } + + /** + * @covers DeferredUpdates::doUpdates + * @covers DeferredUpdates::execute + * @covers DeferredUpdates::addUpdate + */ + public function testPresendAddOnPostsendRun() { + $this->setMwGlobals( 'wgCommandLineMode', true ); + + $x = false; + $y = false; + // clear anything + $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); + $lbFactory->commitMasterChanges( __METHOD__ ); + + DeferredUpdates::addCallableUpdate( + function () use ( &$x, &$y ) { + $x = true; + DeferredUpdates::addCallableUpdate( + function () use ( &$y ) { + $y = true; + }, + DeferredUpdates::PRESEND + ); + }, + DeferredUpdates::POSTSEND + ); + + DeferredUpdates::doUpdates(); + + $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' ); + } +} |