MediaWiki  1.33.0
RevisionTest.php
Go to the documentation of this file.
1 <?php
2 
13 
19 
20  public function setUp() {
21  parent::setUp();
22  $this->setMwGlobals(
23  'wgMultiContentRevisionSchemaMigrationStage',
25  );
26  }
27 
28  public function provideConstructFromArray() {
29  yield 'with text' => [
30  [
31  'text' => 'hello world.',
32  'content_model' => CONTENT_MODEL_JAVASCRIPT
33  ],
34  ];
35  yield 'with content' => [
36  [
37  'content' => new JavaScriptContent( 'hellow world.' )
38  ],
39  ];
40  // FIXME: test with and without user ID, and with a user object.
41  // We can't prepare that here though, since we don't yet have a dummy DB
42  }
43 
48  public function getMockTitle( $model = CONTENT_MODEL_WIKITEXT ) {
49  $mock = $this->getMockBuilder( Title::class )
50  ->disableOriginalConstructor()
51  ->getMock();
52  $mock->expects( $this->any() )
53  ->method( 'getNamespace' )
54  ->will( $this->returnValue( $this->getDefaultWikitextNS() ) );
55  $mock->expects( $this->any() )
56  ->method( 'getPrefixedText' )
57  ->will( $this->returnValue( 'RevisionTest' ) );
58  $mock->expects( $this->any() )
59  ->method( 'getDBkey' )
60  ->will( $this->returnValue( 'RevisionTest' ) );
61  $mock->expects( $this->any() )
62  ->method( 'getArticleID' )
63  ->will( $this->returnValue( 23 ) );
64  $mock->expects( $this->any() )
65  ->method( 'getContentModel' )
66  ->will( $this->returnValue( $model ) );
67 
68  return $mock;
69  }
70 
76  public function testConstructFromArray( $rowArray ) {
77  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
78  $this->assertNotNull( $rev->getContent(), 'no content object available' );
79  $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
80  $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
81  }
82 
87  public function testConstructFromEmptyArray() {
88  $rev = new Revision( [], 0, $this->getMockTitle() );
89  $this->assertNull( $rev->getContent(), 'no content object should be available' );
90  }
91 
97  Wikimedia\suppressWarnings();
98  $rev = new Revision( [ 'page' => 77777777 ] );
99  $this->assertSame( 77777777, $rev->getPage() );
100  Wikimedia\restoreWarnings();
101  }
102 
104  yield 'no user defaults to wgUser' => [
105  [
106  'content' => new JavaScriptContent( 'hello world.' ),
107  ],
108  null,
109  null,
110  ];
111  yield 'user text and id' => [
112  [
113  'content' => new JavaScriptContent( 'hello world.' ),
114  'user_text' => 'SomeTextUserName',
115  'user' => 99,
116 
117  ],
118  99,
119  'SomeTextUserName',
120  ];
121  yield 'user text only' => [
122  [
123  'content' => new JavaScriptContent( 'hello world.' ),
124  'user_text' => '111.111.111.111',
125  ],
126  0,
127  '111.111.111.111',
128  ];
129  }
130 
141  array $rowArray,
142  $expectedUserId,
143  $expectedUserName
144  ) {
145  $testUser = $this->getTestUser()->getUser();
146  $this->setMwGlobals( 'wgUser', $testUser );
147  if ( $expectedUserId === null ) {
148  $expectedUserId = $testUser->getId();
149  }
150  if ( $expectedUserName === null ) {
151  $expectedUserName = $testUser->getName();
152  }
153 
154  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
155  $this->assertEquals( $expectedUserId, $rev->getUser() );
156  $this->assertEquals( $expectedUserName, $rev->getUserText() );
157  }
158 
160  yield 'content and text_id both not empty' => [
161  [
162  'content' => new WikitextContent( 'GOAT' ),
163  'text_id' => 'someid',
164  ],
165  new MWException( 'The text_id field is only available in the pre-MCR schema' )
166  ];
167 
168  yield 'with bad content object (class)' => [
169  [ 'content' => new stdClass() ],
170  new MWException( 'content field must contain a Content object' )
171  ];
172  yield 'with bad content object (string)' => [
173  [ 'content' => 'ImAGoat' ],
174  new MWException( 'content field must contain a Content object' )
175  ];
176  yield 'bad row format' => [
177  'imastring, not a row',
178  new InvalidArgumentException(
179  '$row must be a row object, an associative array, or a RevisionRecord'
180  )
181  ];
182  }
183 
189  public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
190  $this->setExpectedException(
191  get_class( $expectedException ),
192  $expectedException->getMessage(),
193  $expectedException->getCode()
194  );
195  new Revision( $rowArray, 0, $this->getMockTitle() );
196  }
197 
202  public function testConstructFromNothing() {
203  $this->setExpectedException(
205  );
206  new Revision( [] );
207  }
208 
209  public function provideConstructFromRow() {
210  yield 'Full construction' => [
211  [
212  'rev_id' => '42',
213  'rev_page' => '23',
214  'rev_timestamp' => '20171017114835',
215  'rev_user_text' => '127.0.0.1',
216  'rev_user' => '0',
217  'rev_minor_edit' => '0',
218  'rev_deleted' => '0',
219  'rev_len' => '46',
220  'rev_parent_id' => '1',
221  'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
222  'rev_comment_text' => 'Goat Comment!',
223  'rev_comment_data' => null,
224  'rev_comment_cid' => null,
225  ],
226  function ( RevisionTest $testCase, Revision $rev ) {
227  $testCase->assertSame( 42, $rev->getId() );
228  $testCase->assertSame( 23, $rev->getPage() );
229  $testCase->assertSame( '20171017114835', $rev->getTimestamp() );
230  $testCase->assertSame( '127.0.0.1', $rev->getUserText() );
231  $testCase->assertSame( 0, $rev->getUser() );
232  $testCase->assertSame( false, $rev->isMinor() );
233  $testCase->assertSame( false, $rev->isDeleted( Revision::DELETED_TEXT ) );
234  $testCase->assertSame( 46, $rev->getSize() );
235  $testCase->assertSame( 1, $rev->getParentId() );
236  $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() );
237  $testCase->assertSame( 'Goat Comment!', $rev->getComment() );
238  }
239  ];
240  yield 'default field values' => [
241  [
242  'rev_id' => '42',
243  'rev_page' => '23',
244  'rev_timestamp' => '20171017114835',
245  'rev_user_text' => '127.0.0.1',
246  'rev_user' => '0',
247  'rev_minor_edit' => '0',
248  'rev_deleted' => '0',
249  'rev_comment_text' => 'Goat Comment!',
250  'rev_comment_data' => null,
251  'rev_comment_cid' => null,
252  ],
253  function ( RevisionTest $testCase, Revision $rev ) {
254  // parent ID may be null
255  $testCase->assertSame( null, $rev->getParentId(), 'revision id' );
256 
257  // given fields
258  $testCase->assertSame( $rev->getTimestamp(), '20171017114835', 'timestamp' );
259  $testCase->assertSame( $rev->getUserText(), '127.0.0.1', 'user name' );
260  $testCase->assertSame( $rev->getUser(), 0, 'user id' );
261  $testCase->assertSame( $rev->getComment(), 'Goat Comment!' );
262  $testCase->assertSame( false, $rev->isMinor(), 'minor edit' );
263  $testCase->assertSame( 0, $rev->getVisibility(), 'visibility flags' );
264  }
265  ];
266  }
267 
273  public function testConstructFromRow( array $arrayData, callable $assertions ) {
274  $row = (object)$arrayData;
275  $rev = new Revision( $row, 0, $this->getMockTitle() );
276  $assertions( $this, $rev );
277  }
278 
284  $this->overrideMwServices();
285  Wikimedia\suppressWarnings();
286  $rev = new Revision( (object)[
287  'rev_page' => 77777777,
288  'rev_comment_text' => '',
289  'rev_comment_data' => null,
290  ] );
291  $this->assertSame( 77777777, $rev->getPage() );
292  Wikimedia\restoreWarnings();
293  }
294 
295  public function provideGetId() {
296  yield [
297  [],
298  null
299  ];
300  yield [
301  [ 'id' => 998 ],
302  998
303  ];
304  }
305 
310  public function testGetId( $rowArray, $expectedId ) {
311  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
312  $this->assertEquals( $expectedId, $rev->getId() );
313  }
314 
315  public function provideSetId() {
316  yield [ '123', 123 ];
317  yield [ 456, 456 ];
318  }
319 
324  public function testSetId( $input, $expected ) {
325  $rev = new Revision( [], 0, $this->getMockTitle() );
326  $rev->setId( $input );
327  $this->assertSame( $expected, $rev->getId() );
328  }
329 
330  public function provideSetUserIdAndName() {
331  yield [ '123', 123, 'GOaT' ];
332  yield [ 456, 456, 'GOaT' ];
333  }
334 
339  public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
340  $rev = new Revision( [], 0, $this->getMockTitle() );
341  $rev->setUserIdAndName( $inputId, $name );
342  $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
343  $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
344  }
345 
346  public function provideGetParentId() {
347  yield [ [], null ];
348  yield [ [ 'parent_id' => '123' ], 123 ];
349  yield [ [ 'parent_id' => 456 ], 456 ];
350  }
351 
356  public function testGetParentId( $rowArray, $expected ) {
357  $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
358  $this->assertSame( $expected, $rev->getParentId() );
359  }
360 
361  public function provideGetRevisionText() {
362  yield 'Generic test' => [
363  'This is a goat of revision text.',
364  (object)[
365  'old_flags' => '',
366  'old_text' => 'This is a goat of revision text.',
367  ],
368  ];
369  yield 'garbage in, garbage out' => [
370  false,
371  false,
372  ];
373  }
374 
379  public function testGetRevisionText( $expected, $rowData, $prefix = 'old_', $wiki = false ) {
380  $this->assertEquals(
381  $expected,
382  Revision::getRevisionText( $rowData, $prefix, $wiki ) );
383  }
384 
386  yield 'Generic gzip test' => [
387  'This is a small goat of revision text.',
388  (object)[
389  'old_flags' => 'gzip',
390  'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
391  ],
392  ];
393  }
394 
399  public function testGetRevisionWithZlibExtension( $expected, $rowData ) {
400  $this->checkPHPExtension( 'zlib' );
401  $this->testGetRevisionText( $expected, $rowData );
402  }
403 
405  yield 'Generic gzip test' => [
406  'This is a small goat of revision text.',
407  (object)[
408  'old_flags' => 'gzip',
409  'old_text' => 'DEAD BEEF',
410  ],
411  ];
412  }
413 
418  public function testGetRevisionWithZlibExtension_badData( $expected, $rowData ) {
419  $this->checkPHPExtension( 'zlib' );
420  Wikimedia\suppressWarnings();
421  $this->assertFalse(
423  (object)$rowData
424  )
425  );
426  Wikimedia\suppressWarnings( true );
427  }
428 
429  private function getWANObjectCache() {
430  return new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
431  }
432 
436  private function getBlobStore() {
438  $lb = $this->getMockBuilder( LoadBalancer::class )
439  ->disableOriginalConstructor()
440  ->getMock();
441 
442  $cache = $this->getWANObjectCache();
443 
444  $blobStore = new SqlBlobStore( $lb, $cache );
445  return $blobStore;
446  }
447 
448  private function mockBlobStoreFactory( $blobStore ) {
450  $factory = $this->getMockBuilder( BlobStoreFactory::class )
451  ->disableOriginalConstructor()
452  ->getMock();
453  $factory->expects( $this->any() )
454  ->method( 'newBlobStore' )
455  ->willReturn( $blobStore );
456  $factory->expects( $this->any() )
457  ->method( 'newSqlBlobStore' )
458  ->willReturn( $blobStore );
459  return $factory;
460  }
461 
465  private function getRevisionStore() {
467  $lb = $this->getMockBuilder( LoadBalancer::class )
468  ->disableOriginalConstructor()
469  ->getMock();
470 
471  $cache = $this->getWANObjectCache();
472 
473  $blobStore = new RevisionStore(
474  $lb,
475  $this->getBlobStore(),
476  $cache,
477  MediaWikiServices::getInstance()->getCommentStore(),
478  MediaWikiServices::getInstance()->getContentModelStore(),
479  MediaWikiServices::getInstance()->getSlotRoleStore(),
480  MediaWikiServices::getInstance()->getSlotRoleRegistry(),
482  MediaWikiServices::getInstance()->getActorMigration()
483  );
484  return $blobStore;
485  }
486 
488  yield 'Utf8Native' => [
489  "Wiki est l'\xc3\xa9cole superieur !",
490  'fr',
491  'iso-8859-1',
492  (object)[
493  'old_flags' => 'utf-8',
494  'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
495  ]
496  ];
497  yield 'Utf8Legacy' => [
498  "Wiki est l'\xc3\xa9cole superieur !",
499  'fr',
500  'iso-8859-1',
501  (object)[
502  'old_flags' => '',
503  'old_text' => "Wiki est l'\xe9cole superieur !",
504  ]
505  ];
506  }
507 
512  public function testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
513  $blobStore = $this->getBlobStore();
514  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
515  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
516 
517  $this->testGetRevisionText( $expected, $rowData );
518  }
519 
526  yield 'Utf8NativeGzip' => [
527  "Wiki est l'\xc3\xa9cole superieur !",
528  'fr',
529  'iso-8859-1',
530  (object)[
531  'old_flags' => 'gzip,utf-8',
532  'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
533  ]
534  ];
535  yield 'Utf8LegacyGzip' => [
536  "Wiki est l'\xc3\xa9cole superieur !",
537  'fr',
538  'iso-8859-1',
539  (object)[
540  'old_flags' => 'gzip',
541  'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
542  ]
543  ];
544  }
545 
550  public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
551  $this->checkPHPExtension( 'zlib' );
552 
553  $blobStore = $this->getBlobStore();
554  $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
555  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
556 
557  $this->testGetRevisionText( $expected, $rowData );
558  }
559 
563  public function testCompressRevisionTextUtf8() {
564  $row = new stdClass;
565  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
566  $row->old_flags = Revision::compressRevisionText( $row->old_text );
567  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
568  "Flags should contain 'utf-8'" );
569  $this->assertFalse( strpos( $row->old_flags, 'gzip' ) !== false,
570  "Flags should not contain 'gzip'" );
571  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
572  $row->old_text, "Direct check" );
573  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
574  Revision::getRevisionText( $row ), "getRevisionText" );
575  }
576 
581  $this->checkPHPExtension( 'zlib' );
582 
583  $blobStore = $this->getBlobStore();
584  $blobStore->setCompressBlobs( true );
585  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
586 
587  $row = new stdClass;
588  $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
589  $row->old_flags = Revision::compressRevisionText( $row->old_text );
590  $this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
591  "Flags should contain 'utf-8'" );
592  $this->assertTrue( strpos( $row->old_flags, 'gzip' ) !== false,
593  "Flags should contain 'gzip'" );
594  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
595  gzinflate( $row->old_text ), "Direct check" );
596  $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
597  Revision::getRevisionText( $row ), "getRevisionText" );
598  }
599 
603  public function testLoadFromTitle() {
604  $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_NEW );
605  $this->overrideMwServices();
606  $title = $this->getMockTitle();
607 
608  $conditions = [
609  'rev_id=page_latest',
610  'page_namespace' => $title->getNamespace(),
611  'page_title' => $title->getDBkey()
612  ];
613 
614  $row = (object)[
615  'rev_id' => '42',
616  'rev_page' => $title->getArticleID(),
617  'rev_timestamp' => '20171017114835',
618  'rev_user_text' => '127.0.0.1',
619  'rev_user' => '0',
620  'rev_minor_edit' => '0',
621  'rev_deleted' => '0',
622  'rev_len' => '46',
623  'rev_parent_id' => '1',
624  'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
625  'rev_comment_text' => 'Goat Comment!',
626  'rev_comment_data' => null,
627  'rev_comment_cid' => null,
628  'rev_content_format' => 'GOATFORMAT',
629  'rev_content_model' => 'GOATMODEL',
630  ];
631 
632  $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
633  $db = $this->getMock( IDatabase::class );
634  $db->expects( $this->any() )
635  ->method( 'getDomainId' )
636  ->will( $this->returnValue( $domain ) );
637  $db->expects( $this->once() )
638  ->method( 'selectRow' )
639  ->with(
640  $this->equalTo( [
641  'revision', 'page', 'user',
642  'temp_rev_comment' => 'revision_comment_temp', 'comment_rev_comment' => 'comment',
643  'temp_rev_user' => 'revision_actor_temp', 'actor_rev_user' => 'actor',
644  ] ),
645  // We don't really care about the fields are they come from the selectField methods
646  $this->isType( 'array' ),
647  $this->equalTo( $conditions ),
648  // Method name
649  $this->stringContains( 'fetchRevisionRowFromConds' ),
650  // We don't really care about the options here
651  $this->isType( 'array' ),
652  // We don't really care about the join conds are they come from the joinCond methods
653  $this->isType( 'array' )
654  )
655  ->willReturn( $row );
656 
657  $revision = Revision::loadFromTitle( $db, $title );
658 
659  $this->assertEquals( $title->getArticleID(), $revision->getTitle()->getArticleID() );
660  $this->assertEquals( $row->rev_id, $revision->getId() );
661  $this->assertEquals( $row->rev_len, $revision->getSize() );
662  $this->assertEquals( $row->rev_sha1, $revision->getSha1() );
663  $this->assertEquals( $row->rev_parent_id, $revision->getParentId() );
664  $this->assertEquals( $row->rev_timestamp, $revision->getTimestamp() );
665  $this->assertEquals( $row->rev_comment_text, $revision->getComment() );
666  $this->assertEquals( $row->rev_user_text, $revision->getUserText() );
667  }
668 
669  public function provideDecompressRevisionText() {
670  yield '(no legacy encoding), false in false out' => [ false, false, [], false ];
671  yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
672  yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
673  yield '(no legacy encoding), string in with gzip flag returns string' => [
674  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
675  false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
676  ];
677  yield '(no legacy encoding), string in with object flag returns false' => [
678  // gzip string below generated with serialize( 'JOJO' )
679  false, "s:4:\"JOJO\";", [ 'object' ], false,
680  ];
681  yield '(no legacy encoding), serialized object in with object flag returns string' => [
682  false,
683  // Using a TitleValue object as it has a getText method (which is needed)
684  serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
685  [ 'object' ],
686  'HHJJDDFF',
687  ];
688  yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
689  false,
690  // Using a TitleValue object as it has a getText method (which is needed)
691  gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
692  [ 'object', 'gzip' ],
693  '8219JJJ840',
694  ];
695  yield '(ISO-8859-1 encoding), string in string out' => [
696  'ISO-8859-1',
697  iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
698  [],
699  '1®Àþ1',
700  ];
701  yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
702  'ISO-8859-1',
703  gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
704  [ 'gzip' ],
705  '4®Àþ4',
706  ];
707  yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
708  'ISO-8859-1',
709  serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
710  [ 'object' ],
711  '3®Àþ3',
712  ];
713  yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
714  'ISO-8859-1',
715  gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
716  [ 'gzip', 'object' ],
717  '2®Àþ2',
718  ];
719  }
720 
730  public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
731  $blobStore = $this->getBlobStore();
732  if ( $legacyEncoding ) {
733  $blobStore->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
734  }
735 
736  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
737  $this->assertSame(
738  $expected,
739  Revision::decompressRevisionText( $text, $flags )
740  );
741  }
742 
744  yield 'Just text' => [
745  (object)[ 'old_text' => 'SomeText' ],
746  'old_',
747  'SomeText'
748  ];
749  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
750  yield 'gzip text' => [
751  (object)[
752  'old_text' => "sttttr\002\022\000",
753  'old_flags' => 'gzip'
754  ],
755  'old_',
756  'AAAABBAAA'
757  ];
758  yield 'gzip text and different prefix' => [
759  (object)[
760  'jojo_text' => "sttttr\002\022\000",
761  'jojo_flags' => 'gzip'
762  ],
763  'jojo_',
764  'AAAABBAAA'
765  ];
766  }
767 
773  $row,
774  $prefix,
775  $expected
776  ) {
777  $this->assertSame( $expected, Revision::getRevisionText( $row, $prefix ) );
778  }
779 
781  yield 'Just some text' => [ 'someNonUrlText' ];
782  yield 'No second URL part' => [ 'someProtocol://' ];
783  }
784 
790  $text
791  ) {
792  Wikimedia\suppressWarnings();
793  $this->assertFalse(
795  (object)[
796  'old_text' => $text,
797  'old_flags' => 'external',
798  ]
799  )
800  );
801  Wikimedia\suppressWarnings( true );
802  }
803 
808  $this->setService(
809  'ExternalStoreFactory',
810  new ExternalStoreFactory( [ 'ForTesting' ] )
811  );
812  $this->assertSame(
813  'AAAABBAAA',
815  (object)[
816  'old_text' => 'ForTesting://cluster1/12345',
817  'old_flags' => 'external,gzip',
818  ]
819  )
820  );
821  }
822 
827  $cache = $this->getWANObjectCache();
828  $this->setService( 'MainWANObjectCache', $cache );
829 
830  $this->setService(
831  'ExternalStoreFactory',
832  new ExternalStoreFactory( [ 'ForTesting' ] )
833  );
834 
835  $lb = $this->getMockBuilder( LoadBalancer::class )
836  ->disableOriginalConstructor()
837  ->getMock();
838 
839  $blobStore = new SqlBlobStore( $lb, $cache );
840  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
841 
842  $this->assertSame(
843  'AAAABBAAA',
845  (object)[
846  'old_text' => 'ForTesting://cluster1/12345',
847  'old_flags' => 'external,gzip',
848  'old_id' => '7777',
849  ]
850  )
851  );
852 
853  $cacheKey = $cache->makeGlobalKey(
854  'BlobStore',
855  'address',
856  $lb->getLocalDomainID(),
857  'tt:7777'
858  );
859  $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
860  }
861 
865  public function testGetSize() {
866  $title = $this->getMockTitle();
867 
868  $rec = new MutableRevisionRecord( $title );
869  $rev = new Revision( $rec, 0, $title );
870 
871  $this->assertSame( 0, $rev->getSize(), 'Size of no slots is 0' );
872 
873  $rec->setSize( 13 );
874  $this->assertSame( 13, $rev->getSize() );
875  }
876 
880  public function testGetSize_failure() {
881  $title = $this->getMockTitle();
882 
883  $rec = $this->getMockBuilder( RevisionRecord::class )
884  ->disableOriginalConstructor()
885  ->getMock();
886 
887  $rec->method( 'getSize' )
888  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
889 
890  $rev = new Revision( $rec, 0, $title );
891  $this->assertNull( $rev->getSize() );
892  }
893 
897  public function testGetSha1() {
898  $title = $this->getMockTitle();
899 
900  $rec = new MutableRevisionRecord( $title );
901  $rev = new Revision( $rec, 0, $title );
902 
903  $emptyHash = SlotRecord::base36Sha1( '' );
904  $this->assertSame( $emptyHash, $rev->getSha1(), 'Sha1 of no slots is hash of empty string' );
905 
906  $rec->setSha1( 'deadbeef' );
907  $this->assertSame( 'deadbeef', $rev->getSha1() );
908  }
909 
913  public function testGetSha1_failure() {
914  $title = $this->getMockTitle();
915 
916  $rec = $this->getMockBuilder( RevisionRecord::class )
917  ->disableOriginalConstructor()
918  ->getMock();
919 
920  $rec->method( 'getSha1' )
921  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
922 
923  $rev = new Revision( $rec, 0, $title );
924  $this->assertNull( $rev->getSha1() );
925  }
926 
930  public function testGetContent() {
931  $title = $this->getMockTitle();
932 
933  $rec = new MutableRevisionRecord( $title );
934  $rev = new Revision( $rec, 0, $title );
935 
936  $this->assertNull( $rev->getContent(), 'Content of no slots is null' );
937 
938  $content = new TextContent( 'Hello Kittens!' );
939  $rec->setContent( SlotRecord::MAIN, $content );
940  $this->assertSame( $content, $rev->getContent() );
941  }
942 
946  public function testGetContent_failure() {
947  $title = $this->getMockTitle();
948 
949  $rec = $this->getMockBuilder( RevisionRecord::class )
950  ->disableOriginalConstructor()
951  ->getMock();
952 
953  $rec->method( 'getContent' )
954  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
955 
956  $rev = new Revision( $rec, 0, $title );
957  $this->assertNull( $rev->getContent() );
958  }
959 
960 }
RevisionTest\testSetId
testSetId( $input, $expected)
provideSetId Revision::setId
Definition: RevisionTest.php:324
RevisionTest\testGetSha1
testGetSha1()
Revision::getSha1.
Definition: RevisionTest.php:897
RevisionTest\testConstructFromEmptyArray
testConstructFromEmptyArray()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Definition: RevisionTest.php:87
Revision\RevisionAccessException
Exception representing a failure to look up a revision.
Definition: RevisionAccessException.php:33
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:45
SCHEMA_COMPAT_READ_NEW
const SCHEMA_COMPAT_READ_NEW
Definition: Defines.php:287
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
RevisionTest\provideDecompressRevisionText
provideDecompressRevisionText()
Definition: RevisionTest.php:669
RevisionTest\testGetRevisionWithZlibExtension_badData
testGetRevisionWithZlibExtension_badData( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension_badData.
Definition: RevisionTest.php:418
HashBagOStuff
Simple store for keeping values in an associative array for the current process.
Definition: HashBagOStuff.php:31
MediaWikiTestCase\getTestUser
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
Definition: MediaWikiTestCase.php:180
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:33
RevisionTest\testConstructFromArray_userSetAsExpected
testConstructFromArray_userSetAsExpected(array $rowArray, $expectedUserId, $expectedUserName)
provideConstructFromArray_userSetAsExpected Revision::__construct \MediaWiki\Revision\RevisionStore::...
Definition: RevisionTest.php:140
Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:76
MediaWiki\Storage\SqlBlobStore
Service for storing and loading Content objects.
Definition: SqlBlobStore.php:49
RevisionTest\testGetRevisionText_external_oldId
testGetRevisionText_external_oldId()
Revision::getRevisionText.
Definition: RevisionTest.php:826
RevisionTest\testConstructFromArrayThrowsExceptions
testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException)
provideConstructFromArrayThrowsExceptions Revision::__construct \MediaWiki\Revision\RevisionStore::ne...
Definition: RevisionTest.php:189
RevisionTest\provideGetRevisionTextWithZlibExtension
provideGetRevisionTextWithZlibExtension()
Definition: RevisionTest.php:385
Revision\getRevisionText
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row.
Definition: Revision.php:1048
RevisionTest\testConstructFromRowWithBadPageId
testConstructFromRowWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Definition: RevisionTest.php:283
RevisionTest\testConstructFromRow
testConstructFromRow(array $arrayData, callable $assertions)
provideConstructFromRow Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFr...
Definition: RevisionTest.php:273
RevisionTest\testGetSize_failure
testGetSize_failure()
Revision::getSize.
Definition: RevisionTest.php:880
CONTENT_MODEL_WIKITEXT
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:235
serialize
serialize()
Definition: ApiMessageTrait.php:134
RevisionTest\testGetRevisionWithGzipAndLegacyEncoding
testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithGzipAndLegacyEncoding.
Definition: RevisionTest.php:550
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
RevisionTest\provideConstructFromArray
provideConstructFromArray()
Definition: RevisionTest.php:28
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
RevisionTest\provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts()
Definition: RevisionTest.php:780
MediaWikiTestCase\overrideMwServices
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
Definition: MediaWikiTestCase.php:937
RevisionTest\mockBlobStoreFactory
mockBlobStoreFactory( $blobStore)
Definition: RevisionTest.php:448
Revision
Definition: Revision.php:40
RevisionTest\testCompressRevisionTextUtf8Gzip
testCompressRevisionTextUtf8Gzip()
Revision::compressRevisionText.
Definition: RevisionTest.php:580
RevisionTest\getWANObjectCache
getWANObjectCache()
Definition: RevisionTest.php:429
RevisionTest\provideGetRevisionText
provideGetRevisionText()
Definition: RevisionTest.php:361
RevisionTest\provideGetParentId
provideGetParentId()
Definition: RevisionTest.php:346
MWException
MediaWiki exception.
Definition: MWException.php:26
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
RevisionTest\testSetUserIdAndName
testSetUserIdAndName( $inputId, $expectedId, $name)
provideSetUserIdAndName Revision::setUserIdAndName
Definition: RevisionTest.php:339
RevisionTest\testGetRevisionWithLegacyEncoding
testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithLegacyEncoding.
Definition: RevisionTest.php:512
$input
if(is_array( $mode)) switch( $mode) $input
Definition: postprocess-phan.php:141
MediaWikiTestCase\setMwGlobals
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown.
Definition: MediaWikiTestCase.php:709
MediaWikiTestCase
Definition: MediaWikiTestCase.php:17
Revision\compressRevisionText
static compressRevisionText(&$text)
If $wgCompressRevisions is enabled, we will compress data.
Definition: Revision.php:1124
RevisionTest\provideGetRevisionTextWithGzipAndLegacyEncoding
provideGetRevisionTextWithGzipAndLegacyEncoding()
Definition: RevisionTest.php:520
RevisionTest\provideConstructFromArrayThrowsExceptions
provideConstructFromArrayThrowsExceptions()
Definition: RevisionTest.php:159
RevisionTest\setUp
setUp()
Definition: RevisionTest.php:20
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
MediaWiki\Storage\BlobStoreFactory
Service for instantiating BlobStores.
Definition: BlobStoreFactory.php:35
MediaWikiTestCase\getDefaultWikitextNS
getDefaultWikitextNS()
Returns the ID of a namespace that defaults to Wikitext.
Definition: MediaWikiTestCase.php:2211
RevisionTest\testGetContent
testGetContent()
Revision::getContent.
Definition: RevisionTest.php:930
WikitextContent
Content object for wiki text pages.
Definition: WikitextContent.php:36
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
RevisionTest
Test cases in RevisionTest should not interact with the Database.
Definition: RevisionTest.php:18
JavaScriptContent
Content for JavaScript pages.
Definition: JavaScriptContent.php:33
RevisionTest\provideGetRevisionTextWithLegacyEncoding
provideGetRevisionTextWithLegacyEncoding()
Definition: RevisionTest.php:487
MIGRATION_OLD
const MIGRATION_OLD
Definition: Defines.php:315
Wikimedia\Rdbms\LoadBalancer
Database connection, tracking, load balancing, and transaction manager for a cluster.
Definition: LoadBalancer.php:41
null
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
RevisionTest\testGetSize
testGetSize()
Revision::getSize.
Definition: RevisionTest.php:865
RevisionTest\provideGetRevisionTextWithZlibExtension_badData
provideGetRevisionTextWithZlibExtension_badData()
Definition: RevisionTest.php:404
ExternalStoreFactory
Definition: ExternalStoreFactory.php:9
any
they could even be mouse clicks or menu items whatever suits your program You should also get your if any
Definition: COPYING.txt:326
RevisionTest\provideSetUserIdAndName
provideSetUserIdAndName()
Definition: RevisionTest.php:330
RevisionTest\provideConstructFromArray_userSetAsExpected
provideConstructFromArray_userSetAsExpected()
Definition: RevisionTest.php:103
Revision\MutableRevisionRecord
Mutable RevisionRecord implementation, for building new revision entries programmatically.
Definition: MutableRevisionRecord.php:41
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:116
RevisionTest\testDecompressRevisionText
testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected)
provideDecompressRevisionText Revision::decompressRevisionText
Definition: RevisionTest.php:730
RevisionTest\testConstructFromArray
testConstructFromArray( $rowArray)
provideConstructFromArray Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevision...
Definition: RevisionTest.php:76
Revision\RAW
const RAW
Definition: Revision.php:56
RevisionTest\testGetRevisionText_external_noOldId
testGetRevisionText_external_noOldId()
Revision::getRevisionText.
Definition: RevisionTest.php:807
RevisionTest\testGetContent_failure
testGetContent_failure()
Revision::getContent.
Definition: RevisionTest.php:946
RevisionTest\testGetRevisionText_returnsDecompressedTextFieldWhenNotExternal
testGetRevisionText_returnsDecompressedTextFieldWhenNotExternal( $row, $prefix, $expected)
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal Revision::getRevisionText
Definition: RevisionTest.php:772
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:37
RevisionTest\testGetRevisionText
testGetRevisionText( $expected, $rowData, $prefix='old_', $wiki=false)
Revision::getRevisionText provideGetRevisionText.
Definition: RevisionTest.php:379
RevisionTest\provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal()
Definition: RevisionTest.php:743
RevisionTest\testConstructFromArrayWithBadPageId
testConstructFromArrayWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Definition: RevisionTest.php:96
RevisionTest\testGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts
testGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts( $text)
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts Revision::getRevisionText
Definition: RevisionTest.php:789
$cache
$cache
Definition: mcc.php:33
RevisionTest\testConstructFromNothing
testConstructFromNothing()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Definition: RevisionTest.php:202
RevisionTest\testGetId
testGetId( $rowArray, $expectedId)
provideGetId Revision::getId
Definition: RevisionTest.php:310
SCHEMA_COMPAT_NEW
const SCHEMA_COMPAT_NEW
Definition: Defines.php:291
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1769
RevisionTest\testLoadFromTitle
testLoadFromTitle()
Revision::loadFromTitle.
Definition: RevisionTest.php:603
RevisionTest\provideSetId
provideSetId()
Definition: RevisionTest.php:315
SCHEMA_COMPAT_WRITE_BOTH
const SCHEMA_COMPAT_WRITE_BOTH
Definition: Defines.php:288
RevisionTest\testGetSha1_failure
testGetSha1_failure()
Revision::getSha1.
Definition: RevisionTest.php:913
MediaWikiTestCase\checkPHPExtension
checkPHPExtension( $extName)
Check if $extName is a loaded PHP extension, will skip the test whenever it is not loaded.
Definition: MediaWikiTestCase.php:2288
$content
$content
Definition: pageupdater.txt:72
Language\factory
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:215
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
CONTENT_MODEL_JAVASCRIPT
const CONTENT_MODEL_JAVASCRIPT
Definition: Defines.php:236
RevisionTest\provideGetId
provideGetId()
Definition: RevisionTest.php:295
object
globals will be eliminated from MediaWiki replaced by an application object which would be passed to constructors Whether that would be an convenient solution remains to be but certainly PHP makes such object oriented programming models easier than they were in previous versions For the time being MediaWiki programmers will have to work in an environment with some global context At the time of globals were initialised on startup by MediaWiki of these were configuration which are documented in DefaultSettings php There is no comprehensive documentation for the remaining however some of the most important ones are listed below They are typically initialised either in index php or in Setup php $wgTitle Title object created from the request URL $wgOut OutputPage object for HTTP response $wgUser User object for the user associated with the current request $wgLang Language object selected by user preferences $wgContLang Language object associated with the wiki being viewed $wgParser Parser object Parser extensions register their hooks here $wgRequest WebRequest object
Definition: globals.txt:25
RevisionTest\getRevisionStore
getRevisionStore()
Definition: RevisionTest.php:465
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
Revision\decompressRevisionText
static decompressRevisionText( $text, $flags)
Re-converts revision text according to it's flags.
Definition: Revision.php:1135
Revision\loadFromTitle
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that's attached to a given page.
Definition: Revision.php:277
RevisionTest\getBlobStore
getBlobStore()
Definition: RevisionTest.php:436
MediaWikiTestCase\setService
setService( $name, $object)
Sets a service, maintaining a stashed version of the previous service to be restored in tearDown.
Definition: MediaWikiTestCase.php:649
RevisionTest\provideConstructFromRow
provideConstructFromRow()
Definition: RevisionTest.php:209
Revision\DELETED_TEXT
const DELETED_TEXT
Definition: Revision.php:46
RevisionTest\getMockTitle
getMockTitle( $model=CONTENT_MODEL_WIKITEXT)
Definition: RevisionTest.php:48
MediaWikiTestCase\$db
Database $db
Primary database.
Definition: MediaWikiTestCase.php:61
RevisionTest\testCompressRevisionTextUtf8
testCompressRevisionTextUtf8()
Revision::compressRevisionText.
Definition: RevisionTest.php:563
RevisionTest\testGetRevisionWithZlibExtension
testGetRevisionWithZlibExtension( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension.
Definition: RevisionTest.php:399
Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:39
RevisionTest\testGetParentId
testGetParentId( $rowArray, $expected)
provideGetParentId Revision::getParentId()
Definition: RevisionTest.php:356
TitleValue
Represents a page (or page fragment) title within MediaWiki.
Definition: TitleValue.php:36