backup_LogTest.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. namespace MediaWiki\Tests\Maintenance;
  3. use MediaWiki\MediaWikiServices;
  4. use DumpBackup;
  5. use ManualLogEntry;
  6. use Title;
  7. use User;
  8. use WikiExporter;
  9. /**
  10. * Tests for log dumps of BackupDumper
  11. *
  12. * Some of these tests use the old constuctor for TextPassDumper
  13. * and the dump() function, while others use the new loadWithArgv( $args )
  14. * function and execute(). This is to ensure both the old and new methods
  15. * work properly.
  16. *
  17. * @group Database
  18. * @group Dump
  19. * @covers BackupDumper
  20. */
  21. class BackupDumperLoggerTest extends DumpTestCase {
  22. // We'll add several log entries and users for this test. The following
  23. // variables hold the corresponding ids.
  24. private $userId1, $userId2;
  25. private $logId1, $logId2, $logId3;
  26. /**
  27. * adds a log entry to the database.
  28. *
  29. * @param string $type Type of the log entry
  30. * @param string $subtype Subtype of the log entry
  31. * @param User $user User that performs the logged operation
  32. * @param int $ns Number of the namespace for the entry's target's title
  33. * @param string $title Title of the entry's target
  34. * @param string $comment Comment of the log entry
  35. * @param array $parameters (optional) accompanying data that is attached to the entry
  36. *
  37. * @return int Id of the added log entry
  38. */
  39. private function addLogEntry( $type, $subtype, User $user, $ns, $title,
  40. $comment = null, $parameters = null
  41. ) {
  42. $logEntry = new ManualLogEntry( $type, $subtype );
  43. $logEntry->setPerformer( $user );
  44. $logEntry->setTarget( Title::newFromText( $title, $ns ) );
  45. if ( $comment !== null ) {
  46. $logEntry->setComment( $comment );
  47. }
  48. if ( $parameters !== null ) {
  49. $logEntry->setParameters( $parameters );
  50. }
  51. return $logEntry->insert();
  52. }
  53. function addDBData() {
  54. $this->tablesUsed[] = 'logging';
  55. $this->tablesUsed[] = 'user';
  56. try {
  57. $user1 = User::newFromName( 'BackupDumperLogUserA' );
  58. $this->userId1 = $user1->getId();
  59. if ( $this->userId1 === 0 ) {
  60. $user1->addToDatabase();
  61. $this->userId1 = $user1->getId();
  62. }
  63. $this->assertGreaterThan( 0, $this->userId1 );
  64. $user2 = User::newFromName( 'BackupDumperLogUserB' );
  65. $this->userId2 = $user2->getId();
  66. if ( $this->userId2 === 0 ) {
  67. $user2->addToDatabase();
  68. $this->userId2 = $user2->getId();
  69. }
  70. $this->assertGreaterThan( 0, $this->userId2 );
  71. $this->logId1 = $this->addLogEntry( 'type', 'subtype',
  72. $user1, NS_MAIN, "PageA" );
  73. $this->assertGreaterThan( 0, $this->logId1 );
  74. $this->logId2 = $this->addLogEntry( 'supress', 'delete',
  75. $user2, NS_TALK, "PageB", "SomeComment" );
  76. $this->assertGreaterThan( 0, $this->logId2 );
  77. $this->logId3 = $this->addLogEntry( 'move', 'delete',
  78. $user2, NS_MAIN, "PageA", "SomeOtherComment",
  79. [ 'key1' => 1, 3 => 'value3' ] );
  80. $this->assertGreaterThan( 0, $this->logId3 );
  81. } catch ( Exception $e ) {
  82. // We'd love to pass $e directly. However, ... see
  83. // documentation of exceptionFromAddDBData in
  84. // DumpTestCase
  85. $this->exceptionFromAddDBData = $e;
  86. }
  87. }
  88. /**
  89. * asserts that the xml reader is at the beginning of a log entry and skips over
  90. * it while analyzing it.
  91. *
  92. * @param int $id Id of the log entry
  93. * @param string $user_name User name of the log entry's performer
  94. * @param int $user_id User id of the log entry 's performer
  95. * @param string|null $comment Comment of the log entry. If null, the comment text is ignored.
  96. * @param string $type Type of the log entry
  97. * @param string $subtype Subtype of the log entry
  98. * @param string $title Title of the log entry's target
  99. * @param array $parameters (optional) unserialized data accompanying the log entry
  100. */
  101. private function assertLogItem( $id, $user_name, $user_id, $comment, $type,
  102. $subtype, $title, $parameters = []
  103. ) {
  104. $this->assertNodeStart( "logitem" );
  105. $this->skipWhitespace();
  106. $this->assertTextNode( "id", $id );
  107. $this->assertTextNode( "timestamp", false );
  108. $this->assertNodeStart( "contributor" );
  109. $this->skipWhitespace();
  110. $this->assertTextNode( "username", $user_name );
  111. $this->assertTextNode( "id", $user_id );
  112. $this->assertNodeEnd( "contributor" );
  113. $this->skipWhitespace();
  114. if ( $comment !== null ) {
  115. $this->assertTextNode( "comment", $comment );
  116. }
  117. $this->assertTextNode( "type", $type );
  118. $this->assertTextNode( "action", $subtype );
  119. $this->assertTextNode( "logtitle", $title );
  120. $this->assertNodeStart( "params" );
  121. $parameters_xml = unserialize( $this->xml->value );
  122. $this->assertEquals( $parameters, $parameters_xml );
  123. $this->assertTrue( $this->xml->read(), "Skipping past processed text of params" );
  124. $this->assertNodeEnd( "params" );
  125. $this->skipWhitespace();
  126. $this->assertNodeEnd( "logitem" );
  127. $this->skipWhitespace();
  128. }
  129. function testPlain() {
  130. // Preparing the dump
  131. $fname = $this->getNewTempFile();
  132. $dumper = new DumpBackup( [ '--output=file:' . $fname ] );
  133. $dumper->startId = $this->logId1;
  134. $dumper->endId = $this->logId3 + 1;
  135. $dumper->reporting = false;
  136. $dumper->setDB( $this->db );
  137. // Performing the dump
  138. $dumper->dump( WikiExporter::LOGS, WikiExporter::TEXT );
  139. // Analyzing the dumped data
  140. $this->assertDumpStart( $fname );
  141. $this->assertLogItem( $this->logId1, "BackupDumperLogUserA",
  142. $this->userId1, null, "type", "subtype", "PageA" );
  143. $contLang = MediaWikiServices::getInstance()->getContentLanguage();
  144. $this->assertNotNull( $contLang, "Content language object validation" );
  145. $namespace = $contLang->getNsText( NS_TALK );
  146. $this->assertInternalType( 'string', $namespace );
  147. $this->assertGreaterThan( 0, strlen( $namespace ) );
  148. $this->assertLogItem( $this->logId2, "BackupDumperLogUserB",
  149. $this->userId2, "SomeComment", "supress", "delete",
  150. $namespace . ":PageB" );
  151. $this->assertLogItem( $this->logId3, "BackupDumperLogUserB",
  152. $this->userId2, "SomeOtherComment", "move", "delete",
  153. "PageA", [ 'key1' => 1, 3 => 'value3' ] );
  154. $this->assertDumpEnd();
  155. }
  156. function testXmlDumpsBackupUseCaseLogging() {
  157. $this->checkHasGzip();
  158. // Preparing the dump
  159. $fname = $this->getNewTempFile();
  160. $dumper = new DumpBackup();
  161. $dumper->loadWithArgv( [ '--logs', '--output=gzip:' . $fname,
  162. '--reporting=2' ] );
  163. $dumper->startId = $this->logId1;
  164. $dumper->endId = $this->logId3 + 1;
  165. $dumper->setDB( $this->db );
  166. // xmldumps-backup demands reporting, although this is currently not
  167. // implemented in BackupDumper, when dumping logging data. We
  168. // nevertheless capture the output of the dump process already now,
  169. // to be able to alert (once dumping produces reports) that this test
  170. // needs updates.
  171. $dumper->stderr = fopen( 'php://output', 'a' );
  172. if ( $dumper->stderr === false ) {
  173. $this->fail( "Could not open stream for stderr" );
  174. }
  175. // Performing the dump
  176. $dumper->execute();
  177. $this->assertTrue( fclose( $dumper->stderr ), "Closing stderr handle" );
  178. // Analyzing the dumped data
  179. $this->gunzip( $fname );
  180. $this->assertDumpStart( $fname );
  181. $this->assertLogItem( $this->logId1, "BackupDumperLogUserA",
  182. $this->userId1, null, "type", "subtype", "PageA" );
  183. $contLang = MediaWikiServices::getInstance()->getContentLanguage();
  184. $this->assertNotNull( $contLang, "Content language object validation" );
  185. $namespace = $contLang->getNsText( NS_TALK );
  186. $this->assertInternalType( 'string', $namespace );
  187. $this->assertGreaterThan( 0, strlen( $namespace ) );
  188. $this->assertLogItem( $this->logId2, "BackupDumperLogUserB",
  189. $this->userId2, "SomeComment", "supress", "delete",
  190. $namespace . ":PageB" );
  191. $this->assertLogItem( $this->logId3, "BackupDumperLogUserB",
  192. $this->userId2, "SomeOtherComment", "move", "delete",
  193. "PageA", [ 'key1' => 1, 3 => 'value3' ] );
  194. $this->assertDumpEnd();
  195. // Currently, no reporting is implemented. Alert via failure, once
  196. // this changes.
  197. // If reporting for log dumps has been implemented, please update
  198. // the following statement to catch good output
  199. $this->expectOutputString( '' );
  200. }
  201. }