Merge "mediawiki.widgets: Remove use of bind() for lexical 'this' binding"
[lhc/web/wiklou.git] / tests / phpunit / includes / WatchedItemStoreUnitTest.php
index 869b0d2..5f07dbf 100644 (file)
@@ -17,13 +17,20 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
        /**
         * @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
         */
-       private function getMockLoadBalancer( $mockDb ) {
+       private function getMockLoadBalancer( $mockDb, $expectedConnectionType = null ) {
                $mock = $this->getMockBuilder( LoadBalancer::class )
                        ->disableOriginalConstructor()
                        ->getMock();
-               $mock->expects( $this->any() )
-                       ->method( 'getConnection' )
-                       ->will( $this->returnValue( $mockDb ) );
+               if ( $expectedConnectionType !== null ) {
+                       $mock->expects( $this->any() )
+                               ->method( 'getConnection' )
+                               ->with( $expectedConnectionType )
+                               ->will( $this->returnValue( $mockDb ) );
+               } else {
+                       $mock->expects( $this->any() )
+                               ->method( 'getConnection' )
+                               ->will( $this->returnValue( $mockDb ) );
+               }
                $mock->expects( $this->any() )
                        ->method( 'getReadOnlyReason' )
                        ->will( $this->returnValue( false ) );
@@ -927,7 +934,7 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                );
        }
 
-       public function testAddWatchBatch_nonAnonymousUser() {
+       public function testAddWatchBatchForUser_nonAnonymousUser() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
                        ->method( 'insert' )
@@ -967,52 +974,14 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                $mockUser = $this->getMockNonAnonUserWithId( 1 );
 
                $this->assertTrue(
-                       $store->addWatchBatch(
-                               [
-                                       [ $mockUser, new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $mockUser, new TitleValue( 1, 'Some_Page' ) ],
-                               ]
-                       )
-               );
-       }
-
-       public function testAddWatchBatch_anonymousUserCombinationsAreSkipped() {
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->once() )
-                       ->method( 'insert' )
-                       ->with(
-                               'watchlist',
-                               [
-                                       [
-                                               'wl_user' => 1,
-                                               'wl_namespace' => 0,
-                                               'wl_title' => 'Some_Page',
-                                               'wl_notificationtimestamp' => null,
-                                       ]
-                               ]
-                       );
-
-               $mockCache = $this->getMockCache();
-               $mockCache->expects( $this->once() )
-                       ->method( 'delete' )
-                       ->with( '0:Some_Page:1' );
-
-               $store = new WatchedItemStore(
-                       $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
-               );
-
-               $this->assertTrue(
-                       $store->addWatchBatch(
-                               [
-                                       [ $this->getMockNonAnonUserWithId( 1 ), new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $this->getAnonUser(), new TitleValue( 0, 'Other_Page' ) ],
-                               ]
+                       $store->addWatchBatchForUser(
+                               $mockUser,
+                               [ new TitleValue( 0, 'Some_Page' ), new TitleValue( 1, 'Some_Page' ) ]
                        )
                );
        }
 
-       public function testAddWatchBatchReturnsFalse_whenOnlyGivenAnonymousUserCombinations() {
+       public function testAddWatchBatchForUser_anonymousUsersAreSkipped() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
                        ->method( 'insert' );
@@ -1026,18 +995,16 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                        $mockCache
                );
 
-               $anonUser = $this->getAnonUser();
                $this->assertFalse(
-                       $store->addWatchBatch(
-                               [
-                                       [ $anonUser, new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $anonUser, new TitleValue( 1, 'Other_Page' ) ],
-                               ]
+                       $store->addWatchBatchForUser(
+                               $this->getAnonUser(),
+                               [ new TitleValue( 0, 'Other_Page' ) ]
                        )
                );
        }
 
-       public function testAddWatchBatchReturnsFalse_whenGivenEmptyList() {
+       public function testAddWatchBatchReturnsTrue_whenGivenEmptyList() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
                        ->method( 'insert' );
@@ -1051,8 +1018,8 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                        $mockCache
                );
 
-               $this->assertFalse(
-                       $store->addWatchBatch( [] )
+               $this->assertTrue(
+                       $store->addWatchBatchForUser( $user, [] )
                );
        }
 
@@ -1380,6 +1347,108 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                );
        }
 
