Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4057050
AbstractCheckUserPagerTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
AbstractCheckUserPagerTest.php
View Options
<?php
namespace
MediaWiki\CheckUser\Tests\Unit\CheckUser\Pagers
;
use
MediaWiki\CheckUser\CheckUserQueryInterface
;
use
MediaWiki\CheckUser\Tests\Integration\CheckUser\Pagers\DeAbstractedCheckUserPagerTest
;
use
MediaWiki\Html\FormOptions
;
use
MediaWiki\Message\Message
;
use
MediaWiki\Pager\IndexPager
;
use
MediaWiki\Tests\Unit\Libs\Rdbms\AddQuoterMock
;
use
MediaWikiUnitTestCase
;
use
Wikimedia\Rdbms\FakeResultWrapper
;
use
Wikimedia\Rdbms\IReadableDatabase
;
use
Wikimedia\Rdbms\IResultWrapper
;
use
Wikimedia\Rdbms\Platform\SQLPlatform
;
use
Wikimedia\Rdbms\SelectQueryBuilder
;
use
Wikimedia\TestingAccessWrapper
;
use
Wikimedia\Timestamp\ConvertibleTimestamp
;
/**
* Test class for AbstractCheckUserPager class
*
* @group CheckUser
*
* @covers \MediaWiki\CheckUser\CheckUser\Pagers\AbstractCheckUserPager
*/
class
AbstractCheckUserPagerTest
extends
MediaWikiUnitTestCase
{
public
function
testGetTimeRangeStringFirstAndLastEqual
()
{
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[
'getFormattedTimestamp'
]
)
->
getMock
();
$object
->
expects
(
$this
->
once
()
)
->
method
(
'getFormattedTimestamp'
)
->
willReturn
(
'mock_formatted_timestamp'
);
$object
=
TestingAccessWrapper
::
newFromObject
(
$object
);
$this
->
assertSame
(
'mock_formatted_timestamp'
,
$object
->
getTimeRangeString
(
'1653077137'
,
'1653077137'
),
'Return value of AbstractCheckUserPager::getTimeRangeString was not as expected.'
);
}
public
function
testGetTimeRangeStringFirstAndLastNotEqual
()
{
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[
'msg'
]
)
->
getMock
();
// Mock the Message class to assert that the message is constructed correctly.
$mockMessage
=
$this
->
createMock
(
Message
::
class
);
$mockMessage
->
expects
(
$this
->
once
()
)
->
method
(
'dateTimeParams'
)
->
with
(
'1653047635'
,
'1653077137'
)
->
willReturnSelf
();
$mockMessage
->
expects
(
$this
->
once
()
)
->
method
(
'escaped'
)
->
willReturn
(
'mock_formatted_timestamp'
);
$object
->
expects
(
$this
->
once
()
)
->
method
(
'msg'
)
->
with
(
'checkuser-time-range'
)
->
willReturn
(
$mockMessage
);
$object
=
TestingAccessWrapper
::
newFromObject
(
$object
);
$this
->
assertSame
(
'mock_formatted_timestamp'
,
$object
->
getTimeRangeString
(
'1653047635'
,
'1653077137'
),
'Return value of AbstractCheckUserPager::getTimeRangeString was not as expected.'
);
}
/** @dataProvider provideGetTimestampField */
public
function
testGetTimestampField
(
$table
,
$expectedTimestampField
)
{
$objectUnderTest
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[]
)
->
getMock
();
$this
->
assertSame
(
$expectedTimestampField
,
$objectUnderTest
->
getTimestampField
(
$table
),
'Return value of ::getTimestampField was not as expected.'
);
}
public
static
function
provideGetTimestampField
()
{
return
[
'Table as null'
=>
[
null
,
'timestamp'
],
'Table as cu_changes'
=>
[
CheckUserQueryInterface
::
CHANGES_TABLE
,
'cuc_timestamp'
],
'Table as cu_log_event'
=>
[
CheckUserQueryInterface
::
LOG_EVENT_TABLE
,
'cule_timestamp'
],
'Table as cu_private_event'
=>
[
CheckUserQueryInterface
::
PRIVATE_LOG_EVENT_TABLE
,
'cupe_timestamp'
],
];
}
/** @dataProvider provideSetPeriodCondition */
public
function
testSetPeriodCondition
(
$period
,
$fakeTime
,
$expected
)
{
ConvertibleTimestamp
::
setFakeTime
(
$fakeTime
);
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[]
)
->
getMock
();
# Mock the DB as a SQLPlatform as ::setPeriodCondition only uses methods
# included in SQLPlatform.
$object
=
TestingAccessWrapper
::
newFromObject
(
$object
);
$object
->
mDb
=
new
SQLPlatform
(
new
AddQuoterMock
()
);
$object
->
opts
=
new
FormOptions
();
$object
->
opts
->
add
(
'period'
,
''
);
$object
->
opts
->
setValue
(
'period'
,
$period
,
true
);
# Call method under test
$object
->
setPeriodCondition
();
if
(
$expected
)
{
$expected
=
$object
->
mDb
->
timestamp
(
$expected
);
$this
->
assertArrayEquals
(
[
$expected
,
''
],
$object
->
getRangeOffsets
(),
false
,
false
,
'A different time period condition was generated than expected.'
);
}
else
{
$this
->
assertArrayEquals
(
[
''
,
''
],
$object
->
getRangeOffsets
(),
false
,
false
,
'Time period conditions were generated when they were not supposed to be.'
);
}
}
public
static
function
provideSetPeriodCondition
()
{
return
[
'Empty period'
=>
[
''
,
'1653047635'
,
false
],
'Period value for all'
=>
[
0
,
'1653047635'
,
false
],
'Period value for 7 days'
=>
[
7
,
'1653077137'
,
'20220513000000'
],
'Period value for 30 days'
=>
[
30
,
'1653047635'
,
'20220420000000'
],
];
}
public
function
testGetCheckUserHelperFieldsetWhenNoResults
()
{
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
getMock
();
$object
=
TestingAccessWrapper
::
newFromObject
(
$object
);
$object
->
mResult
=
$this
->
createMock
(
IResultWrapper
::
class
);
$object
->
mResult
->
method
(
'numRows'
)->
willReturn
(
0
);
$this
->
assertNull
(
$object
->
getCheckUserHelperFieldset
(),
'The fieldset should not be shown if there are no results.'
);
}
/** @dataProvider provideBuildQueryInfo */
public
function
testBuildQueryInfo
(
$offset
,
$limit
,
$order
,
$startOffset
,
$endOffset
,
$includeOffset
,
$mockedQueryInfo
,
$partialExpectedArray
)
{
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[
'getQueryInfo'
]
)
->
getMock
();
// Mock ::getQueryInfo to return the query info for each three queries in turn.
$object
->
method
(
'getQueryInfo'
)
->
willReturnCallback
(
static
fn
(
$table
)
=>
$mockedQueryInfo
[
$table
]
);
$object
->
setIncludeOffset
(
$includeOffset
);
$object
->
mDb
=
new
SQLPlatform
(
new
AddQuoterMock
()
);
$object
=
TestingAccessWrapper
::
newFromObject
(
$object
);
# Set the start and end offset.
$object
->
endOffset
=
$endOffset
;
$object
->
startOffset
=
$startOffset
;
# Needed because the constructor was disabled. These would be set by the constructor.
$object
->
mIndexField
=
'timestamp'
;
$object
->
mExtraSortFields
=
[];
# Call the method under test.
$queryInfo
=
$object
->
buildQueryInfo
(
$offset
,
$limit
,
$order
);
$this
->
assertCount
(
3
,
$queryInfo
,
'::buildQueryInfo should have returned query info for three queries.'
);
foreach
(
$queryInfo
as
$table
=>
$queryInfoForTable
)
{
$this
->
assertArrayContains
(
$partialExpectedArray
[
$table
],
$queryInfoForTable
,
"::buildQueryInfo result was not correct for table $table."
);
}
}
public
static
function
provideBuildQueryInfo
()
{
return
[
'Offset, limit 20, order ASC, include offset'
=>
[
'test_offset'
,
20
,
IndexPager
::
QUERY_ASCENDING
,
''
,
''
,
true
,
[
CheckUserQueryInterface
::
CHANGES_TABLE
=>
[
'tables'
=>
[
'cu_changes'
],
'fields'
=>
[
'timestamp'
,
'alias'
=>
'test'
],
'conds'
=>
[
'cond'
=>
'test'
],
'options'
=>
[],
'join_conds'
=>
[]
],
CheckUserQueryInterface
::
LOG_EVENT_TABLE
=>
[
'tables'
=>
[
'cu_log_event'
],
'fields'
=>
[
'timestamp'
,
'alias'
=>
'test2'
],
'conds'
=>
[
'cond'
=>
'test2'
],
'options'
=>
[],
'join_conds'
=>
[
'logging'
=>
'test'
]
],
CheckUserQueryInterface
::
PRIVATE_LOG_EVENT_TABLE
=>
[
'tables'
=>
[
'cu_private_event'
],
'fields'
=>
[
'timestamp'
,
'alias'
=>
'test3'
],
'conds'
=>
[
'cond'
=>
'test3'
],
'options'
=>
[],
'join_conds'
=>
[]
],
],
[
CheckUserQueryInterface
::
CHANGES_TABLE
=>
[
// tables
0
=>
[
'cu_changes'
],
// fields
1
=>
[
'timestamp'
,
'alias'
=>
'test'
],
// where conds
2
=>
[
'cond'
=>
'test'
,
"cuc_timestamp >= 'test_offset'"
],
// options
4
=>
[
'LIMIT'
=>
20
,
'ORDER BY'
=>
[
'timestamp'
]
],
// join_conds
5
=>
[],
],
CheckUserQueryInterface
::
LOG_EVENT_TABLE
=>
[
// tables
0
=>
[
'cu_log_event'
],
// fields
1
=>
[
'timestamp'
,
'alias'
=>
'test2'
],
// where conds
2
=>
[
'cond'
=>
'test2'
,
"cule_timestamp >= 'test_offset'"
],
// options
4
=>
[
'LIMIT'
=>
20
,
'ORDER BY'
=>
[
'timestamp'
]
],
// join_conds
5
=>
[
'logging'
=>
'test'
],
],
CheckUserQueryInterface
::
PRIVATE_LOG_EVENT_TABLE
=>
[
// tables
0
=>
[
'cu_private_event'
],
// fields
1
=>
[
'timestamp'
,
'alias'
=>
'test3'
],
// where conds
2
=>
[
'cond'
=>
'test3'
,
"cupe_timestamp >= 'test_offset'"
],
// options
4
=>
[
'LIMIT'
=>
20
,
'ORDER BY'
=>
[
'timestamp'
]
],
// join_conds
5
=>
[],
],
]
],
];
}
/** @dataProvider provideReallyDoQuery */
public
function
testReallyDoQuery
(
$limit
,
$order
,
$fakeResults
,
$expectedReturnResults
)
{
$object
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[
'buildQueryInfo'
]
)
->
getMock
();
// Mock the DB
$mockDb
=
$this
->
createMock
(
IReadableDatabase
::
class
);
// Mock the select method
$mockedQueryInfoForCuChanges
=
[
[
'cu_changes'
],
[
'timestamp'
],
[],
'fname'
,
[],
[]
];
$mockedQueryInfoForCuLogEvent
=
[
[
'cu_log_event'
],
[
'timestamp'
],
[],
'fname'
,
[],
[]
];
$mockedQueryInfoForCuPrivateEvent
=
[
[
'cu_private_event'
],
[
'timestamp'
],
[],
'fname'
,
[],
[]
];
$object
->
expects
(
$this
->
once
()
)
->
method
(
'buildQueryInfo'
)
->
willReturn
(
[
$mockedQueryInfoForCuChanges
,
$mockedQueryInfoForCuLogEvent
,
$mockedQueryInfoForCuPrivateEvent
]
);
$mockDb
->
method
(
'newSelectQueryBuilder'
)->
willReturnCallback
(
static
function
()
use
(
$mockDb
)
{
return
new
SelectQueryBuilder
(
$mockDb
);
}
);
$expectedSelects
=
[
'cu_changes'
=>
true
,
'cu_log_event'
=>
true
,
'cu_private_event'
=>
true
];
$mockDb
->
expects
(
$this
->
exactly
(
3
)
)
->
method
(
'select'
)
->
willReturnCallback
(
function
(
$tables
,
$vars
,
$_
,
$fname
)
use
(
&
$expectedSelects
,
$fakeResults
)
{
$this
->
assertIsArray
(
$tables
);
$this
->
assertCount
(
1
,
$tables
);
$table
=
$tables
[
0
];
$this
->
assertArrayHasKey
(
$table
,
$expectedSelects
);
unset
(
$expectedSelects
[
$table
]
);
$this
->
assertSame
(
[
'timestamp'
],
$vars
);
$this
->
assertSame
(
'fname'
,
$fname
);
return
$fakeResults
[
$table
];
}
);
$object
->
mDb
=
$mockDb
;
$returnResults
=
$object
->
reallyDoQuery
(
''
,
$limit
,
$order
);
$this
->
assertSame
(
count
(
$expectedReturnResults
),
$returnResults
->
count
(),
'Unexpected number of results returned by ::reallyDoQuery.'
);
if
(
$returnResults
->
count
()
)
{
$fetchRowResult
=
$returnResults
->
fetchRow
();
while
(
$fetchRowResult
)
{
$this
->
assertArrayEquals
(
$expectedReturnResults
[
$returnResults
->
key
()],
$fetchRowResult
,
false
,
false
,
"Returned results from ::reallyDoQuery at index {$returnResults->key()} were not as expected."
);
$fetchRowResult
=
$returnResults
->
fetchRow
();
}
}
}
public
static
function
provideReallyDoQuery
()
{
# Generate rows to return from IDatabase::select with just the timestamp for testing.
$fakeResultsOrderDesc
=
[];
$fakeResultsOrderAsc
=
[];
$fakeResultsPerTable
=
[];
$fakeResultsOrderDescForReadOld
=
[];
$fakeResultsOrderAscForReadOld
=
[];
for
(
$i
=
0
;
$i
<
10
;
$i
++
)
{
foreach
(
CheckUserQueryInterface
::
RESULT_TABLES
as
$tableIndex
=>
$table
)
{
$row
=
[
'timestamp'
=>
'202301052123'
.
$i
.
$tableIndex
,
'title'
=>
'Test'
.
$table
.
$i
];
$fakeResultsOrderDesc
[
'202301052123'
.
$i
.
$tableIndex
]
=
$row
;
$fakeResultsOrderAsc
[
'202301052123'
.
$i
.
$tableIndex
]
=
$row
;
if
(
$table
===
CheckUserQueryInterface
::
CHANGES_TABLE
)
{
$fakeResultsOrderDescForReadOld
[
'202301052123'
.
$i
.
$tableIndex
]
=
$row
;
$fakeResultsOrderAscForReadOld
[
'202301052123'
.
$i
.
$tableIndex
]
=
$row
;
}
$fakeResultsPerTable
[
$table
][]
=
$row
;
}
}
# Wrap the results in a FakeResultWrapper
$fakeResultsPerTable
=
array_map
(
static
function
(
$results_array
)
{
return
new
FakeResultWrapper
(
$results_array
);
},
$fakeResultsPerTable
);
# Generate the expected return results for different conditions.
krsort
(
$fakeResultsOrderDescForReadOld
);
$fakeResultsOrderDescForReadOld
=
array_values
(
$fakeResultsOrderDescForReadOld
);
ksort
(
$fakeResultsOrderAscForReadOld
);
$fakeResultsOrderAscForReadOld
=
array_values
(
$fakeResultsOrderAscForReadOld
);
krsort
(
$fakeResultsOrderDesc
);
$fakeResultsOrderDesc
=
array_values
(
$fakeResultsOrderDesc
);
ksort
(
$fakeResultsOrderAsc
);
$fakeResultsOrderAsc
=
array_values
(
$fakeResultsOrderAsc
);
# Start test cases
return
[
'Limit 500, order ASC'
=>
[
500
,
IndexPager
::
QUERY_ASCENDING
,
$fakeResultsPerTable
,
$fakeResultsOrderAsc
],
'Limit 10, order DESC'
=>
[
10
,
IndexPager
::
QUERY_DESCENDING
,
$fakeResultsPerTable
,
array_slice
(
$fakeResultsOrderDesc
,
0
,
10
)
],
'Limit 10, order ASC'
=>
[
10
,
IndexPager
::
QUERY_ASCENDING
,
$fakeResultsPerTable
,
array_slice
(
$fakeResultsOrderAsc
,
0
,
10
)
],
];
}
/** @dataProvider provideGroupResultsByIndexField */
public
function
testGroupResultsByIndexField
(
$indexField
,
$results
,
$expectedGroupedResults
)
{
$objectUnderTest
=
$this
->
getMockBuilder
(
DeAbstractedCheckUserPagerTest
::
class
)
->
disableOriginalConstructor
()
->
onlyMethods
(
[
'getIndexField'
]
)
->
getMock
();
$objectUnderTest
->
method
(
'getIndexField'
)
->
willReturn
(
$indexField
);
$objectUnderTest
=
TestingAccessWrapper
::
newFromObject
(
$objectUnderTest
);
$this
->
assertArrayEquals
(
$expectedGroupedResults
,
$objectUnderTest
->
groupResultsByIndexField
(
$results
),
true
,
true
,
'::groupResultsByIndexField did not group the results in the expected way.'
);
}
public
static
function
provideGroupResultsByIndexField
()
{
$currentTimestamp
=
ConvertibleTimestamp
::
now
();
$otherTimestamp
=
'20220904094043'
;
return
[
'Timestamp index field for 3 rows with no duplicate timestamps'
=>
[
'timestamp'
,
[
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
111
],
(
object
)[
'timestamp'
=>
$otherTimestamp
,
'id'
=>
23
],
],
[
$currentTimestamp
=>
[
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
111
]
],
$otherTimestamp
=>
[
(
object
)[
'timestamp'
=>
$otherTimestamp
,
'id'
=>
23
]
],
]
],
'Timestamp index field for 3 rows with duplicate timestamps'
=>
[
'timestamp'
,
[
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
1
],
(
object
)[
'timestamp'
=>
$otherTimestamp
,
'id'
=>
2
],
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
3
],
],
[
$currentTimestamp
=>
[
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
1
],
(
object
)[
'timestamp'
=>
$currentTimestamp
,
'id'
=>
3
],
],
$otherTimestamp
=>
[
(
object
)[
'timestamp'
=>
$otherTimestamp
,
'id'
=>
2
],
],
]
]
];
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Aug 16 2026, 03:48 (12 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
28/cc/e3b80a9ddc9bb01b436633c1e954
Default Alt Text
AbstractCheckUserPagerTest.php (14 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment