3 use MediaWiki\MainConfigNames
;
4 use MediaWiki\Title\Title
;
5 use MediaWiki\Utils\MWTimestamp
;
6 use Wikimedia\Rdbms\IDatabase
;
7 use Wikimedia\Timestamp\ConvertibleTimestamp
;
10 * Tests for CategoryChangesAsRdf recent changes exporter.
11 * @covers \CategoryChangesAsRdf
14 class CategoryChangesAsRdfTest
extends MediaWikiLangTestCase
{
16 protected function setUp(): void
{
18 $this->overrideConfigValues( [
19 MainConfigNames
::Server
=> 'http://acme.test',
20 MainConfigNames
::CanonicalServer
=> 'http://acme.test',
24 public static function provideCategoryData() {
26 'delete category' => [
27 __DIR__
. "/../data/categoriesrdf/delete.sparql",
28 'getDeletedCatsIterator',
31 (object)[ 'rc_title' => 'Test', 'rc_cur_id' => 1, '_processed' => 1 ],
32 (object)[ 'rc_title' => 'Test 2', 'rc_cur_id' => 2, '_processed' => 2 ],
36 __DIR__
. "/../data/categoriesrdf/move.sparql",
37 'getMovedCatsIterator',
43 'page_title' => 'MovedTo',
44 'page_namespace' => NS_CATEGORY
,
46 'pp_propname' => null,
52 'rc_title' => 'MovedTo',
54 'page_title' => 'MovedAgain',
55 'page_namespace' => NS_CATEGORY
,
56 'pp_propname' => 'hiddencat',
62 'rc_title' => 'Test 2',
64 'page_title' => 'AlsoMoved',
65 'page_namespace' => NS_CATEGORY
,
67 'pp_propname' => null,
73 'rc_title' => 'Test 3',
75 'page_title' => 'MovedOut',
76 'page_namespace' => NS_MAIN
,
77 'pp_propname' => null,
83 'rc_title' => 'Test 4',
85 'page_title' => 'Already Done',
86 'page_namespace' => NS_CATEGORY
,
87 'pp_propname' => null,
95 'restore deleted category' => [
96 __DIR__
. "/../data/categoriesrdf/restore.sparql",
97 'getRestoredCatsIterator',
101 'rc_title' => 'Restored cat',
104 'pp_propname' => null,
110 'rc_title' => 'Restored again',
112 'pp_propname' => null,
118 'rc_title' => 'Already seen',
120 'pp_propname' => null,
129 __DIR__
. "/../data/categoriesrdf/new.sparql",
130 'getNewCatsIterator',
134 'rc_title' => 'New category',
137 'pp_propname' => null,
143 'rc_title' => 'Новая категория 😃',
146 'pp_propname' => 'hiddencat',
152 'rc_title' => 'Processed already',
159 __DIR__
. "/../data/categoriesrdf/edit.sparql",
160 'getChangedCatsIterator',
164 'rc_title' => 'Changed category',
167 'pp_propname' => null,
173 'rc_title' => 'Changed again',
175 'pp_propname' => null,
181 'rc_title' => 'Processed already',
183 'pp_propname' => null,
191 // TODO: not sure how to test categorization changes, it uses the database select...
196 * Mock category links iterator.
197 * @param IDatabase $dbr
201 public function getCategoryLinksIterator( $dbr, array $ids ) {
203 foreach ( $ids as $pageid ) {
204 $res[] = (object)[ 'cl_from' => $pageid, 'cl_to' => "Parent of $pageid" ];
210 * @dataProvider provideCategoryData
211 * @param string $testFileName Name of the test, defines filename with expected results.
212 * @param string $iterator Iterator method name to mock
213 * @param string $handler Handler method to call
214 * @param array $result Result to be returned from mock iterator
215 * @param array $preProcessed List of pre-processed items
217 public function testSparqlUpdate( $testFileName, $iterator, $handler, $result,
218 array $preProcessed = [] ) {
220 $this->getMockBuilder( CategoryChangesAsRdf
::class )
221 ->onlyMethods( [ $iterator, 'getCategoryLinksIterator' ] )
224 $dumpScript->method( 'getCategoryLinksIterator' )
225 ->willReturnCallback( [ $this, 'getCategoryLinksIterator' ] );
227 $dumpScript->expects( $this->once() )
228 ->method( $iterator )
229 ->willReturn( [ $result ] );
231 $ref = new ReflectionObject( $dumpScript );
232 $processedProperty = $ref->getProperty( 'processed' );
233 $processedProperty->setAccessible( true );
234 $processedProperty->setValue( $dumpScript, $preProcessed );
236 $output = fopen( "php://memory", "w+b" );
237 $dbr = $this->getDb();
238 /** @var CategoryChangesAsRdf $dumpScript */
239 $dumpScript->initialize();
240 $dumpScript->getRdf();
241 $dumpScript->$handler( $dbr, $output );
244 $sparql = stream_get_contents( $output );
245 $this->assertFileContains( $testFileName, $sparql );
247 $processed = $processedProperty->getValue( $dumpScript );
248 $expectedProcessed = array_keys( $preProcessed );
249 foreach ( $result as $row ) {
250 if ( isset( $row->_processed
) ) {
251 $this->assertArrayHasKey( $row->_processed
, $processed,
252 "ID {$row->_processed} was not processed!" );
253 $expectedProcessed[] = $row->_processed
;
256 $this->assertSame( $expectedProcessed, array_keys( $processed ),
257 'Processed array has wrong items' );
260 public function testUpdateTs() {
261 $dumpScript = new CategoryChangesAsRdf();
262 $dumpScript->initialize();
263 $update = $dumpScript->updateTS( 1503620949 );
264 $outFile = __DIR__
. '/../data/categoriesrdf/updatets.txt';
265 $this->assertFileContains( $outFile, $update );
268 public function testCategorization() {
269 $this->overrideConfigValue(
270 MainConfigNames
::RCWatchCategoryMembership
,
273 $start = new MWTimestamp( "2020-07-31T10:00:00" );
274 $end = new MWTimestamp( "2020-07-31T10:01:00" );
275 ConvertibleTimestamp
::setFakeTime( "2020-07-31T10:00:00" );
276 $l1 = Title
::makeTitle( NS_CATEGORY
, __CLASS__
. "_L1" );
277 $l2 = Title
::makeTitle( NS_CATEGORY
, __CLASS__
. "_L2" );
278 $pageInL2 = Title
::makeTitle( NS_CATEGORY
, __CLASS__
. "_Page" );
279 $this->editPage( $l1, "" );
280 $this->editPage( $l2, "[[{$l1->getPrefixedText()}]]" );
281 $this->editPage( $pageInL2, "[[{$l2->getPrefixedText()}]]" );
283 $output = fopen( "php://memory", "w+b" );
285 $this->runJobs( [], [
286 'type' => 'categoryMembershipChange'
289 $dbr = $this->getDb();
290 $categoryChangesAsRdf = new CategoryChangesAsRdf();
292 $ref = new ReflectionObject( $categoryChangesAsRdf );
293 $startTSProp = $ref->getProperty( 'startTS' );
294 $startTSProp->setAccessible( true );
295 $startTSProp->setValue( $categoryChangesAsRdf, $start->getTimestamp() );
296 $endTSProp = $ref->getProperty( 'endTS' );
297 $endTSProp->setAccessible( true );
298 $endTSProp->setValue( $categoryChangesAsRdf, $end->getTimestamp() );
300 $categoryChangesAsRdf->initialize();
301 $categoryChangesAsRdf->getRdf();
302 $categoryChangesAsRdf->handleCategorization( $dbr, $output );
304 $sparql = stream_get_contents( $output );
305 $outFile = __DIR__
. '/../data/categoriesrdf/categorization.txt';
306 $this->assertFileContains( $outFile, $sparql );