MediaWiki  master
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',
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_OLD );
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  ] ),
644  // We don't really care about the fields are they come from the selectField methods
645  $this->isType( 'array' ),
646  $this->equalTo( $conditions ),
647  // Method name
648  $this->stringContains( 'fetchRevisionRowFromConds' ),
649  // We don't really care about the options here
650  $this->isType( 'array' ),
651  // We don't really care about the join conds are they come from the joinCond methods
652  $this->isType( 'array' )
653  )
654  ->willReturn( $row );
655 
656  $revision = Revision::loadFromTitle( $db, $title );
657 
658  $this->assertEquals( $title->getArticleID(), $revision->getTitle()->getArticleID() );
659  $this->assertEquals( $row->rev_id, $revision->getId() );
660  $this->assertEquals( $row->rev_len, $revision->getSize() );
661  $this->assertEquals( $row->rev_sha1, $revision->getSha1() );
662  $this->assertEquals( $row->rev_parent_id, $revision->getParentId() );
663  $this->assertEquals( $row->rev_timestamp, $revision->getTimestamp() );
664  $this->assertEquals( $row->rev_comment_text, $revision->getComment() );
665  $this->assertEquals( $row->rev_user_text, $revision->getUserText() );
666  }
667 
668  public function provideDecompressRevisionText() {
669  yield '(no legacy encoding), false in false out' => [ false, false, [], false ];
670  yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
671  yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
672  yield '(no legacy encoding), string in with gzip flag returns string' => [
673  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
674  false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
675  ];
676  yield '(no legacy encoding), string in with object flag returns false' => [
677  // gzip string below generated with serialize( 'JOJO' )
678  false, "s:4:\"JOJO\";", [ 'object' ], false,
679  ];
680  yield '(no legacy encoding), serialized object in with object flag returns string' => [
681  false,
682  // Using a TitleValue object as it has a getText method (which is needed)
683  serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
684  [ 'object' ],
685  'HHJJDDFF',
686  ];
687  yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
688  false,
689  // Using a TitleValue object as it has a getText method (which is needed)
690  gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
691  [ 'object', 'gzip' ],
692  '8219JJJ840',
693  ];
694  yield '(ISO-8859-1 encoding), string in string out' => [
695  'ISO-8859-1',
696  iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
697  [],
698  '1®Àþ1',
699  ];
700  yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
701  'ISO-8859-1',
702  gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
703  [ 'gzip' ],
704  '4®Àþ4',
705  ];
706  yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
707  'ISO-8859-1',
708  serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
709  [ 'object' ],
710  '3®Àþ3',
711  ];
712  yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
713  'ISO-8859-1',
714  gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
715  [ 'gzip', 'object' ],
716  '2®Àþ2',
717  ];
718  }
719 
729  public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
730  $blobStore = $this->getBlobStore();
731  if ( $legacyEncoding ) {
732  $blobStore->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
733  }
734 
735  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
736  $this->assertSame(
737  $expected,
738  Revision::decompressRevisionText( $text, $flags )
739  );
740  }
741 
743  yield 'Just text' => [
744  (object)[ 'old_text' => 'SomeText' ],
745  'old_',
746  'SomeText'
747  ];
748  // gzip string below generated with gzdeflate( 'AAAABBAAA' )
749  yield 'gzip text' => [
750  (object)[
751  'old_text' => "sttttr\002\022\000",
752  'old_flags' => 'gzip'
753  ],
754  'old_',
755  'AAAABBAAA'
756  ];
757  yield 'gzip text and different prefix' => [
758  (object)[
759  'jojo_text' => "sttttr\002\022\000",
760  'jojo_flags' => 'gzip'
761  ],
762  'jojo_',
763  'AAAABBAAA'
764  ];
765  }
766 
772  $row,
773  $prefix,
774  $expected
775  ) {
776  $this->assertSame( $expected, Revision::getRevisionText( $row, $prefix ) );
777  }
778 
780  yield 'Just some text' => [ 'someNonUrlText' ];
781  yield 'No second URL part' => [ 'someProtocol://' ];
782  }
783 
789  $text
790  ) {
791  Wikimedia\suppressWarnings();
792  $this->assertFalse(
794  (object)[
795  'old_text' => $text,
796  'old_flags' => 'external',
797  ]
798  )
799  );
800  Wikimedia\suppressWarnings( true );
801  }
802 
807  $this->setService(
808  'ExternalStoreFactory',
809  new ExternalStoreFactory( [ 'ForTesting' ] )
810  );
811  $this->assertSame(
812  'AAAABBAAA',
814  (object)[
815  'old_text' => 'ForTesting://cluster1/12345',
816  'old_flags' => 'external,gzip',
817  ]
818  )
819  );
820  }
821 
826  $cache = $this->getWANObjectCache();
827  $this->setService( 'MainWANObjectCache', $cache );
828 
829  $this->setService(
830  'ExternalStoreFactory',
831  new ExternalStoreFactory( [ 'ForTesting' ] )
832  );
833 
834  $lb = $this->getMockBuilder( LoadBalancer::class )
835  ->disableOriginalConstructor()
836  ->getMock();
837 
838  $blobStore = new SqlBlobStore( $lb, $cache );
839  $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
840 
841  $this->assertSame(
842  'AAAABBAAA',
844  (object)[
845  'old_text' => 'ForTesting://cluster1/12345',
846  'old_flags' => 'external,gzip',
847  'old_id' => '7777',
848  ]
849  )
850  );
851 
852  $cacheKey = $cache->makeGlobalKey(
853  'BlobStore',
854  'address',
855  $lb->getLocalDomainID(),
856  'tt:7777'
857  );
858  $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
859  }
860 
864  public function testGetSize() {
865  $title = $this->getMockTitle();
866 
867  $rec = new MutableRevisionRecord( $title );
868  $rev = new Revision( $rec, 0, $title );
869 
870  $this->assertSame( 0, $rev->getSize(), 'Size of no slots is 0' );
871 
872  $rec->setSize( 13 );
873  $this->assertSame( 13, $rev->getSize() );
874  }
875 
879  public function testGetSize_failure() {
880  $title = $this->getMockTitle();
881 
882  $rec = $this->getMockBuilder( RevisionRecord::class )
883  ->disableOriginalConstructor()
884  ->getMock();
885 
886  $rec->method( 'getSize' )
887  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
888 
889  $rev = new Revision( $rec, 0, $title );
890  $this->assertNull( $rev->getSize() );
891  }
892 
896  public function testGetSha1() {
897  $title = $this->getMockTitle();
898 
899  $rec = new MutableRevisionRecord( $title );
900  $rev = new Revision( $rec, 0, $title );
901 
902  $emptyHash = SlotRecord::base36Sha1( '' );
903  $this->assertSame( $emptyHash, $rev->getSha1(), 'Sha1 of no slots is hash of empty string' );
904 
905  $rec->setSha1( 'deadbeef' );
906  $this->assertSame( 'deadbeef', $rev->getSha1() );
907  }
908 
912  public function testGetSha1_failure() {
913  $title = $this->getMockTitle();
914 
915  $rec = $this->getMockBuilder( RevisionRecord::class )
916  ->disableOriginalConstructor()
917  ->getMock();
918 
919  $rec->method( 'getSha1' )
920  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
921 
922  $rev = new Revision( $rec, 0, $title );
923  $this->assertNull( $rev->getSha1() );
924  }
925 
929  public function testGetContent() {
930  $title = $this->getMockTitle();
931 
932  $rec = new MutableRevisionRecord( $title );
933  $rev = new Revision( $rec, 0, $title );
934 
935  $this->assertNull( $rev->getContent(), 'Content of no slots is null' );
936 
937  $content = new TextContent( 'Hello Kittens!' );
938  $rec->setContent( SlotRecord::MAIN, $content );
939  $this->assertSame( $content, $rev->getContent() );
940  }
941 
945  public function testGetContent_failure() {
946  $title = $this->getMockTitle();
947 
948  $rec = $this->getMockBuilder( RevisionRecord::class )
949  ->disableOriginalConstructor()
950  ->getMock();
951 
952  $rec->method( 'getContent' )
953  ->willThrowException( new RevisionAccessException( 'Oops!' ) );
954 
955  $rev = new Revision( $rec, 0, $title );
956  $this->assertNull( $rev->getContent() );
957  }
958 
959 }
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))
Service for storing and loading Content objects.
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal()
testGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts( $text)
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts Revision::getRevisionText ...
testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithLegacyEncoding.
provideGetRevisionTextWithGzipAndLegacyEncoding()
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:235
testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected)
provideDecompressRevisionText Revision::decompressRevisionText
if(is_array( $mode)) switch( $mode) $input
testGetRevisionText_external_oldId()
Revision::getRevisionText.
testGetContent()
Revision::getContent.
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
serialize()
testConstructFromEmptyArray()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
testCompressRevisionTextUtf8Gzip()
Revision::compressRevisionText.
if(!isset( $args[0])) $lang
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
testConstructFromArrayWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
testGetContent_failure()
Revision::getContent.
testSetId( $input, $expected)
provideSetId Revision::setId
const SCHEMA_COMPAT_READ_NEW
Definition: Defines.php:287
mockBlobStoreFactory( $blobStore)
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
provideConstructFromArray()
testGetSha1_failure()
Revision::getSha1.
Content for JavaScript pages.
provideGetRevisionTextWithLegacyEncoding()
static decompressRevisionText( $text, $flags)
Re-converts revision text according to it&#39;s flags.
Definition: Revision.php:1135
provideConstructFromArrayThrowsExceptions()
testConstructFromArray( $rowArray)
provideConstructFromArray Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevision...
testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException)
provideConstructFromArrayThrowsExceptions Revision::__construct \MediaWiki\Revision\RevisionStore::ne...
testGetParentId( $rowArray, $expected)
provideGetParentId Revision::getParentId()
static getRevisionText( $row, $prefix='old_', $wiki=false)
Get revision text associated with an old or archive row.
Definition: Revision.php:1048
Mutable RevisionRecord implementation, for building new revision entries programmatically.
provideDecompressRevisionText()
getDefaultWikitextNS()
Returns the ID of a namespace that defaults to Wikitext.
provideGetRevisionTextWithZlibExtension()
testGetRevisionWithZlibExtension_badData( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension_badData.
testGetRevisionText_external_noOldId()
Revision::getRevisionText.
testSetUserIdAndName( $inputId, $expectedId, $name)
provideSetUserIdAndName Revision::setUserIdAndName
const MIGRATION_OLD
Definition: Defines.php:315
Service for looking up page revisions.
testCompressRevisionTextUtf8()
Revision::compressRevisionText.
static compressRevisionText(&$text)
If $wgCompressRevisions is enabled, we will compress data.
Definition: Revision.php:1124
$cache
Definition: mcc.php:33
provideConstructFromArray_userSetAsExpected()
static loadFromTitle( $db, $title, $id=0)
Load either the current, or a specified, revision that&#39;s attached to a given page.
Definition: Revision.php:277
testLoadFromTitle()
Revision::loadFromTitle.
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
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:925
testGetSize_failure()
Revision::getSize.
provideGetRevisionTextWithZlibExtension_badData()
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:215
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:1766
overrideMwServices(Config $configOverrides=null, array $services=[])
Stashes the global instance of MediaWikiServices, and installs a new one, allowing test cases to over...
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown...
const RAW
Definition: Revision.php:56
testGetRevisionText( $expected, $rowData, $prefix='old_', $wiki=false)
Revision::getRevisionText provideGetRevisionText.
const SCHEMA_COMPAT_WRITE_BOTH
Definition: Defines.php:288
testConstructFromNothing()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
CONTENT_MODEL_JAVASCRIPT
Allow users to upload files.
const DELETED_TEXT
Definition: Revision.php:46
setService( $name, $object)
Sets a service, maintaining a stashed version of the previous service to be restored in tearDown...
testGetSha1()
Revision::getSha1.
checkPHPExtension( $extName)
Check if $extName is a loaded PHP extension, will skip the test whenever it is not loaded...
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
testGetSize()
Revision::getSize.
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
testConstructFromArray_userSetAsExpected(array $rowArray, $expectedUserId, $expectedUserName)
provideConstructFromArray_userSetAsExpected Revision::__construct \MediaWiki\Revision\RevisionStore::...
testGetRevisionText_returnsDecompressedTextFieldWhenNotExternal( $row, $prefix, $expected)
provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal Revision::getRevisionText ...
Exception representing a failure to look up a revision.
testGetId( $rowArray, $expectedId)
provideGetId Revision::getId
Database $db
Primary database.
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts()
getMockTitle( $model=CONTENT_MODEL_WIKITEXT)
testConstructFromRowWithBadPageId()
Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFromArray.
const SCHEMA_COMPAT_OLD
Definition: Defines.php:290
$content
Definition: pageupdater.txt:72
testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData)
Revision::getRevisionText provideGetRevisionTextWithGzipAndLegacyEncoding.
testConstructFromRow(array $arrayData, callable $assertions)
provideConstructFromRow Revision::__construct \MediaWiki\Revision\RevisionStore::newMutableRevisionFr...
static getTestUser( $groups=[])
Convenience method for getting an immutable test user.
testGetRevisionWithZlibExtension( $expected, $rowData)
Revision::getRevisionText provideGetRevisionTextWithZlibExtension.
Test cases in RevisionTest should not interact with the Database.