+       public function testGetWatchedItemsForUser() {
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                               [ 'wl_user' => 1 ]
+                       )
+                       ->will( $this->returnValue( [
+                               $this->getFakeRow( [
+                                       'wl_namespace' => 0,
+                                       'wl_title' => 'Foo1',
+                                       'wl_notificationtimestamp' => '20151212010101',
+                               ] ),
+                               $this->getFakeRow( [
+                                       'wl_namespace' => 1,
+                                       'wl_title' => 'Foo2',
+                                       'wl_notificationtimestamp' => null,
+                               ] ),
+                       ] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )->method( 'delete' );
+               $mockCache->expects( $this->never() )->method( 'get' );
+               $mockCache->expects( $this->never() )->method( 'set' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+               $user = $this->getMockNonAnonUserWithId( 1 );
+
+               $watchedItems = $store->getWatchedItemsForUser( $user );
+
+               $this->assertInternalType( 'array', $watchedItems );
+               $this->assertCount( 2, $watchedItems );
+               foreach ( $watchedItems as $watchedItem ) {
+                       $this->assertInstanceOf( 'WatchedItem', $watchedItem );
+               }
+               $this->assertEquals(
+                       new WatchedItem( $user, new TitleValue( 0, 'Foo1' ), '20151212010101' ),
+                       $watchedItems[0]
+               );
+               $this->assertEquals(
+                       new WatchedItem( $user, new TitleValue( 1, 'Foo2' ), null ),
+                       $watchedItems[1]
+               );
+       }
+
+       public function provideDbTypes() {
+               return [
+                       [ false, DB_SLAVE ],
+                       [ true, DB_MASTER ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideDbTypes
+        */
+       public function testGetWatchedItemsForUser_optionsAndEmptyResult( $forWrite, $dbType ) {
+               $mockDb = $this->getMockDb();
+               $mockCache = $this->getMockCache();
+               $mockLoadBalancer = $this->getMockLoadBalancer( $mockDb, $dbType );
+               $user = $this->getMockNonAnonUserWithId( 1 );
+
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                               [ 'wl_user' => 1 ],
+                               $this->isType( 'string' ),
+                               [ 'ORDER BY' => [ 'wl_namespace ASC', 'wl_title ASC' ] ]
+                       )
+                       ->will( $this->returnValue( [] ) );
+
+               $store = new WatchedItemStore(
+                       $mockLoadBalancer,
+                       $mockCache
+               );
+
+               $watchedItems = $store->getWatchedItemsForUser(
+                       $user,
+                       [ 'forWrite' => $forWrite, 'sort' => WatchedItemStore::SORT_ASC ]
+               );
+               $this->assertEquals( [], $watchedItems );
+       }
+
+       public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $this->getMockDb() ),
+                       $this->getMockCache()
+               );
+
+               $this->setExpectedException( 'InvalidArgumentException' );
+               $store->getWatchedItemsForUser(
+                       $this->getMockNonAnonUserWithId( 1 ),
+                       [ 'sort' => 'foo' ]
+               );
+       }
+
        public function testIsWatchedItem_existingItem() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
@@ -1481,6 +1550,251 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                );
        }
 
