MaintenanceTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. <?php
  2. namespace MediaWiki\Tests\Maintenance;
  3. use Maintenance;
  4. use MediaWiki\MediaWikiServices;
  5. use Wikimedia\TestingAccessWrapper;
  6. /**
  7. * @covers Maintenance
  8. */
  9. class MaintenanceTest extends MaintenanceBaseTestCase {
  10. /**
  11. * @see MaintenanceBaseTestCase::getMaintenanceClass
  12. */
  13. protected function getMaintenanceClass() {
  14. return Maintenance::class;
  15. }
  16. /**
  17. * @see MaintenanceBaseTestCase::createMaintenance
  18. *
  19. * Note to extension authors looking for a model to follow: This function
  20. * is normally not needed in a maintenance test, it's only overridden here
  21. * because Maintenance is abstract.
  22. */
  23. protected function createMaintenance() {
  24. $className = $this->getMaintenanceClass();
  25. $obj = $this->getMockForAbstractClass( $className );
  26. return TestingAccessWrapper::newFromObject( $obj );
  27. }
  28. // Although the following tests do not seem to be too consistent (compare for
  29. // example the newlines within the test.*StringString tests, or the
  30. // test.*Intermittent.* tests), the objective of these tests is not to describe
  31. // consistent behavior, but rather currently existing behavior.
  32. /**
  33. * @dataProvider provideOutputData
  34. */
  35. function testOutput( $outputs, $expected, $extraNL ) {
  36. foreach ( $outputs as $data ) {
  37. if ( is_array( $data ) ) {
  38. list( $msg, $channel ) = $data;
  39. } else {
  40. $msg = $data;
  41. $channel = null;
  42. }
  43. $this->maintenance->output( $msg, $channel );
  44. }
  45. $this->assertOutputPrePostShutdown( $expected, $extraNL );
  46. }
  47. public function provideOutputData() {
  48. return [
  49. [ [ "" ], "", false ],
  50. [ [ "foo" ], "foo", false ],
  51. [ [ "foo", "bar" ], "foobar", false ],
  52. [ [ "foo\n" ], "foo\n", false ],
  53. [ [ "foo\n\n" ], "foo\n\n", false ],
  54. [ [ "foo\nbar" ], "foo\nbar", false ],
  55. [ [ "foo\nbar\n" ], "foo\nbar\n", false ],
  56. [ [ "foo\n", "bar\n" ], "foo\nbar\n", false ],
  57. [ [ "", "foo", "", "\n", "ba", "", "r\n" ], "foo\nbar\n", false ],
  58. [ [ "", "foo", "", "\nb", "a", "", "r\n" ], "foo\nbar\n", false ],
  59. [ [ [ "foo", "bazChannel" ] ], "foo", true ],
  60. [ [ [ "foo\n", "bazChannel" ] ], "foo", true ],
  61. // If this test fails, note that output takes strings with double line
  62. // endings (although output's implementation in this situation calls
  63. // outputChanneled with a string ending in a nl ... which is not allowed
  64. // according to the documentation of outputChanneled)
  65. [ [ [ "foo\n\n", "bazChannel" ] ], "foo\n", true ],
  66. [ [ [ "foo\nbar", "bazChannel" ] ], "foo\nbar", true ],
  67. [ [ [ "foo\nbar\n", "bazChannel" ] ], "foo\nbar", true ],
  68. [
  69. [
  70. [ "foo\n", "bazChannel" ],
  71. [ "bar\n", "bazChannel" ],
  72. ],
  73. "foobar",
  74. true
  75. ],
  76. [
  77. [
  78. [ "", "bazChannel" ],
  79. [ "foo", "bazChannel" ],
  80. [ "", "bazChannel" ],
  81. [ "\n", "bazChannel" ],
  82. [ "ba", "bazChannel" ],
  83. [ "", "bazChannel" ],
  84. [ "r\n", "bazChannel" ],
  85. ],
  86. "foobar",
  87. true
  88. ],
  89. [
  90. [
  91. [ "", "bazChannel" ],
  92. [ "foo", "bazChannel" ],
  93. [ "", "bazChannel" ],
  94. [ "\nb", "bazChannel" ],
  95. [ "a", "bazChannel" ],
  96. [ "", "bazChannel" ],
  97. [ "r\n", "bazChannel" ],
  98. ],
  99. "foo\nbar",
  100. true
  101. ],
  102. [
  103. [
  104. [ "foo", "bazChannel" ],
  105. [ "bar", "bazChannel" ],
  106. [ "qux", "quuxChannel" ],
  107. [ "corge", "bazChannel" ],
  108. ],
  109. "foobar\nqux\ncorge",
  110. true
  111. ],
  112. [
  113. [
  114. [ "foo", "bazChannel" ],
  115. [ "bar\n", "bazChannel" ],
  116. [ "qux\n", "quuxChannel" ],
  117. [ "corge", "bazChannel" ],
  118. ],
  119. "foobar\nqux\ncorge",
  120. true
  121. ],
  122. [
  123. [
  124. [ "foo", null ],
  125. [ "bar", "bazChannel" ],
  126. [ "qux", null ],
  127. [ "quux", "bazChannel" ],
  128. ],
  129. "foobar\nquxquux",
  130. true
  131. ],
  132. [
  133. [
  134. [ "foo", "bazChannel" ],
  135. [ "bar", null ],
  136. [ "qux", "bazChannel" ],
  137. [ "quux", null ],
  138. ],
  139. "foo\nbarqux\nquux",
  140. false
  141. ],
  142. [
  143. [
  144. [ "foo", 1 ],
  145. [ "bar", 1.0 ],
  146. ],
  147. "foo\nbar",
  148. true
  149. ],
  150. [ [ "foo", "", "bar" ], "foobar", false ],
  151. [ [ "foo", false, "bar" ], "foobar", false ],
  152. [
  153. [
  154. [ "qux", "quuxChannel" ],
  155. "foo",
  156. false,
  157. "bar"
  158. ],
  159. "qux\nfoobar",
  160. false
  161. ],
  162. [
  163. [
  164. [ "foo", "bazChannel" ],
  165. [ "", "bazChannel" ],
  166. [ "bar", "bazChannel" ],
  167. ],
  168. "foobar",
  169. true
  170. ],
  171. [
  172. [
  173. [ "foo", "bazChannel" ],
  174. [ false, "bazChannel" ],
  175. [ "bar", "bazChannel" ],
  176. ],
  177. "foobar",
  178. true
  179. ],
  180. ];
  181. }
  182. /**
  183. * @dataProvider provideOutputChanneledData
  184. */
  185. function testOutputChanneled( $outputs, $expected, $extraNL ) {
  186. foreach ( $outputs as $data ) {
  187. if ( is_array( $data ) ) {
  188. list( $msg, $channel ) = $data;
  189. } else {
  190. $msg = $data;
  191. $channel = null;
  192. }
  193. $this->maintenance->outputChanneled( $msg, $channel );
  194. }
  195. $this->assertOutputPrePostShutdown( $expected, $extraNL );
  196. }
  197. public function provideOutputChanneledData() {
  198. return [
  199. [ [ "" ], "\n", false ],
  200. [ [ "foo" ], "foo\n", false ],
  201. [ [ "foo", "bar" ], "foo\nbar\n", false ],
  202. [ [ "foo\nbar" ], "foo\nbar\n", false ],
  203. [ [ "", "foo", "", "\nb", "a", "", "r" ], "\nfoo\n\n\nb\na\n\nr\n", false ],
  204. [ [ [ "foo", "bazChannel" ] ], "foo", true ],
  205. [
  206. [
  207. [ "foo\nbar", "bazChannel" ]
  208. ],
  209. "foo\nbar",
  210. true
  211. ],
  212. [
  213. [
  214. [ "foo", "bazChannel" ],
  215. [ "bar", "bazChannel" ],
  216. ],
  217. "foobar",
  218. true
  219. ],
  220. [
  221. [
  222. [ "", "bazChannel" ],
  223. [ "foo", "bazChannel" ],
  224. [ "", "bazChannel" ],
  225. [ "\nb", "bazChannel" ],
  226. [ "a", "bazChannel" ],
  227. [ "", "bazChannel" ],
  228. [ "r", "bazChannel" ],
  229. ],
  230. "foo\nbar",
  231. true
  232. ],
  233. [
  234. [
  235. [ "foo", "bazChannel" ],
  236. [ "bar", "bazChannel" ],
  237. [ "qux", "quuxChannel" ],
  238. [ "corge", "bazChannel" ],
  239. ],
  240. "foobar\nqux\ncorge",
  241. true
  242. ],
  243. [
  244. [
  245. [ "foo", "bazChannel" ],
  246. [ "bar", "bazChannel" ],
  247. [ "qux", "quuxChannel" ],
  248. [ "corge", "bazChannel" ],
  249. ],
  250. "foobar\nqux\ncorge",
  251. true
  252. ],
  253. [
  254. [
  255. [ "foo", "bazChannel" ],
  256. [ "bar", null ],
  257. [ "qux", null ],
  258. [ "corge", "bazChannel" ],
  259. ],
  260. "foo\nbar\nqux\ncorge",
  261. true
  262. ],
  263. [
  264. [
  265. [ "foo", null ],
  266. [ "bar", "bazChannel" ],
  267. [ "qux", null ],
  268. [ "quux", "bazChannel" ],
  269. ],
  270. "foo\nbar\nqux\nquux",
  271. true
  272. ],
  273. [
  274. [
  275. [ "foo", "bazChannel" ],
  276. [ "bar", null ],
  277. [ "qux", "bazChannel" ],
  278. [ "quux", null ],
  279. ],
  280. "foo\nbar\nqux\nquux\n",
  281. false
  282. ],
  283. [
  284. [
  285. [ "foo", 1 ],
  286. [ "bar", 1.0 ],
  287. ],
  288. "foo\nbar",
  289. true
  290. ],
  291. [ [ "foo", "", "bar" ], "foo\n\nbar\n", false ],
  292. [ [ "foo", false, "bar" ], "foo\nbar\n", false ],
  293. ];
  294. }
  295. function testCleanupChanneledClean() {
  296. $this->maintenance->cleanupChanneled();
  297. $this->assertOutputPrePostShutdown( "", false );
  298. }
  299. function testCleanupChanneledAfterOutput() {
  300. $this->maintenance->output( "foo" );
  301. $this->maintenance->cleanupChanneled();
  302. $this->assertOutputPrePostShutdown( "foo", false );
  303. }
  304. function testCleanupChanneledAfterOutputWNullChannel() {
  305. $this->maintenance->output( "foo", null );
  306. $this->maintenance->cleanupChanneled();
  307. $this->assertOutputPrePostShutdown( "foo", false );
  308. }
  309. function testCleanupChanneledAfterOutputWChannel() {
  310. $this->maintenance->output( "foo", "bazChannel" );
  311. $this->maintenance->cleanupChanneled();
  312. $this->assertOutputPrePostShutdown( "foo\n", false );
  313. }
  314. function testCleanupChanneledAfterNLOutput() {
  315. $this->maintenance->output( "foo\n" );
  316. $this->maintenance->cleanupChanneled();
  317. $this->assertOutputPrePostShutdown( "foo\n", false );
  318. }
  319. function testCleanupChanneledAfterNLOutputWNullChannel() {
  320. $this->maintenance->output( "foo\n", null );
  321. $this->maintenance->cleanupChanneled();
  322. $this->assertOutputPrePostShutdown( "foo\n", false );
  323. }
  324. function testCleanupChanneledAfterNLOutputWChannel() {
  325. $this->maintenance->output( "foo\n", "bazChannel" );
  326. $this->maintenance->cleanupChanneled();
  327. $this->assertOutputPrePostShutdown( "foo\n", false );
  328. }
  329. function testCleanupChanneledAfterOutputChanneledWOChannel() {
  330. $this->maintenance->outputChanneled( "foo" );
  331. $this->maintenance->cleanupChanneled();
  332. $this->assertOutputPrePostShutdown( "foo\n", false );
  333. }
  334. function testCleanupChanneledAfterOutputChanneledWNullChannel() {
  335. $this->maintenance->outputChanneled( "foo", null );
  336. $this->maintenance->cleanupChanneled();
  337. $this->assertOutputPrePostShutdown( "foo\n", false );
  338. }
  339. function testCleanupChanneledAfterOutputChanneledWChannel() {
  340. $this->maintenance->outputChanneled( "foo", "bazChannel" );
  341. $this->maintenance->cleanupChanneled();
  342. $this->assertOutputPrePostShutdown( "foo\n", false );
  343. }
  344. function testMultipleMaintenanceObjectsInteractionOutput() {
  345. $m2 = $this->createMaintenance();
  346. $this->maintenance->output( "foo" );
  347. $m2->output( "bar" );
  348. $this->assertEquals( "foobar", $this->getActualOutput(),
  349. "Output before shutdown simulation (m2)" );
  350. $m2->cleanupChanneled();
  351. $this->assertOutputPrePostShutdown( "foobar", false );
  352. }
  353. function testMultipleMaintenanceObjectsInteractionOutputWNullChannel() {
  354. $m2 = $this->createMaintenance();
  355. $this->maintenance->output( "foo", null );
  356. $m2->output( "bar", null );
  357. $this->assertEquals( "foobar", $this->getActualOutput(),
  358. "Output before shutdown simulation (m2)" );
  359. $m2->cleanupChanneled();
  360. $this->assertOutputPrePostShutdown( "foobar", false );
  361. }
  362. function testMultipleMaintenanceObjectsInteractionOutputWChannel() {
  363. $m2 = $this->createMaintenance();
  364. $this->maintenance->output( "foo", "bazChannel" );
  365. $m2->output( "bar", "bazChannel" );
  366. $this->assertEquals( "foobar", $this->getActualOutput(),
  367. "Output before shutdown simulation (m2)" );
  368. $m2->cleanupChanneled();
  369. $this->assertOutputPrePostShutdown( "foobar\n", true );
  370. }
  371. function testMultipleMaintenanceObjectsInteractionOutputWNullChannelNL() {
  372. $m2 = $this->createMaintenance();
  373. $this->maintenance->output( "foo\n", null );
  374. $m2->output( "bar\n", null );
  375. $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
  376. "Output before shutdown simulation (m2)" );
  377. $m2->cleanupChanneled();
  378. $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
  379. }
  380. function testMultipleMaintenanceObjectsInteractionOutputWChannelNL() {
  381. $m2 = $this->createMaintenance();
  382. $this->maintenance->output( "foo\n", "bazChannel" );
  383. $m2->output( "bar\n", "bazChannel" );
  384. $this->assertEquals( "foobar", $this->getActualOutput(),
  385. "Output before shutdown simulation (m2)" );
  386. $m2->cleanupChanneled();
  387. $this->assertOutputPrePostShutdown( "foobar\n", true );
  388. }
  389. function testMultipleMaintenanceObjectsInteractionOutputChanneled() {
  390. $m2 = $this->createMaintenance();
  391. $this->maintenance->outputChanneled( "foo" );
  392. $m2->outputChanneled( "bar" );
  393. $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
  394. "Output before shutdown simulation (m2)" );
  395. $m2->cleanupChanneled();
  396. $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
  397. }
  398. function testMultipleMaintenanceObjectsInteractionOutputChanneledWNullChannel() {
  399. $m2 = $this->createMaintenance();
  400. $this->maintenance->outputChanneled( "foo", null );
  401. $m2->outputChanneled( "bar", null );
  402. $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
  403. "Output before shutdown simulation (m2)" );
  404. $m2->cleanupChanneled();
  405. $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
  406. }
  407. function testMultipleMaintenanceObjectsInteractionOutputChanneledWChannel() {
  408. $m2 = $this->createMaintenance();
  409. $this->maintenance->outputChanneled( "foo", "bazChannel" );
  410. $m2->outputChanneled( "bar", "bazChannel" );
  411. $this->assertEquals( "foobar", $this->getActualOutput(),
  412. "Output before shutdown simulation (m2)" );
  413. $m2->cleanupChanneled();
  414. $this->assertOutputPrePostShutdown( "foobar\n", true );
  415. }
  416. function testMultipleMaintenanceObjectsInteractionCleanupChanneledWChannel() {
  417. $m2 = $this->createMaintenance();
  418. $this->maintenance->outputChanneled( "foo", "bazChannel" );
  419. $m2->outputChanneled( "bar", "bazChannel" );
  420. $this->assertEquals( "foobar", $this->getActualOutput(),
  421. "Output before first cleanup" );
  422. $this->maintenance->cleanupChanneled();
  423. $this->assertEquals( "foobar\n", $this->getActualOutput(),
  424. "Output after first cleanup" );
  425. $m2->cleanupChanneled();
  426. $this->assertEquals( "foobar\n\n", $this->getActualOutput(),
  427. "Output after second cleanup" );
  428. $m2->cleanupChanneled();
  429. $this->assertOutputPrePostShutdown( "foobar\n\n", false );
  430. }
  431. /**
  432. * @covers Maintenance::getConfig
  433. */
  434. public function testGetConfig() {
  435. $this->assertInstanceOf( 'Config', $this->maintenance->getConfig() );
  436. $this->assertSame(
  437. MediaWikiServices::getInstance()->getMainConfig(),
  438. $this->maintenance->getConfig()
  439. );
  440. }
  441. /**
  442. * @covers Maintenance::setConfig
  443. */
  444. public function testSetConfig() {
  445. $conf = $this->createMock( 'Config' );
  446. $this->maintenance->setConfig( $conf );
  447. $this->assertSame( $conf, $this->maintenance->getConfig() );
  448. }
  449. function testParseArgs() {
  450. $m2 = $this->createMaintenance();
  451. // Create an option with an argument allowed to be specified multiple times
  452. $m2->addOption( 'multi', 'This option does stuff', false, true, false, true );
  453. $m2->loadWithArgv( [ '--multi', 'this1', '--multi', 'this2' ] );
  454. $this->assertEquals( [ 'this1', 'this2' ], $m2->getOption( 'multi' ) );
  455. $this->assertEquals( [ [ 'multi', 'this1' ], [ 'multi', 'this2' ] ],
  456. $m2->orderedOptions );
  457. $m2->cleanupChanneled();
  458. $m2 = $this->createMaintenance();
  459. $m2->addOption( 'multi', 'This option does stuff', false, false, false, true );
  460. $m2->loadWithArgv( [ '--multi', '--multi' ] );
  461. $this->assertEquals( [ 1, 1 ], $m2->getOption( 'multi' ) );
  462. $this->assertEquals( [ [ 'multi', 1 ], [ 'multi', 1 ] ], $m2->orderedOptions );
  463. $m2->cleanupChanneled();
  464. $m2 = $this->createMaintenance();
  465. // Create an option with an argument allowed to be specified multiple times
  466. $m2->addOption( 'multi', 'This option doesn\'t actually support multiple occurrences' );
  467. $m2->loadWithArgv( [ '--multi=yo' ] );
  468. $this->assertEquals( 'yo', $m2->getOption( 'multi' ) );
  469. $this->assertEquals( [ [ 'multi', 'yo' ] ], $m2->orderedOptions );
  470. $m2->cleanupChanneled();
  471. }
  472. }