6 * @covers WatchedItemStore
8 class WatchedItemStoreUnitTest
extends PHPUnit_Framework_TestCase
{
11 * @return PHPUnit_Framework_MockObject_MockObject|IDatabase
13 private function getMockDb() {
14 return $this->getMock( IDatabase
::class );
18 * @return PHPUnit_Framework_MockObject_MockObject|LoadBalancer
20 private function getMockLoadBalancer( $mockDb ) {
21 $mock = $this->getMockBuilder( LoadBalancer
::class )
22 ->disableOriginalConstructor()
24 $mock->expects( $this->any() )
25 ->method( 'getConnection' )
26 ->will( $this->returnValue( $mockDb ) );
27 $mock->expects( $this->any() )
28 ->method( 'getReadOnlyReason' )
29 ->will( $this->returnValue( false ) );
34 * @return PHPUnit_Framework_MockObject_MockObject|BagOStuff
36 private function getMockCache() {
37 $mock = $this->getMockBuilder( BagOStuff
::class )
38 ->disableOriginalConstructor()
40 $mock->expects( $this->any() )
42 ->will( $this->returnCallback( function() {
43 return implode( ':', func_get_args() );
50 * @return PHPUnit_Framework_MockObject_MockObject|User
52 private function getMockNonAnonUserWithId( $id ) {
53 $mock = $this->getMock( User
::class );
54 $mock->expects( $this->any() )
56 ->will( $this->returnValue( false ) );
57 $mock->expects( $this->any() )
59 ->will( $this->returnValue( $id ) );
66 private function getAnonUser() {
67 return User
::newFromName( 'Anon_User' );
70 private function getFakeRow( array $rowValues ) {
71 $fakeRow = new stdClass();
72 foreach ( $rowValues as $valueName => $value ) {
73 $fakeRow->$valueName = $value;
78 public function testGetDefaultInstance() {
79 $instanceOne = WatchedItemStore
::getDefaultInstance();
80 $instanceTwo = WatchedItemStore
::getDefaultInstance();
81 $this->assertSame( $instanceOne, $instanceTwo );
84 public function testDuplicateEntry_nothingToDuplicate() {
85 $mockDb = $this->getMockDb();
86 $mockDb->expects( $this->once() )
92 'wl_notificationtimestamp',
96 'wl_title' => 'Old_Title',
98 'WatchedItemStore::duplicateEntry',
101 ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
103 $store = new WatchedItemStore(
104 $this->getMockLoadBalancer( $mockDb ),
105 new HashBagOStuff( [ 'maxKeys' => 100 ] )
108 $store->duplicateEntry(
109 Title
::newFromText( 'Old_Title' ),
110 Title
::newFromText( 'New_Title' )
114 public function testDuplicateEntry_somethingToDuplicate() {
116 $this->getFakeRow( [ 'wl_user' => 1, 'wl_notificationtimestamp' => '20151212010101' ] ),
117 $this->getFakeRow( [ 'wl_user' => 2, 'wl_notificationtimestamp' => null ] ),
120 $mockDb = $this->getMockDb();
121 $mockDb->expects( $this->at( 0 ) )
127 'wl_notificationtimestamp',
131 'wl_title' => 'Old_Title',
134 ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
135 $mockDb->expects( $this->at( 1 ) )
136 ->method( 'replace' )
139 [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
144 'wl_title' => 'New_Title',
145 'wl_notificationtimestamp' => '20151212010101',
150 'wl_title' => 'New_Title',
151 'wl_notificationtimestamp' => null,
154 $this->isType( 'string' )
157 $store = new WatchedItemStore(
158 $this->getMockLoadBalancer( $mockDb ),
159 new HashBagOStuff( [ 'maxKeys' => 100 ] )
162 $store->duplicateEntry(
163 Title
::newFromText( 'Old_Title' ),
164 Title
::newFromText( 'New_Title' )
168 public function testDuplicateAllAssociatedEntries_nothingToDuplicate() {
169 $mockDb = $this->getMockDb();
170 $mockDb->expects( $this->at( 0 ) )
176 'wl_notificationtimestamp',
180 'wl_title' => 'Old_Title',
183 ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
184 $mockDb->expects( $this->at( 1 ) )
190 'wl_notificationtimestamp',
194 'wl_title' => 'Old_Title',
197 ->will( $this->returnValue( new FakeResultWrapper( [] ) ) );
199 $store = new WatchedItemStore(
200 $this->getMockLoadBalancer( $mockDb ),
201 new HashBagOStuff( [ 'maxKeys' => 100 ] )
204 $store->duplicateAllAssociatedEntries(
205 Title
::newFromText( 'Old_Title' ),
206 Title
::newFromText( 'New_Title' )
210 public function testDuplicateAllAssociatedEntries_somethingToDuplicate() {
212 $this->getFakeRow( [ 'wl_user' => 1, 'wl_notificationtimestamp' => '20151212010101' ] ),
215 $mockDb = $this->getMockDb();
216 $mockDb->expects( $this->at( 0 ) )
222 'wl_notificationtimestamp',
226 'wl_title' => 'Old_Title',
229 ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
230 $mockDb->expects( $this->at( 1 ) )
231 ->method( 'replace' )
234 [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
239 'wl_title' => 'New_Title',
240 'wl_notificationtimestamp' => '20151212010101',
243 $this->isType( 'string' )
245 $mockDb->expects( $this->at( 2 ) )
251 'wl_notificationtimestamp',
255 'wl_title' => 'Old_Title',
258 ->will( $this->returnValue( new FakeResultWrapper( $fakeRows ) ) );
259 $mockDb->expects( $this->at( 3 ) )
260 ->method( 'replace' )
263 [ [ 'wl_user', 'wl_namespace', 'wl_title' ] ],
268 'wl_title' => 'New_Title',
269 'wl_notificationtimestamp' => '20151212010101',
272 $this->isType( 'string' )
275 $store = new WatchedItemStore(
276 $this->getMockLoadBalancer( $mockDb ),
277 new HashBagOStuff( [ 'maxKeys' => 100 ] )
280 $store->duplicateAllAssociatedEntries(
281 Title
::newFromText( 'Old_Title' ),
282 Title
::newFromText( 'New_Title' )
286 public function testAddWatch_nonAnonymousUser() {
287 $mockDb = $this->getMockDb();
288 $mockDb->expects( $this->once() )
296 'wl_title' => 'Some_Page',
297 'wl_notificationtimestamp' => null,
302 $mockCache = $this->getMockCache();
303 $mockCache->expects( $this->once() )
305 ->with( '0:Some_Page:1' );
307 $store = new WatchedItemStore(
308 $this->getMockLoadBalancer( $mockDb ),
313 $this->getMockNonAnonUserWithId( 1 ),
314 Title
::newFromText( 'Some_Page' )
318 public function testAddWatch_anonymousUser() {
319 $mockDb = $this->getMockDb();
320 $mockDb->expects( $this->never() )
321 ->method( 'insert' );
323 $mockCache = $this->getMockCache();
324 $mockCache->expects( $this->never() )
325 ->method( 'delete' );
327 $store = new WatchedItemStore(
328 $this->getMockLoadBalancer( $mockDb ),
333 $this->getAnonUser(),
334 Title
::newFromText( 'Some_Page' )
338 public function testAddWatchBatch_nonAnonymousUser() {
339 $mockDb = $this->getMockDb();
340 $mockDb->expects( $this->once() )
348 'wl_title' => 'Some_Page',
349 'wl_notificationtimestamp' => null,
354 'wl_title' => 'Some_Page',
355 'wl_notificationtimestamp' => null,
360 $mockCache = $this->getMockCache();
361 $mockCache->expects( $this->exactly( 2 ) )
362 ->method( 'delete' );
363 $mockCache->expects( $this->at( 1 ) )
365 ->with( '0:Some_Page:1' );
366 $mockCache->expects( $this->at( 3 ) )
368 ->with( '1:Some_Page:1' );
370 $store = new WatchedItemStore(
371 $this->getMockLoadBalancer( $mockDb ),
375 $mockUser = $this->getMockNonAnonUserWithId( 1 );
378 $store->addWatchBatch(
380 [ $mockUser, new TitleValue( 0, 'Some_Page' ) ],
381 [ $mockUser, new TitleValue( 1, 'Some_Page' ) ],
387 public function testAddWatchBatch_anonymousUserCombinationsAreSkipped() {
388 $mockDb = $this->getMockDb();
389 $mockDb->expects( $this->once() )
397 'wl_title' => 'Some_Page',
398 'wl_notificationtimestamp' => null,
403 $mockCache = $this->getMockCache();
404 $mockCache->expects( $this->once() )
406 ->with( '0:Some_Page:1' );
408 $store = new WatchedItemStore(
409 $this->getMockLoadBalancer( $mockDb ),
414 $store->addWatchBatch(
416 [ $this->getMockNonAnonUserWithId( 1 ), new TitleValue( 0, 'Some_Page' ) ],
417 [ $this->getAnonUser(), new TitleValue( 0, 'Other_Page' ) ],
423 public function testAddWatchBatchReturnsFalse_whenOnlyGivenAnonymousUserCombinations() {
424 $mockDb = $this->getMockDb();
425 $mockDb->expects( $this->never() )
426 ->method( 'insert' );
428 $mockCache = $this->getMockCache();
429 $mockCache->expects( $this->never() )
430 ->method( 'delete' );
432 $store = new WatchedItemStore(
433 $this->getMockLoadBalancer( $mockDb ),
437 $anonUser = $this->getAnonUser();
439 $store->addWatchBatch(
441 [ $anonUser, new TitleValue( 0, 'Some_Page' ) ],
442 [ $anonUser, new TitleValue( 1, 'Other_Page' ) ],
448 public function testAddWatchBatchReturnsFalse_whenGivenEmptyList() {
449 $mockDb = $this->getMockDb();
450 $mockDb->expects( $this->never() )
451 ->method( 'insert' );
453 $mockCache = $this->getMockCache();
454 $mockCache->expects( $this->never() )
455 ->method( 'delete' );
457 $store = new WatchedItemStore(
458 $this->getMockLoadBalancer( $mockDb ),
463 $store->addWatchBatch( [] )
467 public function testLoadWatchedItem_existingItem() {
468 $mockDb = $this->getMockDb();
469 $mockDb->expects( $this->once() )
470 ->method( 'selectRow' )
473 'wl_notificationtimestamp',
477 'wl_title' => 'SomeDbKey',
480 ->will( $this->returnValue(
481 $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
484 $mockCache = $this->getMockCache();
485 $mockCache->expects( $this->once() )
491 $store = new WatchedItemStore(
492 $this->getMockLoadBalancer( $mockDb ),
496 $watchedItem = $store->loadWatchedItem(
497 $this->getMockNonAnonUserWithId( 1 ),
498 new TitleValue( 0, 'SomeDbKey' )
500 $this->assertInstanceOf( 'WatchedItem', $watchedItem );
501 $this->assertEquals( 1, $watchedItem->getUser()->getId() );
502 $this->assertEquals( 'SomeDbKey', $watchedItem->getLinkTarget()->getDBkey() );
503 $this->assertEquals( 0, $watchedItem->getLinkTarget()->getNamespace() );
506 public function testLoadWatchedItem_noItem() {
507 $mockDb = $this->getMockDb();
508 $mockDb->expects( $this->once() )
509 ->method( 'selectRow' )
512 'wl_notificationtimestamp',
516 'wl_title' => 'SomeDbKey',
519 ->will( $this->returnValue( [] ) );
521 $mockCache = $this->getMockCache();
522 $mockCache->expects( $this->never() )
523 ->method( 'delete' );
525 $store = new WatchedItemStore(
526 $this->getMockLoadBalancer( $mockDb ),
531 $store->loadWatchedItem(
532 $this->getMockNonAnonUserWithId( 1 ),
533 new TitleValue( 0, 'SomeDbKey' )
538 public function testLoadWatchedItem_anonymousUser() {
539 $mockDb = $this->getMockDb();
540 $mockDb->expects( $this->never() )
541 ->method( 'selectRow' );
543 $mockCache = $this->getMockCache();
544 $mockCache->expects( $this->never() )
545 ->method( 'delete' );
547 $store = new WatchedItemStore(
548 $this->getMockLoadBalancer( $mockDb ),
553 $store->loadWatchedItem(
554 $this->getAnonUser(),
555 new TitleValue( 0, 'SomeDbKey' )
560 public function testRemoveWatch_existingItem() {
561 $mockDb = $this->getMockDb();
562 $mockDb->expects( $this->once() )
569 'wl_title' => 'SomeDbKey',
572 $mockDb->expects( $this->once() )
573 ->method( 'affectedRows' )
574 ->will( $this->returnValue( 1 ) );
576 $mockCache = $this->getMockCache();
577 $mockCache->expects( $this->once() )
579 ->with( '0:SomeDbKey:1' );
581 $store = new WatchedItemStore(
582 $this->getMockLoadBalancer( $mockDb ),
588 $this->getMockNonAnonUserWithId( 1 ),
589 new TitleValue( 0, 'SomeDbKey' )
594 public function testRemoveWatch_noItem() {
595 $mockDb = $this->getMockDb();
596 $mockDb->expects( $this->once() )
603 'wl_title' => 'SomeDbKey',
606 $mockDb->expects( $this->once() )
607 ->method( 'affectedRows' )
608 ->will( $this->returnValue( 0 ) );
610 $mockCache = $this->getMockCache();
611 $mockCache->expects( $this->once() )
613 ->with( '0:SomeDbKey:1' );
615 $store = new WatchedItemStore(
616 $this->getMockLoadBalancer( $mockDb ),
622 $this->getMockNonAnonUserWithId( 1 ),
623 new TitleValue( 0, 'SomeDbKey' )
628 public function testRemoveWatch_anonymousUser() {
629 $mockDb = $this->getMockDb();
630 $mockDb->expects( $this->never() )
631 ->method( 'delete' );
633 $mockCache = $this->getMockCache();
634 $mockCache->expects( $this->never() )
635 ->method( 'delete' );
637 $store = new WatchedItemStore(
638 $this->getMockLoadBalancer( $mockDb ),
644 $this->getAnonUser(),
645 new TitleValue( 0, 'SomeDbKey' )
650 public function testGetWatchedItem_existingItem() {
651 $mockDb = $this->getMockDb();
652 $mockDb->expects( $this->once() )
653 ->method( 'selectRow' )
656 'wl_notificationtimestamp',
660 'wl_title' => 'SomeDbKey',
663 ->will( $this->returnValue(
664 $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
667 $mockCache = $this->getMockCache();
668 $mockCache->expects( $this->once() )
673 ->will( $this->returnValue( null ) );
674 $mockCache->expects( $this->once() )
680 $store = new WatchedItemStore(
681 $this->getMockLoadBalancer( $mockDb ),
685 $watchedItem = $store->getWatchedItem(
686 $this->getMockNonAnonUserWithId( 1 ),
687 new TitleValue( 0, 'SomeDbKey' )
689 $this->assertInstanceOf( 'WatchedItem', $watchedItem );
690 $this->assertEquals( 1, $watchedItem->getUser()->getId() );
691 $this->assertEquals( 'SomeDbKey', $watchedItem->getLinkTarget()->getDBkey() );
692 $this->assertEquals( 0, $watchedItem->getLinkTarget()->getNamespace() );
695 public function testGetWatchedItem_cachedItem() {
696 $mockDb = $this->getMockDb();
697 $mockDb->expects( $this->never() )
698 ->method( 'selectRow' );
700 $mockUser = $this->getMockNonAnonUserWithId( 1 );
701 $linkTarget = new TitleValue( 0, 'SomeDbKey' );
702 $cachedItem = new WatchedItem( $mockUser, $linkTarget, '20151212010101' );
704 $mockCache = $this->getMockCache();
705 $mockCache->expects( $this->once() )
710 ->will( $this->returnValue( $cachedItem ) );
711 $mockCache->expects( $this->never() )
714 $store = new WatchedItemStore(
715 $this->getMockLoadBalancer( $mockDb ),
721 $store->getWatchedItem(
728 public function testGetWatchedItem_noItem() {
729 $mockDb = $this->getMockDb();
730 $mockDb->expects( $this->once() )
731 ->method( 'selectRow' )
734 'wl_notificationtimestamp',
738 'wl_title' => 'SomeDbKey',
741 ->will( $this->returnValue( [] ) );
743 $mockCache = $this->getMockCache();
744 $mockCache->expects( $this->never() )
747 $store = new WatchedItemStore(
748 $this->getMockLoadBalancer( $mockDb ),
753 $store->getWatchedItem(
754 $this->getMockNonAnonUserWithId( 1 ),
755 new TitleValue( 0, 'SomeDbKey' )
760 public function testGetWatchedItem_anonymousUser() {
761 $mockDb = $this->getMockDb();
762 $mockDb->expects( $this->never() )
763 ->method( 'selectRow' );
765 $mockCache = $this->getMockCache();
766 $mockCache->expects( $this->never() )
769 $store = new WatchedItemStore(
770 $this->getMockLoadBalancer( $mockDb ),
775 $store->getWatchedItem(
776 $this->getAnonUser(),
777 new TitleValue( 0, 'SomeDbKey' )
782 public function testIsWatchedItem_existingItem() {
783 $mockDb = $this->getMockDb();
784 $mockDb->expects( $this->once() )
785 ->method( 'selectRow' )
788 'wl_notificationtimestamp',
792 'wl_title' => 'SomeDbKey',
795 ->will( $this->returnValue(
796 $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
799 $mockCache = $this->getMockCache();
800 $mockCache->expects( $this->once() )
806 $store = new WatchedItemStore(
807 $this->getMockLoadBalancer( $mockDb ),
813 $this->getMockNonAnonUserWithId( 1 ),
814 new TitleValue( 0, 'SomeDbKey' )
819 public function testIsWatchedItem_noItem() {
820 $mockDb = $this->getMockDb();
821 $mockDb->expects( $this->once() )
822 ->method( 'selectRow' )
825 'wl_notificationtimestamp',
829 'wl_title' => 'SomeDbKey',
832 ->will( $this->returnValue( [] ) );
834 $mockCache = $this->getMockCache();
835 $mockCache->expects( $this->never() )
838 $store = new WatchedItemStore(
839 $this->getMockLoadBalancer( $mockDb ),
845 $this->getMockNonAnonUserWithId( 1 ),
846 new TitleValue( 0, 'SomeDbKey' )
851 public function testIsWatchedItem_anonymousUser() {
852 $mockDb = $this->getMockDb();
853 $mockDb->expects( $this->never() )
854 ->method( 'selectRow' );
856 $mockCache = $this->getMockCache();
857 $mockCache->expects( $this->never() )
860 $store = new WatchedItemStore(
861 $this->getMockLoadBalancer( $mockDb ),
867 $this->getAnonUser(),
868 new TitleValue( 0, 'SomeDbKey' )
873 public function testResetNotificationTimestamp_anonymousUser() {
874 $mockDb = $this->getMockDb();
875 $mockDb->expects( $this->never() )
876 ->method( 'selectRow' );
878 $mockCache = $this->getMockCache();
879 $mockCache->expects( $this->never() )
882 $store = new WatchedItemStore(
883 $this->getMockLoadBalancer( $mockDb ),
888 $store->resetNotificationTimestamp(
889 $this->getAnonUser(),
890 Title
::newFromText( 'SomeDbKey' )
895 public function testResetNotificationTimestamp_noItem() {
896 $mockDb = $this->getMockDb();
897 $mockDb->expects( $this->once() )
898 ->method( 'selectRow' )
901 'wl_notificationtimestamp',
905 'wl_title' => 'SomeDbKey',
908 ->will( $this->returnValue( [] ) );
910 $mockCache = $this->getMockCache();
911 $mockCache->expects( $this->never() )
914 $store = new WatchedItemStore(
915 $this->getMockLoadBalancer( $mockDb ),
920 $store->resetNotificationTimestamp(
921 $this->getMockNonAnonUserWithId( 1 ),
922 Title
::newFromText( 'SomeDbKey' )
927 public function testResetNotificationTimestamp_item() {
928 $user = $this->getMockNonAnonUserWithId( 1 );
929 $title = Title
::newFromText( 'SomeDbKey' );
931 $mockDb = $this->getMockDb();
932 $mockDb->expects( $this->once() )
933 ->method( 'selectRow' )
936 'wl_notificationtimestamp',
940 'wl_title' => 'SomeDbKey',
943 ->will( $this->returnValue(
944 $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
947 $mockCache = $this->getMockCache();
948 $mockCache->expects( $this->once() )
952 $this->isInstanceOf( WatchedItem
::class )
954 $mockCache->expects( $this->once() )
956 ->with( '0:SomeDbKey:1' );
958 $store = new WatchedItemStore(
959 $this->getMockLoadBalancer( $mockDb ),
963 // Note: This does not actually assert the job is correct
964 $callableCallCounter = 0;
965 $mockCallback = function( $callable ) use ( &$callableCallCounter ) {
966 $callableCallCounter++
;
967 $this->assertInternalType( 'callable', $callable );
969 $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
972 $store->resetNotificationTimestamp(
977 $this->assertEquals( 1, $callableCallCounter );
980 public function testResetNotificationTimestamp_noItemForced() {
981 $user = $this->getMockNonAnonUserWithId( 1 );
982 $title = Title
::newFromText( 'SomeDbKey' );
984 $mockDb = $this->getMockDb();
985 $mockDb->expects( $this->never() )
986 ->method( 'selectRow' );
988 $mockCache = $this->getMockCache();
989 $mockDb->expects( $this->never() )
991 $mockDb->expects( $this->never() )
992 ->method( 'delete' );
994 $store = new WatchedItemStore(
995 $this->getMockLoadBalancer( $mockDb ),
999 // Note: This does not actually assert the job is correct
1000 $callableCallCounter = 0;
1001 $mockCallback = function( $callable ) use ( &$callableCallCounter ) {
1002 $callableCallCounter++
;
1003 $this->assertInternalType( 'callable', $callable );
1005 $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
1008 $store->resetNotificationTimestamp(
1014 $this->assertEquals( 1, $callableCallCounter );
1021 * @return PHPUnit_Framework_MockObject_MockObject|Title
1023 private function getMockTitle( $text, $ns = 0 ) {
1024 $title = $this->getMock( Title
::class );
1025 $title->expects( $this->any() )
1026 ->method( 'getText' )
1027 ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
1028 $title->expects( $this->any() )
1029 ->method( 'getDbKey' )
1030 ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) );
1031 $title->expects( $this->any() )
1032 ->method( 'getNamespace' )
1033 ->will( $this->returnValue( $ns ) );
1037 public function testResetNotificationTimestamp_oldidSpecifiedLatestRevisionForced() {
1038 $user = $this->getMockNonAnonUserWithId( 1 );
1040 $title = $this->getMockTitle( 'SomeTitle' );
1041 $title->expects( $this->once() )
1042 ->method( 'getNextRevisionID' )
1044 ->will( $this->returnValue( false ) );
1046 $mockDb = $this->getMockDb();
1047 $mockDb->expects( $this->never() )
1048 ->method( 'selectRow' );
1050 $mockCache = $this->getMockCache();
1051 $mockDb->expects( $this->never() )
1053 $mockDb->expects( $this->never() )
1054 ->method( 'delete' );
1056 $store = new WatchedItemStore(
1057 $this->getMockLoadBalancer( $mockDb ),
1061 // Note: This does not actually assert the job is correct
1062 $callableCallCounter = 0;
1063 $store->overrideDeferredUpdatesAddCallableUpdateCallback(
1064 function( $callable ) use ( &$callableCallCounter ) {
1065 $callableCallCounter++
;
1066 $this->assertInternalType( 'callable', $callable );
1071 $store->resetNotificationTimestamp(
1078 $this->assertEquals( 1, $callableCallCounter );
1081 public function testResetNotificationTimestamp_oldidSpecifiedNotLatestRevisionForced() {
1082 $user = $this->getMockNonAnonUserWithId( 1 );
1084 $title = $this->getMockTitle( 'SomeDbKey' );
1085 $title->expects( $this->once() )
1086 ->method( 'getNextRevisionID' )
1088 ->will( $this->returnValue( 33 ) );
1090 $mockDb = $this->getMockDb();
1091 $mockDb->expects( $this->once() )
1092 ->method( 'selectRow' )
1095 'wl_notificationtimestamp',
1098 'wl_namespace' => 0,
1099 'wl_title' => 'SomeDbKey',
1102 ->will( $this->returnValue(
1103 $this->getFakeRow( [ 'wl_notificationtimestamp' => '20151212010101' ] )
1106 $mockCache = $this->getMockCache();
1107 $mockDb->expects( $this->never() )
1109 $mockDb->expects( $this->never() )
1110 ->method( 'delete' );
1112 $store = new WatchedItemStore(
1113 $this->getMockLoadBalancer( $mockDb ),
1117 // Note: This does not actually assert the job is correct
1118 $addUpdateCallCounter = 0;
1119 $store->overrideDeferredUpdatesAddCallableUpdateCallback(
1120 function( $callable ) use ( &$addUpdateCallCounter ) {
1121 $addUpdateCallCounter++
;
1122 $this->assertInternalType( 'callable', $callable );
1126 $getTimestampCallCounter = 0;
1127 $store->overrideRevisionGetTimestampFromIdCallback(
1128 function( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) {
1129 $getTimestampCallCounter++
;
1130 $this->assertEquals( $title, $titleParam );
1131 $this->assertEquals( $oldid, $oldidParam );
1136 $store->resetNotificationTimestamp(
1143 $this->assertEquals( 1, $addUpdateCallCounter );
1144 $this->assertEquals( 1, $getTimestampCallCounter );
1147 public function testUpdateNotificationTimestamp_watchersExist() {
1148 $mockDb = $this->getMockDb();
1149 $mockDb->expects( $this->once() )
1150 ->method( 'select' )
1156 'wl_namespace' => 0,
1157 'wl_title' => 'SomeDbKey',
1158 'wl_notificationtimestamp IS NULL'
1162 $this->returnValue( [
1163 $this->getFakeRow( [ 'wl_user' => '2' ] ),
1164 $this->getFakeRow( [ 'wl_user' => '3' ] )
1167 $mockDb->expects( $this->once() )
1168 ->method( 'onTransactionIdle' )
1169 ->with( $this->isType( 'callable' ) )
1170 ->will( $this->returnCallback( function( $callable ) {
1173 $mockDb->expects( $this->once() )
1174 ->method( 'update' )
1177 [ 'wl_notificationtimestamp' => null ],
1179 'wl_user' => [ 2, 3 ],
1180 'wl_namespace' => 0,
1181 'wl_title' => 'SomeDbKey',
1185 $store = new WatchedItemStore(
1186 $this->getMockLoadBalancer( $mockDb ),
1187 new HashBagOStuff( [ 'maxKeys' => 100 ] )
1190 $this->assertEquals(
1192 $store->updateNotificationTimestamp(
1193 $this->getMockNonAnonUserWithId( 1 ),
1194 new TitleValue( 0, 'SomeDbKey' ),
1200 public function testUpdateNotificationTimestamp_noWatchers() {
1201 $mockDb = $this->getMockDb();
1202 $mockDb->expects( $this->once() )
1203 ->method( 'select' )
1209 'wl_namespace' => 0,
1210 'wl_title' => 'SomeDbKey',
1211 'wl_notificationtimestamp IS NULL'
1215 $this->returnValue( [] )
1217 $mockDb->expects( $this->never() )
1218 ->method( 'onTransactionIdle' );
1219 $mockDb->expects( $this->never() )
1220 ->method( 'update' );
1222 $store = new WatchedItemStore(
1223 $this->getMockLoadBalancer( $mockDb ),
1224 new HashBagOStuff( [ 'maxKeys' => 100 ] )
1227 $watchers = $store->updateNotificationTimestamp(
1228 $this->getMockNonAnonUserWithId( 1 ),
1229 new TitleValue( 0, 'SomeDbKey' ),
1232 $this->assertInternalType( 'array', $watchers );
1233 $this->assertEmpty( $watchers );