3 use MediaWiki\CommentStore\CommentStoreComment
;
4 use MediaWiki\Content\WikitextContent
;
5 use MediaWiki\Deferred\DeferredUpdates
;
6 use MediaWiki\Deferred\UserEditCountUpdate
;
7 use MediaWiki\Revision\MutableRevisionRecord
;
8 use MediaWiki\Revision\SlotRecord
;
9 use MediaWiki\Tests\User\TempUser\TempUserTestTrait
;
10 use MediaWiki\Title\Title
;
11 use MediaWiki\User\UserIdentity
;
12 use MediaWiki\User\UserIdentityValue
;
13 use MediaWiki\User\UserRigorOptions
;
16 * @covers \MediaWiki\User\UserEditTracker
19 class UserEditTrackerTest
extends MediaWikiIntegrationTestCase
{
21 use TempUserTestTrait
;
26 * @param UserIdentity $user
27 * @param string $timestamp
29 private function editTrackerDoEdit( $user, $timestamp ) {
30 $title = Title
::newFromText( __FUNCTION__
);
31 $page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
32 if ( !$page->exists() ) {
33 $page->insertOn( $this->getDb() );
36 $rev = new MutableRevisionRecord( $title );
37 $rev->setContent( SlotRecord
::MAIN
, new WikitextContent( $timestamp ) );
38 $rev->setComment( CommentStoreComment
::newUnsavedComment( '' ) );
39 $rev->setTimestamp( $timestamp );
40 $rev->setUser( $user );
41 $rev->setPageId( $page->getId() );
42 $this->getServiceContainer()->getRevisionStore()->insertRevisionOn( $rev, $this->getDb() );
46 * Change the user_editcount field in the DB
48 * @param UserIdentity $user
49 * @param int|null $count
51 private function setDbEditCount( $user, $count ) {
52 $this->getDb()->newUpdateQueryBuilder()
54 ->set( [ 'user_editcount' => $count ] )
55 ->where( [ 'user_id' => $user->getId() ] )
56 ->caller( __METHOD__
)
60 public function testGetUserEditCount() {
61 // Set user_editcount to 5
62 $user = $this->getMutableTestUser()->getUser();
63 $update = new UserEditCountUpdate( $user, 5 );
66 $tracker = $this->getServiceContainer()->getUserEditTracker();
67 $this->assertSame( 5, $tracker->getUserEditCount( $user ) );
69 // Now fetch from cache
70 $this->assertSame( 5, $tracker->getUserEditCount( $user ) );
73 public function testGetUserEditCount_anon() {
74 // getUserEditCount returns null if the user is unregistered
75 $anon = UserIdentityValue
::newAnonymous( '1.2.3.4' );
76 $tracker = $this->getServiceContainer()->getUserEditTracker();
77 $this->assertNull( $tracker->getUserEditCount( $anon ) );
80 public function testGetUserEditCount_null() {
81 // getUserEditCount doesn't find a value in user_editcount and calls
82 // initializeUserEditCount
83 $user = $this->getMutableTestUser()->getUserIdentity();
84 $this->setDbEditCount( $user, null );
85 $tracker = $this->getServiceContainer()->getUserEditTracker();
86 $this->assertSame( 0, $tracker->getUserEditCount( $user ) );
89 public function testInitializeUserEditCount() {
90 $user = $this->getMutableTestUser()->getUser();
91 $this->editTrackerDoEdit( $user, '20200101000000' );
92 $tracker = $this->getServiceContainer()->getUserEditTracker();
93 $tracker->initializeUserEditCount( $user );
95 $this->assertSame( 1, $tracker->getUserEditCount( $user ) );
98 public function testGetEditTimestamp() {
99 $user = $this->getMutableTestUser()->getUser();
100 $tracker = $this->getServiceContainer()->getUserEditTracker();
101 $this->assertFalse( $tracker->getFirstEditTimestamp( $user ) );
102 $this->assertFalse( $tracker->getLatestEditTimestamp( $user ) );
104 $ts1 = '20010101000000';
105 $ts2 = '20020101000000';
106 $ts3 = '20030101000000';
107 $this->editTrackerDoEdit( $user, $ts3 );
108 $this->editTrackerDoEdit( $user, $ts2 );
109 $this->editTrackerDoEdit( $user, $ts1 );
111 $this->assertSame( $ts1, $tracker->getFirstEditTimestamp( $user ) );
112 $this->assertSame( $ts3, $tracker->getLatestEditTimestamp( $user ) );
115 public function testGetEditTimestamp_anon() {
116 $this->disableAutoCreateTempUser();
117 $user = $this->getServiceContainer()->getUserFactory()
118 ->newFromName( '127.0.0.1', UserRigorOptions
::RIGOR_NONE
);
119 $tracker = $this->getServiceContainer()->getUserEditTracker();
120 $this->editTrackerDoEdit( $user, '20200101000000' );
121 $this->assertFalse( $tracker->getFirstEditTimestamp( $user ) );
122 $this->assertFalse( $tracker->getLatestEditTimestamp( $user ) );
125 public function testClearUserEditCache() {
126 $user = $this->getMutableTestUser()->getUser();
127 $tracker = $this->getServiceContainer()->getUserEditTracker();
128 $this->assertSame( 0, $tracker->getUserEditCount( $user ) );
129 $this->setDbEditCount( $user, 1 );
130 $this->assertSame( 0, $tracker->getUserEditCount( $user ) );
131 $tracker->clearUserEditCache( $user );
132 $this->assertSame( 1, $tracker->getUserEditCount( $user ) );
135 public function testIncrementUserEditCount() {
136 $tracker = $this->getServiceContainer()->getUserEditTracker();
137 $user = $this->getMutableTestUser()->getUser();
139 $editCountStart = $tracker->getUserEditCount( $user );
141 $this->getDb()->startAtomic( __METHOD__
); // let deferred updates queue up
143 $tracker->incrementUserEditCount( $user );
146 DeferredUpdates
::pendingUpdatesCount(),
147 'Update queued for registered user'
150 $tracker->incrementUserEditCount( UserIdentityValue
::newAnonymous( '1.1.1.1' ) );
153 DeferredUpdates
::pendingUpdatesCount(),
154 'No update queued for anonymous user'
157 $this->getDb()->endAtomic( __METHOD__
); // run deferred updates
158 $this->runDeferredUpdates();
162 DeferredUpdates
::pendingUpdatesCount(),
163 'deferred updates ran'
166 $editCountEnd = $tracker->getUserEditCount( $user );
169 $editCountEnd - $editCountStart,
170 'Edit count was incremented'
174 public function testManualCache() {
175 // Make sure manually setting the cached value overrides the database, in case
176 // User::loadFromRow() is called with a row containing user_editcount that is
177 // different from the actual database value, the row takes precedence
178 $user = new UserIdentityValue( 123, __METHOD__
);
179 $this->setDbEditCount( $user, 5 );
181 $tracker = $this->getServiceContainer()->getUserEditTracker();
182 $tracker->setCachedUserEditCount( $user, 10 );
183 $this->assertSame( 10, $tracker->getUserEditCount( $user ) );