X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=tests%2Fphpunit%2Fincludes%2FWatchedItemStoreUnitTest.php;h=030d9d59dbacaceff9d9594ea2cf5e1bc2c7e5d2;hb=140da10741c9850fa58c06f28003c3216b6f27a5;hp=d9fd4de151c89a5e4d8c6e262417d71e49a8a8b7;hpb=b4a60a54d746508cc7477bf7c4028c1ad8d1a485;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/phpunit/includes/WatchedItemStoreUnitTest.php b/tests/phpunit/includes/WatchedItemStoreUnitTest.php index d9fd4de151..030d9d59db 100644 --- a/tests/phpunit/includes/WatchedItemStoreUnitTest.php +++ b/tests/phpunit/includes/WatchedItemStoreUnitTest.php @@ -6,7 +6,7 @@ use MediaWiki\Linker\LinkTarget; * * @covers WatchedItemStore */ -class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { +class WatchedItemStoreUnitTest extends MediaWikiTestCase { /** * @return PHPUnit_Framework_MockObject_MockObject|IDatabase @@ -94,23 +94,6 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { ); } - public function testGetDefaultInstance() { - $instanceOne = WatchedItemStore::getDefaultInstance(); - $instanceTwo = WatchedItemStore::getDefaultInstance(); - $this->assertSame( $instanceOne, $instanceTwo ); - } - - public function testOverrideDefaultInstance() { - $instance = WatchedItemStore::getDefaultInstance(); - $scopedOverride = $instance->overrideDefaultInstance( null ); - - $this->assertNotSame( $instance, WatchedItemStore::getDefaultInstance() ); - - unset( $scopedOverride ); - - $this->assertSame( $instance, WatchedItemStore::getDefaultInstance() ); - } - public function testCountWatchedItems() { $user = $this->getMockNonAnonUserWithId( 1 ); @@ -2007,6 +1990,33 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { return $title; } + private function verifyCallbackJob( + $callback, + LinkTarget $expectedTitle, + $expectedUserId, + callable $notificationTimestampCondition + ) { + $this->assertInternalType( 'callable', $callback ); + + $callbackReflector = new ReflectionFunction( $callback ); + $vars = $callbackReflector->getStaticVariables(); + $this->assertArrayHasKey( 'job', $vars ); + $this->assertInstanceOf( ActivityUpdateJob::class, $vars['job'] ); + + /** @var ActivityUpdateJob $job */ + $job = $vars['job']; + $this->assertEquals( $expectedTitle->getDBkey(), $job->getTitle()->getDBkey() ); + $this->assertEquals( $expectedTitle->getNamespace(), $job->getTitle()->getNamespace() ); + + $jobParams = $job->getParams(); + $this->assertArrayHasKey( 'type', $jobParams ); + $this->assertEquals( 'updateWatchlistNotification', $jobParams['type'] ); + $this->assertArrayHasKey( 'userid', $jobParams ); + $this->assertEquals( $expectedUserId, $jobParams['userid'] ); + $this->assertArrayHasKey( 'notifTime', $jobParams ); + $this->assertTrue( $notificationTimestampCondition( $jobParams['notifTime'] ) ); + } + public function testResetNotificationTimestamp_oldidSpecifiedLatestRevisionForced() { $user = $this->getMockNonAnonUserWithId( 1 ); $oldid = 22; @@ -2033,12 +2043,18 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { $mockCache ); - // Note: This does not actually assert the job is correct $callableCallCounter = 0; $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( - function( $callable ) use ( &$callableCallCounter ) { + function( $callable ) use ( &$callableCallCounter, $title, $user ) { $callableCallCounter++; - $this->assertInternalType( 'callable', $callable ); + $this->verifyCallbackJob( + $callable, + $title, + $user->getId(), + function( $time ) { + return $time === null; + } + ); } ); @@ -2093,12 +2109,159 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { $mockCache ); - // Note: This does not actually assert the job is correct $addUpdateCallCounter = 0; $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback( - function( $callable ) use ( &$addUpdateCallCounter ) { + function( $callable ) use ( &$addUpdateCallCounter, $title, $user ) { + $addUpdateCallCounter++; + $this->verifyCallbackJob( + $callable, + $title, + $user->getId(), + function( $time ) { + return $time !== null && $time > '20151212010101'; + } + ); + } + ); + + $getTimestampCallCounter = 0; + $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback( + function( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) { + $getTimestampCallCounter++; + $this->assertEquals( $title, $titleParam ); + $this->assertEquals( $oldid, $oldidParam ); + } + ); + + $this->assertTrue( + $store->resetNotificationTimestamp( + $user, + $title, + 'force', + $oldid + ) + ); + $this->assertEquals( 1, $addUpdateCallCounter ); + $this->assertEquals( 1, $getTimestampCallCounter ); + + ScopedCallback::consume( $scopedOverrideDeferred ); + ScopedCallback::consume( $scopedOverrideRevision ); + } + + public function testResetNotificationTimestamp_notWatchedPageForced() { + $user = $this->getMockNonAnonUserWithId( 1 ); + $oldid = 22; + $title = $this->getMockTitle( 'SomeDbKey' ); + $title->expects( $this->once() ) + ->method( 'getNextRevisionID' ) + ->with( $oldid ) + ->will( $this->returnValue( 33 ) ); + + $mockDb = $this->getMockDb(); + $mockDb->expects( $this->once() ) + ->method( 'selectRow' ) + ->with( + 'watchlist', + 'wl_notificationtimestamp', + [ + 'wl_user' => 1, + 'wl_namespace' => 0, + 'wl_title' => 'SomeDbKey', + ] + ) + ->will( $this->returnValue( false ) ); + + $mockCache = $this->getMockCache(); + $mockDb->expects( $this->never() ) + ->method( 'get' ); + $mockDb->expects( $this->never() ) + ->method( 'set' ); + $mockDb->expects( $this->never() ) + ->method( 'delete' ); + + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $mockDb ), + $mockCache + ); + + $callableCallCounter = 0; + $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( + function( $callable ) use ( &$callableCallCounter, $title, $user ) { + $callableCallCounter++; + $this->verifyCallbackJob( + $callable, + $title, + $user->getId(), + function( $time ) { + return $time === null; + } + ); + } + ); + + $this->assertTrue( + $store->resetNotificationTimestamp( + $user, + $title, + 'force', + $oldid + ) + ); + $this->assertEquals( 1, $callableCallCounter ); + + ScopedCallback::consume( $scopedOverride ); + } + + public function testResetNotificationTimestamp_futureNotificationTimestampForced() { + $user = $this->getMockNonAnonUserWithId( 1 ); + $oldid = 22; + $title = $this->getMockTitle( 'SomeDbKey' ); + $title->expects( $this->once() ) + ->method( 'getNextRevisionID' ) + ->with( $oldid ) + ->will( $this->returnValue( 33 ) ); + + $mockDb = $this->getMockDb(); + $mockDb->expects( $this->once() ) + ->method( 'selectRow' ) + ->with( + 'watchlist', + 'wl_notificationtimestamp', + [ + 'wl_user' => 1, + 'wl_namespace' => 0, + 'wl_title' => 'SomeDbKey', + ] + ) + ->will( $this->returnValue( + $this->getFakeRow( [ 'wl_notificationtimestamp' => '30151212010101' ] ) + ) ); + + $mockCache = $this->getMockCache(); + $mockDb->expects( $this->never() ) + ->method( 'get' ); + $mockDb->expects( $this->never() ) + ->method( 'set' ); + $mockDb->expects( $this->never() ) + ->method( 'delete' ); + + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $mockDb ), + $mockCache + ); + + $addUpdateCallCounter = 0; + $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback( + function( $callable ) use ( &$addUpdateCallCounter, $title, $user ) { $addUpdateCallCounter++; - $this->assertInternalType( 'callable', $callable ); + $this->verifyCallbackJob( + $callable, + $title, + $user->getId(), + function( $time ) { + return $time === '30151212010101'; + } + ); } ); @@ -2126,13 +2289,165 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { ScopedCallback::consume( $scopedOverrideRevision ); } + public function testResetNotificationTimestamp_futureNotificationTimestampNotForced() { + $user = $this->getMockNonAnonUserWithId( 1 ); + $oldid = 22; + $title = $this->getMockTitle( 'SomeDbKey' ); + $title->expects( $this->once() ) + ->method( 'getNextRevisionID' ) + ->with( $oldid ) + ->will( $this->returnValue( 33 ) ); + + $mockDb = $this->getMockDb(); + $mockDb->expects( $this->once() ) + ->method( 'selectRow' ) + ->with( + 'watchlist', + 'wl_notificationtimestamp', + [ + 'wl_user' => 1, + 'wl_namespace' => 0, + 'wl_title' => 'SomeDbKey', + ] + ) + ->will( $this->returnValue( + $this->getFakeRow( [ 'wl_notificationtimestamp' => '30151212010101' ] ) + ) ); + + $mockCache = $this->getMockCache(); + $mockDb->expects( $this->never() ) + ->method( 'get' ); + $mockDb->expects( $this->never() ) + ->method( 'set' ); + $mockDb->expects( $this->never() ) + ->method( 'delete' ); + + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $mockDb ), + $mockCache + ); + + $addUpdateCallCounter = 0; + $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback( + function( $callable ) use ( &$addUpdateCallCounter, $title, $user ) { + $addUpdateCallCounter++; + $this->verifyCallbackJob( + $callable, + $title, + $user->getId(), + function( $time ) { + return $time === false; + } + ); + } + ); + + $getTimestampCallCounter = 0; + $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback( + function( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) { + $getTimestampCallCounter++; + $this->assertEquals( $title, $titleParam ); + $this->assertEquals( $oldid, $oldidParam ); + } + ); + + $this->assertTrue( + $store->resetNotificationTimestamp( + $user, + $title, + '', + $oldid + ) + ); + $this->assertEquals( 1, $addUpdateCallCounter ); + $this->assertEquals( 1, $getTimestampCallCounter ); + + ScopedCallback::consume( $scopedOverrideDeferred ); + ScopedCallback::consume( $scopedOverrideRevision ); + } + + public function testSetNotificationTimestampsForUser_anonUser() { + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $this->getMockDb() ), + $this->getMockCache() + ); + $this->assertFalse( $store->setNotificationTimestampsForUser( $this->getAnonUser(), '' ) ); + } + + public function testSetNotificationTimestampsForUser_allRows() { + $user = $this->getMockNonAnonUserWithId( 1 ); + $timestamp = '20100101010101'; + + $mockDb = $this->getMockDb(); + $mockDb->expects( $this->once() ) + ->method( 'update' ) + ->with( + 'watchlist', + [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ], + [ 'wl_user' => 1 ] + ) + ->will( $this->returnValue( true ) ); + $mockDb->expects( $this->exactly( 1 ) ) + ->method( 'timestamp' ) + ->will( $this->returnCallback( function( $value ) { + return 'TS' . $value . 'TS'; + } ) ); + + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $mockDb ), + $this->getMockCache() + ); + + $this->assertTrue( + $store->setNotificationTimestampsForUser( $user, $timestamp ) + ); + } + + public function testSetNotificationTimestampsForUser_specificTargets() { + $user = $this->getMockNonAnonUserWithId( 1 ); + $timestamp = '20100101010101'; + $targets = [ new TitleValue( 0, 'Foo' ), new TitleValue( 0, 'Bar' ) ]; + + $mockDb = $this->getMockDb(); + $mockDb->expects( $this->once() ) + ->method( 'update' ) + ->with( + 'watchlist', + [ 'wl_notificationtimestamp' => 'TS' . $timestamp . 'TS' ], + [ 'wl_user' => 1, 0 => 'makeWhereFrom2d return value' ] + ) + ->will( $this->returnValue( true ) ); + $mockDb->expects( $this->exactly( 1 ) ) + ->method( 'timestamp' ) + ->will( $this->returnCallback( function( $value ) { + return 'TS' . $value . 'TS'; + } ) ); + $mockDb->expects( $this->once() ) + ->method( 'makeWhereFrom2d' ) + ->with( + [ [ 'Foo' => 1, 'Bar' => 1 ] ], + $this->isType( 'string' ), + $this->isType( 'string' ) + ) + ->will( $this->returnValue( 'makeWhereFrom2d return value' ) ); + + $store = $this->newWatchedItemStore( + $this->getMockLoadBalancer( $mockDb ), + $this->getMockCache() + ); + + $this->assertTrue( + $store->setNotificationTimestampsForUser( $user, $timestamp, $targets ) + ); + } + public function testUpdateNotificationTimestamp_watchersExist() { $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) - ->method( 'select' ) + ->method( 'selectFieldValues' ) ->with( - [ 'watchlist' ], - [ 'wl_user' ], + 'watchlist', + 'wl_user', [ 'wl_user != 1', 'wl_namespace' => 0, @@ -2140,18 +2455,7 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { 'wl_notificationtimestamp IS NULL' ] ) - ->will( - $this->returnValue( [ - $this->getFakeRow( [ 'wl_user' => '2' ] ), - $this->getFakeRow( [ 'wl_user' => '3' ] ) - ] ) - ); - $mockDb->expects( $this->once() ) - ->method( 'onTransactionIdle' ) - ->with( $this->isType( 'callable' ) ) - ->will( $this->returnCallback( function( $callable ) { - $callable(); - } ) ); + ->will( $this->returnValue( [ '2', '3' ] ) ); $mockDb->expects( $this->once() ) ->method( 'update' ) ->with( @@ -2187,10 +2491,10 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { public function testUpdateNotificationTimestamp_noWatchers() { $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) - ->method( 'select' ) + ->method( 'selectFieldValues' ) ->with( - [ 'watchlist' ], - [ 'wl_user' ], + 'watchlist', + 'wl_user', [ 'wl_user != 1', 'wl_namespace' => 0, @@ -2201,8 +2505,6 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { ->will( $this->returnValue( [] ) ); - $mockDb->expects( $this->never() ) - ->method( 'onTransactionIdle' ); $mockDb->expects( $this->never() ) ->method( 'update' ); @@ -2236,19 +2538,10 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase { $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] ) ) ); $mockDb->expects( $this->once() ) - ->method( 'select' ) + ->method( 'selectFieldValues' ) ->will( - $this->returnValue( [ - $this->getFakeRow( [ 'wl_user' => '2' ] ), - $this->getFakeRow( [ 'wl_user' => '3' ] ) - ] ) + $this->returnValue( [ '2', '3' ] ) ); - $mockDb->expects( $this->once() ) - ->method( 'onTransactionIdle' ) - ->with( $this->isType( 'callable' ) ) - ->will( $this->returnCallback( function( $callable ) { - $callable(); - } ) ); $mockDb->expects( $this->once() ) ->method( 'update' );