+       public function testGetNotificationTimestampsBatch() {
+               $targets = [
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       new TitleValue( 1, 'AnotherDbKey' ),
+               ];
+
+               $mockDb = $this->getMockDb();
+               $dbResult = [
+                       $this->getFakeRow( [
+                               'wl_namespace' => 0,
+                               'wl_title' => 'SomeDbKey',
+                               'wl_notificationtimestamp' => '20151212010101',
+                       ] ),
+                       $this->getFakeRow(
+                               [
+                                       'wl_namespace' => 1,
+                                       'wl_title' => 'AnotherDbKey',
+                                       'wl_notificationtimestamp' => null,
+                               ]
+                       ),
+               ];
+
+               $mockDb->expects( $this->once() )
+                       ->method( 'makeWhereFrom2d' )
+                       ->with(
+                               [ [ 'SomeDbKey' => 1 ], [ 'AnotherDbKey' => 1 ] ],
+                               $this->isType( 'string' ),
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( 'makeWhereFrom2d return value' ) );
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                               [
+                                       'makeWhereFrom2d return value',
+                                       'wl_user' => 1
+                               ],
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( $dbResult ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->exactly( 2 ) )
+                       ->method( 'get' )
+                       ->withConsecutive(
+                               [ '0:SomeDbKey:1' ],
+                               [ '1:AnotherDbKey:1' ]
+                       )
+                       ->will( $this->returnValue( null ) );
+               $mockCache->expects( $this->never() )->method( 'set' );
+               $mockCache->expects( $this->never() )->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       [
+                               0 => [ 'SomeDbKey' => '20151212010101', ],
+                               1 => [ 'AnotherDbKey' => null, ],
+                       ],
+                       $store->getNotificationTimestampsBatch( $this->getMockNonAnonUserWithId( 1 ), $targets )
+               );
+       }
+
+       public function testGetNotificationTimestampsBatch_notWatchedTarget() {
+               $targets = [
+                       new TitleValue( 0, 'OtherDbKey' ),
+               ];
+
+               $mockDb = $this->getMockDb();
+
+               $mockDb->expects( $this->once() )
+                       ->method( 'makeWhereFrom2d' )
+                       ->with(
+                               [ [ 'OtherDbKey' => 1 ] ],
+                               $this->isType( 'string' ),
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( 'makeWhereFrom2d return value' ) );
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                               [
+                                       'makeWhereFrom2d return value',
+                                       'wl_user' => 1
+                               ],
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( $this->getFakeRow( [] ) ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->once() )
+                       ->method( 'get' )
+                       ->with( '0:OtherDbKey:1' )
+                       ->will( $this->returnValue( null ) );
+               $mockCache->expects( $this->never() )->method( 'set' );
+               $mockCache->expects( $this->never() )->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       [
+                               0 => [ 'OtherDbKey' => false, ],
+                       ],
+                       $store->getNotificationTimestampsBatch( $this->getMockNonAnonUserWithId( 1 ), $targets )
+               );
+       }
+
+       public function testGetNotificationTimestampsBatch_cachedItem() {
+               $targets = [
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       new TitleValue( 1, 'AnotherDbKey' ),
+               ];
+
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $cachedItem = new WatchedItem( $user, $targets[0], '20151212010101' );
+
+               $mockDb = $this->getMockDb();
+
+               $mockDb->expects( $this->once() )
+                       ->method( 'makeWhereFrom2d' )
+                       ->with(
+                               [ 1 => [ 'AnotherDbKey' => 1 ] ],
+                               $this->isType( 'string' ),
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( 'makeWhereFrom2d return value' ) );
+               $mockDb->expects( $this->once() )
+                       ->method( 'select' )
+                       ->with(
+                               'watchlist',
+                               [ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
+                               [
+                                       'makeWhereFrom2d return value',
+                                       'wl_user' => 1
+                               ],
+                               $this->isType( 'string' )
+                       )
+                       ->will( $this->returnValue( [
+                               $this->getFakeRow(
+                                       [ 'wl_namespace' => 1, 'wl_title' => 'AnotherDbKey', 'wl_notificationtimestamp' => null, ]
+                               )
+                       ] ) );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->at( 1 ) )
+                       ->method( 'get' )
+                       ->with( '0:SomeDbKey:1' )
+                       ->will( $this->returnValue( $cachedItem ) );
+               $mockCache->expects( $this->at( 3 ) )
+                       ->method( 'get' )
+                       ->with( '1:AnotherDbKey:1' )
+                       ->will( $this->returnValue( null ) );
+               $mockCache->expects( $this->never() )->method( 'set' );
+               $mockCache->expects( $this->never() )->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       [
+                               0 => [ 'SomeDbKey' => '20151212010101', ],
+                               1 => [ 'AnotherDbKey' => null, ],
+                       ],
+                       $store->getNotificationTimestampsBatch( $user, $targets )
+               );
+       }
+
+       public function testGetNotificationTimestampsBatch_allItemsCached() {
+               $targets = [
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       new TitleValue( 1, 'AnotherDbKey' ),
+               ];
+
+               $user = $this->getMockNonAnonUserWithId( 1 );
+               $cachedItems = [
+                       new WatchedItem( $user, $targets[0], '20151212010101' ),
+                       new WatchedItem( $user, $targets[1], null ),
+               ];
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )->method( $this->anything() );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->at( 1 ) )
+                       ->method( 'get' )
+                       ->with( '0:SomeDbKey:1' )
+                       ->will( $this->returnValue( $cachedItems[0] ) );
+               $mockCache->expects( $this->at( 3 ) )
+                       ->method( 'get' )
+                       ->with( '1:AnotherDbKey:1' )
+                       ->will( $this->returnValue( $cachedItems[1] ) );
+               $mockCache->expects( $this->never() )->method( 'set' );
+               $mockCache->expects( $this->never() )->method( 'delete' );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       [
+                               0 => [ 'SomeDbKey' => '20151212010101', ],
+                               1 => [ 'AnotherDbKey' => null, ],
+                       ],
+                       $store->getNotificationTimestampsBatch( $user, $targets )
+               );
+       }
+
+       public function testGetNotificationTimestampsBatch_anonymousUser() {
+               $targets = [
+                       new TitleValue( 0, 'SomeDbKey' ),
+                       new TitleValue( 1, 'AnotherDbKey' ),
+               ];
+
+               $mockDb = $this->getMockDb();
+               $mockDb->expects( $this->never() )->method( $this->anything() );
+
+               $mockCache = $this->getMockCache();
+               $mockCache->expects( $this->never() )->method( $this->anything() );
+
+               $store = new WatchedItemStore(
+                       $this->getMockLoadBalancer( $mockDb ),
+                       $mockCache
+               );
+
+               $this->assertEquals(
+                       [
+                               0 => [ 'SomeDbKey' => false, ],
+                               1 => [ 'AnotherDbKey' => false, ],
+                       ],
+                       $store->getNotificationTimestampsBatch( $this->getAnonUser(), $targets )
+               );
+       }
+
        public function testResetNotificationTimestamp_anonymousUser() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )