PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/phpunit/includes/filerepo/FileBackendTest.php

https://bitbucket.org/glasshouse/glasshousewiki
PHP | 1868 lines | 1734 code | 95 blank | 39 comment | 20 complexity | ba55627cc361e951a0dbc40d29048fdb MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @group FileRepo
  4. * @group FileBackend
  5. * @group medium
  6. */
  7. class FileBackendTest extends MediaWikiTestCase {
  8. private $backend, $multiBackend;
  9. private $filesToPrune = array();
  10. private static $backendToUse;
  11. function setUp() {
  12. global $wgFileBackends;
  13. parent::setUp();
  14. $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand();
  15. if ( $this->getCliArg( 'use-filebackend=' ) ) {
  16. if ( self::$backendToUse ) {
  17. $this->singleBackend = self::$backendToUse;
  18. } else {
  19. $name = $this->getCliArg( 'use-filebackend=' );
  20. $useConfig = array();
  21. foreach ( $wgFileBackends as $conf ) {
  22. if ( $conf['name'] == $name ) {
  23. $useConfig = $conf;
  24. break;
  25. }
  26. }
  27. $useConfig['name'] = 'localtesting'; // swap name
  28. $useConfig['shardViaHashLevels'] = array( // test sharding
  29. 'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
  30. );
  31. $class = $useConfig['class'];
  32. self::$backendToUse = new $class( $useConfig );
  33. $this->singleBackend = self::$backendToUse;
  34. }
  35. } else {
  36. $this->singleBackend = new FSFileBackend( array(
  37. 'name' => 'localtesting',
  38. 'lockManager' => 'fsLockManager',
  39. #'parallelize' => 'implicit',
  40. 'containerPaths' => array(
  41. 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
  42. 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
  43. ) );
  44. }
  45. $this->multiBackend = new FileBackendMultiWrite( array(
  46. 'name' => 'localtesting',
  47. 'lockManager' => 'fsLockManager',
  48. 'parallelize' => 'implicit',
  49. 'backends' => array(
  50. array(
  51. 'name' => 'localmutlitesting1',
  52. 'class' => 'FSFileBackend',
  53. 'lockManager' => 'nullLockManager',
  54. 'containerPaths' => array(
  55. 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
  56. 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
  57. 'isMultiMaster' => false
  58. ),
  59. array(
  60. 'name' => 'localmutlitesting2',
  61. 'class' => 'FSFileBackend',
  62. 'lockManager' => 'nullLockManager',
  63. 'containerPaths' => array(
  64. 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
  65. 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
  66. 'isMultiMaster' => true
  67. )
  68. )
  69. ) );
  70. $this->filesToPrune = array();
  71. }
  72. private function baseStorePath() {
  73. return 'mwstore://localtesting';
  74. }
  75. private function backendClass() {
  76. return get_class( $this->backend );
  77. }
  78. /**
  79. * @dataProvider provider_testIsStoragePath
  80. */
  81. public function testIsStoragePath( $path, $isStorePath ) {
  82. $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ),
  83. "FileBackend::isStoragePath on path '$path'" );
  84. }
  85. function provider_testIsStoragePath() {
  86. return array(
  87. array( 'mwstore://', true ),
  88. array( 'mwstore://backend', true ),
  89. array( 'mwstore://backend/container', true ),
  90. array( 'mwstore://backend/container/', true ),
  91. array( 'mwstore://backend/container/path', true ),
  92. array( 'mwstore://backend//container/', true ),
  93. array( 'mwstore://backend//container//', true ),
  94. array( 'mwstore://backend//container//path', true ),
  95. array( 'mwstore:///', true ),
  96. array( 'mwstore:/', false ),
  97. array( 'mwstore:', false ),
  98. );
  99. }
  100. /**
  101. * @dataProvider provider_testSplitStoragePath
  102. */
  103. public function testSplitStoragePath( $path, $res ) {
  104. $this->assertEquals( $res, FileBackend::splitStoragePath( $path ),
  105. "FileBackend::splitStoragePath on path '$path'" );
  106. }
  107. function provider_testSplitStoragePath() {
  108. return array(
  109. array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
  110. array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
  111. array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
  112. array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
  113. array( 'mwstore://backend//container/path', array( null, null, null ) ),
  114. array( 'mwstore://backend//container//path', array( null, null, null ) ),
  115. array( 'mwstore://', array( null, null, null ) ),
  116. array( 'mwstore://backend', array( null, null, null ) ),
  117. array( 'mwstore:///', array( null, null, null ) ),
  118. array( 'mwstore:/', array( null, null, null ) ),
  119. array( 'mwstore:', array( null, null, null ) )
  120. );
  121. }
  122. /**
  123. * @dataProvider provider_normalizeStoragePath
  124. */
  125. public function testNormalizeStoragePath( $path, $res ) {
  126. $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ),
  127. "FileBackend::normalizeStoragePath on path '$path'" );
  128. }
  129. function provider_normalizeStoragePath() {
  130. return array(
  131. array( 'mwstore://backend/container', 'mwstore://backend/container' ),
  132. array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
  133. array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
  134. array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
  135. array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
  136. array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj',
  137. array( 'mwstore://', null ),
  138. array( 'mwstore://backend', null ),
  139. array( 'mwstore://backend//container/path', null ),
  140. array( 'mwstore://backend//container//path', null ),
  141. array( 'mwstore:///', null ),
  142. array( 'mwstore:/', null ),
  143. array( 'mwstore:', null ), )
  144. );
  145. }
  146. /**
  147. * @dataProvider provider_testParentStoragePath
  148. */
  149. public function testParentStoragePath( $path, $res ) {
  150. $this->assertEquals( $res, FileBackend::parentStoragePath( $path ),
  151. "FileBackend::parentStoragePath on path '$path'" );
  152. }
  153. function provider_testParentStoragePath() {
  154. return array(
  155. array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
  156. array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
  157. array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
  158. array( 'mwstore://backend/container', null ),
  159. array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
  160. array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
  161. array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
  162. array( 'mwstore://backend/container/', null ),
  163. );
  164. }
  165. /**
  166. * @dataProvider provider_testExtensionFromPath
  167. */
  168. public function testExtensionFromPath( $path, $res ) {
  169. $this->assertEquals( $res, FileBackend::extensionFromPath( $path ),
  170. "FileBackend::extensionFromPath on path '$path'" );
  171. }
  172. function provider_testExtensionFromPath() {
  173. return array(
  174. array( 'mwstore://backend/container/path.txt', 'txt' ),
  175. array( 'mwstore://backend/container/path.svg.png', 'png' ),
  176. array( 'mwstore://backend/container/path', '' ),
  177. array( 'mwstore://backend/container/path.', '' ),
  178. );
  179. }
  180. /**
  181. * @dataProvider provider_testStore
  182. */
  183. public function testStore( $op ) {
  184. $this->filesToPrune[] = $op['src'];
  185. $this->backend = $this->singleBackend;
  186. $this->tearDownFiles();
  187. $this->doTestStore( $op );
  188. $this->tearDownFiles();
  189. $this->backend = $this->multiBackend;
  190. $this->tearDownFiles();
  191. $this->doTestStore( $op );
  192. $this->filesToPrune[] = $op['src']; # avoid file leaking
  193. $this->tearDownFiles();
  194. }
  195. private function doTestStore( $op ) {
  196. $backendName = $this->backendClass();
  197. $source = $op['src'];
  198. $dest = $op['dst'];
  199. $this->prepare( array( 'dir' => dirname( $dest ) ) );
  200. file_put_contents( $source, "Unit test file" );
  201. if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
  202. $this->backend->store( $op );
  203. }
  204. $status = $this->backend->doOperation( $op );
  205. $this->assertGoodStatus( $status,
  206. "Store from $source to $dest succeeded without warnings ($backendName)." );
  207. $this->assertEquals( true, $status->isOK(),
  208. "Store from $source to $dest succeeded ($backendName)." );
  209. $this->assertEquals( array( 0 => true ), $status->success,
  210. "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
  211. $this->assertEquals( true, file_exists( $source ),
  212. "Source file $source still exists ($backendName)." );
  213. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
  214. "Destination file $dest exists ($backendName)." );
  215. $this->assertEquals( filesize( $source ),
  216. $this->backend->getFileSize( array( 'src' => $dest ) ),
  217. "Destination file $dest has correct size ($backendName)." );
  218. $props1 = FSFile::getPropsFromPath( $source );
  219. $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
  220. $this->assertEquals( $props1, $props2,
  221. "Source and destination have the same props ($backendName)." );
  222. $this->assertBackendPathsConsistent( array( $dest ) );
  223. }
  224. public function provider_testStore() {
  225. $cases = array();
  226. $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
  227. $toPath = $this->baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
  228. $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
  229. $cases[] = array(
  230. $op, // operation
  231. $tmpName, // source
  232. $toPath, // dest
  233. );
  234. $op2 = $op;
  235. $op2['overwrite'] = true;
  236. $cases[] = array(
  237. $op2, // operation
  238. $tmpName, // source
  239. $toPath, // dest
  240. );
  241. $op2 = $op;
  242. $op2['overwriteSame'] = true;
  243. $cases[] = array(
  244. $op2, // operation
  245. $tmpName, // source
  246. $toPath, // dest
  247. );
  248. return $cases;
  249. }
  250. /**
  251. * @dataProvider provider_testCopy
  252. */
  253. public function testCopy( $op ) {
  254. $this->backend = $this->singleBackend;
  255. $this->tearDownFiles();
  256. $this->doTestCopy( $op );
  257. $this->tearDownFiles();
  258. $this->backend = $this->multiBackend;
  259. $this->tearDownFiles();
  260. $this->doTestCopy( $op );
  261. $this->tearDownFiles();
  262. }
  263. private function doTestCopy( $op ) {
  264. $backendName = $this->backendClass();
  265. $source = $op['src'];
  266. $dest = $op['dst'];
  267. $this->prepare( array( 'dir' => dirname( $source ) ) );
  268. $this->prepare( array( 'dir' => dirname( $dest ) ) );
  269. $status = $this->backend->doOperation(
  270. array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
  271. $this->assertGoodStatus( $status,
  272. "Creation of file at $source succeeded ($backendName)." );
  273. if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
  274. $this->backend->copy( $op );
  275. }
  276. $status = $this->backend->doOperation( $op );
  277. $this->assertGoodStatus( $status,
  278. "Copy from $source to $dest succeeded without warnings ($backendName)." );
  279. $this->assertEquals( true, $status->isOK(),
  280. "Copy from $source to $dest succeeded ($backendName)." );
  281. $this->assertEquals( array( 0 => true ), $status->success,
  282. "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
  283. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
  284. "Source file $source still exists ($backendName)." );
  285. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
  286. "Destination file $dest exists after copy ($backendName)." );
  287. $this->assertEquals(
  288. $this->backend->getFileSize( array( 'src' => $source ) ),
  289. $this->backend->getFileSize( array( 'src' => $dest ) ),
  290. "Destination file $dest has correct size ($backendName)." );
  291. $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
  292. $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
  293. $this->assertEquals( $props1, $props2,
  294. "Source and destination have the same props ($backendName)." );
  295. $this->assertBackendPathsConsistent( array( $source, $dest ) );
  296. }
  297. public function provider_testCopy() {
  298. $cases = array();
  299. $source = $this->baseStorePath() . '/unittest-cont1/e/file.txt';
  300. $dest = $this->baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
  301. $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
  302. $cases[] = array(
  303. $op, // operation
  304. $source, // source
  305. $dest, // dest
  306. );
  307. $op2 = $op;
  308. $op2['overwrite'] = true;
  309. $cases[] = array(
  310. $op2, // operation
  311. $source, // source
  312. $dest, // dest
  313. );
  314. $op2 = $op;
  315. $op2['overwriteSame'] = true;
  316. $cases[] = array(
  317. $op2, // operation
  318. $source, // source
  319. $dest, // dest
  320. );
  321. return $cases;
  322. }
  323. /**
  324. * @dataProvider provider_testMove
  325. */
  326. public function testMove( $op ) {
  327. $this->backend = $this->singleBackend;
  328. $this->tearDownFiles();
  329. $this->doTestMove( $op );
  330. $this->tearDownFiles();
  331. $this->backend = $this->multiBackend;
  332. $this->tearDownFiles();
  333. $this->doTestMove( $op );
  334. $this->tearDownFiles();
  335. }
  336. private function doTestMove( $op ) {
  337. $backendName = $this->backendClass();
  338. $source = $op['src'];
  339. $dest = $op['dst'];
  340. $this->prepare( array( 'dir' => dirname( $source ) ) );
  341. $this->prepare( array( 'dir' => dirname( $dest ) ) );
  342. $status = $this->backend->doOperation(
  343. array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
  344. $this->assertGoodStatus( $status,
  345. "Creation of file at $source succeeded ($backendName)." );
  346. if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
  347. $this->backend->copy( $op );
  348. }
  349. $status = $this->backend->doOperation( $op );
  350. $this->assertGoodStatus( $status,
  351. "Move from $source to $dest succeeded without warnings ($backendName)." );
  352. $this->assertEquals( true, $status->isOK(),
  353. "Move from $source to $dest succeeded ($backendName)." );
  354. $this->assertEquals( array( 0 => true ), $status->success,
  355. "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
  356. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
  357. "Source file $source does not still exists ($backendName)." );
  358. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
  359. "Destination file $dest exists after move ($backendName)." );
  360. $this->assertNotEquals(
  361. $this->backend->getFileSize( array( 'src' => $source ) ),
  362. $this->backend->getFileSize( array( 'src' => $dest ) ),
  363. "Destination file $dest has correct size ($backendName)." );
  364. $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
  365. $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
  366. $this->assertEquals( false, $props1['fileExists'],
  367. "Source file does not exist accourding to props ($backendName)." );
  368. $this->assertEquals( true, $props2['fileExists'],
  369. "Destination file exists accourding to props ($backendName)." );
  370. $this->assertBackendPathsConsistent( array( $source, $dest ) );
  371. }
  372. public function provider_testMove() {
  373. $cases = array();
  374. $source = $this->baseStorePath() . '/unittest-cont1/e/file.txt';
  375. $dest = $this->baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
  376. $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
  377. $cases[] = array(
  378. $op, // operation
  379. $source, // source
  380. $dest, // dest
  381. );
  382. $op2 = $op;
  383. $op2['overwrite'] = true;
  384. $cases[] = array(
  385. $op2, // operation
  386. $source, // source
  387. $dest, // dest
  388. );
  389. $op2 = $op;
  390. $op2['overwriteSame'] = true;
  391. $cases[] = array(
  392. $op2, // operation
  393. $source, // source
  394. $dest, // dest
  395. );
  396. return $cases;
  397. }
  398. /**
  399. * @dataProvider provider_testDelete
  400. */
  401. public function testDelete( $op, $withSource, $okStatus ) {
  402. $this->backend = $this->singleBackend;
  403. $this->tearDownFiles();
  404. $this->doTestDelete( $op, $withSource, $okStatus );
  405. $this->tearDownFiles();
  406. $this->backend = $this->multiBackend;
  407. $this->tearDownFiles();
  408. $this->doTestDelete( $op, $withSource, $okStatus );
  409. $this->tearDownFiles();
  410. }
  411. private function doTestDelete( $op, $withSource, $okStatus ) {
  412. $backendName = $this->backendClass();
  413. $source = $op['src'];
  414. $this->prepare( array( 'dir' => dirname( $source ) ) );
  415. if ( $withSource ) {
  416. $status = $this->backend->doOperation(
  417. array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
  418. $this->assertGoodStatus( $status,
  419. "Creation of file at $source succeeded ($backendName)." );
  420. }
  421. $status = $this->backend->doOperation( $op );
  422. if ( $okStatus ) {
  423. $this->assertGoodStatus( $status,
  424. "Deletion of file at $source succeeded without warnings ($backendName)." );
  425. $this->assertEquals( true, $status->isOK(),
  426. "Deletion of file at $source succeeded ($backendName)." );
  427. $this->assertEquals( array( 0 => true ), $status->success,
  428. "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
  429. } else {
  430. $this->assertEquals( false, $status->isOK(),
  431. "Deletion of file at $source failed ($backendName)." );
  432. }
  433. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
  434. "Source file $source does not exist after move ($backendName)." );
  435. $this->assertFalse(
  436. $this->backend->getFileSize( array( 'src' => $source ) ),
  437. "Source file $source has correct size (false) ($backendName)." );
  438. $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
  439. $this->assertFalse( $props1['fileExists'],
  440. "Source file $source does not exist according to props ($backendName)." );
  441. $this->assertBackendPathsConsistent( array( $source ) );
  442. }
  443. public function provider_testDelete() {
  444. $cases = array();
  445. $source = $this->baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
  446. $op = array( 'op' => 'delete', 'src' => $source );
  447. $cases[] = array(
  448. $op, // operation
  449. true, // with source
  450. true // succeeds
  451. );
  452. $cases[] = array(
  453. $op, // operation
  454. false, // without source
  455. false // fails
  456. );
  457. $op['ignoreMissingSource'] = true;
  458. $cases[] = array(
  459. $op, // operation
  460. false, // without source
  461. true // succeeds
  462. );
  463. return $cases;
  464. }
  465. /**
  466. * @dataProvider provider_testCreate
  467. */
  468. public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
  469. $this->backend = $this->singleBackend;
  470. $this->tearDownFiles();
  471. $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
  472. $this->tearDownFiles();
  473. $this->backend = $this->multiBackend;
  474. $this->tearDownFiles();
  475. $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
  476. $this->tearDownFiles();
  477. }
  478. private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
  479. $backendName = $this->backendClass();
  480. $dest = $op['dst'];
  481. $this->prepare( array( 'dir' => dirname( $dest ) ) );
  482. $oldText = 'blah...blah...waahwaah';
  483. if ( $alreadyExists ) {
  484. $status = $this->backend->doOperation(
  485. array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
  486. $this->assertGoodStatus( $status,
  487. "Creation of file at $dest succeeded ($backendName)." );
  488. }
  489. $status = $this->backend->doOperation( $op );
  490. if ( $okStatus ) {
  491. $this->assertGoodStatus( $status,
  492. "Creation of file at $dest succeeded without warnings ($backendName)." );
  493. $this->assertEquals( true, $status->isOK(),
  494. "Creation of file at $dest succeeded ($backendName)." );
  495. $this->assertEquals( array( 0 => true ), $status->success,
  496. "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
  497. } else {
  498. $this->assertEquals( false, $status->isOK(),
  499. "Creation of file at $dest failed ($backendName)." );
  500. }
  501. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
  502. "Destination file $dest exists after creation ($backendName)." );
  503. $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
  504. $this->assertEquals( true, $props1['fileExists'],
  505. "Destination file $dest exists according to props ($backendName)." );
  506. if ( $okStatus ) { // file content is what we saved
  507. $this->assertEquals( $newSize, $props1['size'],
  508. "Destination file $dest has expected size according to props ($backendName)." );
  509. $this->assertEquals( $newSize,
  510. $this->backend->getFileSize( array( 'src' => $dest ) ),
  511. "Destination file $dest has correct size ($backendName)." );
  512. } else { // file content is some other previous text
  513. $this->assertEquals( strlen( $oldText ), $props1['size'],
  514. "Destination file $dest has original size according to props ($backendName)." );
  515. $this->assertEquals( strlen( $oldText ),
  516. $this->backend->getFileSize( array( 'src' => $dest ) ),
  517. "Destination file $dest has original size according to props ($backendName)." );
  518. }
  519. $this->assertBackendPathsConsistent( array( $dest ) );
  520. }
  521. /**
  522. * @dataProvider provider_testCreate
  523. */
  524. public function provider_testCreate() {
  525. $cases = array();
  526. $dest = $this->baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
  527. $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
  528. $cases[] = array(
  529. $op, // operation
  530. false, // no dest already exists
  531. true, // succeeds
  532. strlen( $op['content'] )
  533. );
  534. $op2 = $op;
  535. $op2['content'] = "\n";
  536. $cases[] = array(
  537. $op2, // operation
  538. false, // no dest already exists
  539. true, // succeeds
  540. strlen( $op2['content'] )
  541. );
  542. $op2 = $op;
  543. $op2['content'] = "fsf\n waf 3kt";
  544. $cases[] = array(
  545. $op2, // operation
  546. true, // dest already exists
  547. false, // fails
  548. strlen( $op2['content'] )
  549. );
  550. $op2 = $op;
  551. $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
  552. $op2['overwrite'] = true;
  553. $cases[] = array(
  554. $op2, // operation
  555. true, // dest already exists
  556. true, // succeeds
  557. strlen( $op2['content'] )
  558. );
  559. $op2 = $op;
  560. $op2['content'] = "39qjmg3-qg";
  561. $op2['overwriteSame'] = true;
  562. $cases[] = array(
  563. $op2, // operation
  564. true, // dest already exists
  565. false, // succeeds
  566. strlen( $op2['content'] )
  567. );
  568. return $cases;
  569. }
  570. public function testDoQuickOperations() {
  571. $this->backend = $this->singleBackend;
  572. $this->doTestDoQuickOperations();
  573. $this->tearDownFiles();
  574. $this->backend = $this->multiBackend;
  575. $this->doTestDoQuickOperations();
  576. $this->tearDownFiles();
  577. }
  578. private function doTestDoQuickOperations() {
  579. $backendName = $this->backendClass();
  580. $base = $this->baseStorePath();
  581. $files = array(
  582. "$base/unittest-cont1/e/fileA.a",
  583. "$base/unittest-cont1/e/fileB.a",
  584. "$base/unittest-cont1/e/fileC.a"
  585. );
  586. $ops = array();
  587. $purgeOps = array();
  588. foreach ( $files as $path ) {
  589. $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
  590. $this->assertGoodStatus( $status,
  591. "Preparing $path succeeded without warnings ($backendName)." );
  592. $ops[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand(0,50000) );
  593. $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
  594. }
  595. $purgeOps[] = array( 'op' => 'null' );
  596. $status = $this->backend->doQuickOperations( $ops );
  597. $this->assertGoodStatus( $status,
  598. "Creation of source files succeeded ($backendName)." );
  599. foreach ( $files as $file ) {
  600. $this->assertTrue( $this->backend->fileExists( array( 'src' => $file ) ),
  601. "File $file exists." );
  602. }
  603. $status = $this->backend->doQuickOperations( $purgeOps );
  604. $this->assertGoodStatus( $status,
  605. "Quick deletion of source files succeeded ($backendName)." );
  606. foreach ( $files as $file ) {
  607. $this->assertFalse( $this->backend->fileExists( array( 'src' => $file ) ),
  608. "File $file purged." );
  609. }
  610. }
  611. /**
  612. * @dataProvider provider_testConcatenate
  613. */
  614. public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
  615. $this->filesToPrune[] = $op['dst'];
  616. $this->backend = $this->singleBackend;
  617. $this->tearDownFiles();
  618. $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
  619. $this->tearDownFiles();
  620. $this->backend = $this->multiBackend;
  621. $this->tearDownFiles();
  622. $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
  623. $this->filesToPrune[] = $op['dst']; # avoid file leaking
  624. $this->tearDownFiles();
  625. }
  626. private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
  627. $backendName = $this->backendClass();
  628. $expContent = '';
  629. // Create sources
  630. $ops = array();
  631. foreach ( $srcs as $i => $source ) {
  632. $this->prepare( array( 'dir' => dirname( $source ) ) );
  633. $ops[] = array(
  634. 'op' => 'create', // operation
  635. 'dst' => $source, // source
  636. 'content' => $srcsContent[$i]
  637. );
  638. $expContent .= $srcsContent[$i];
  639. }
  640. $status = $this->backend->doOperations( $ops );
  641. $this->assertGoodStatus( $status,
  642. "Creation of source files succeeded ($backendName)." );
  643. $dest = $params['dst'];
  644. if ( $alreadyExists ) {
  645. $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
  646. $this->assertEquals( true, $ok,
  647. "Creation of file at $dest succeeded ($backendName)." );
  648. } else {
  649. $ok = file_put_contents( $dest, '' ) !== false;
  650. $this->assertEquals( true, $ok,
  651. "Creation of 0-byte file at $dest succeeded ($backendName)." );
  652. }
  653. // Combine the files into one
  654. $status = $this->backend->concatenate( $params );
  655. if ( $okStatus ) {
  656. $this->assertGoodStatus( $status,
  657. "Creation of concat file at $dest succeeded without warnings ($backendName)." );
  658. $this->assertEquals( true, $status->isOK(),
  659. "Creation of concat file at $dest succeeded ($backendName)." );
  660. } else {
  661. $this->assertEquals( false, $status->isOK(),
  662. "Creation of concat file at $dest failed ($backendName)." );
  663. }
  664. if ( $okStatus ) {
  665. $this->assertEquals( true, is_file( $dest ),
  666. "Dest concat file $dest exists after creation ($backendName)." );
  667. } else {
  668. $this->assertEquals( true, is_file( $dest ),
  669. "Dest concat file $dest exists after failed creation ($backendName)." );
  670. }
  671. $contents = file_get_contents( $dest );
  672. $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
  673. if ( $okStatus ) {
  674. $this->assertEquals( $expContent, $contents,
  675. "Concat file at $dest has correct contents ($backendName)." );
  676. } else {
  677. $this->assertNotEquals( $expContent, $contents,
  678. "Concat file at $dest has correct contents ($backendName)." );
  679. }
  680. }
  681. function provider_testConcatenate() {
  682. $cases = array();
  683. $rand = mt_rand( 0, 2000000000 ) . time();
  684. $dest = wfTempDir() . "/randomfile!$rand.txt";
  685. $srcs = array(
  686. $this->baseStorePath() . '/unittest-cont1/e/file1.txt',
  687. $this->baseStorePath() . '/unittest-cont1/e/file2.txt',
  688. $this->baseStorePath() . '/unittest-cont1/e/file3.txt',
  689. $this->baseStorePath() . '/unittest-cont1/e/file4.txt',
  690. $this->baseStorePath() . '/unittest-cont1/e/file5.txt',
  691. $this->baseStorePath() . '/unittest-cont1/e/file6.txt',
  692. $this->baseStorePath() . '/unittest-cont1/e/file7.txt',
  693. $this->baseStorePath() . '/unittest-cont1/e/file8.txt',
  694. $this->baseStorePath() . '/unittest-cont1/e/file9.txt',
  695. $this->baseStorePath() . '/unittest-cont1/e/file10.txt'
  696. );
  697. $content = array(
  698. 'egfage',
  699. 'ageageag',
  700. 'rhokohlr',
  701. 'shgmslkg',
  702. 'kenga',
  703. 'owagmal',
  704. 'kgmae',
  705. 'g eak;g',
  706. 'lkaem;a',
  707. 'legma'
  708. );
  709. $params = array( 'srcs' => $srcs, 'dst' => $dest );
  710. $cases[] = array(
  711. $params, // operation
  712. $srcs, // sources
  713. $content, // content for each source
  714. false, // no dest already exists
  715. true, // succeeds
  716. );
  717. $cases[] = array(
  718. $params, // operation
  719. $srcs, // sources
  720. $content, // content for each source
  721. true, // dest already exists
  722. false, // succeeds
  723. );
  724. return $cases;
  725. }
  726. /**
  727. * @dataProvider provider_testGetFileStat
  728. */
  729. public function testGetFileStat( $path, $content, $alreadyExists ) {
  730. $this->backend = $this->singleBackend;
  731. $this->tearDownFiles();
  732. $this->doTestGetFileStat( $path, $content, $alreadyExists );
  733. $this->tearDownFiles();
  734. $this->backend = $this->multiBackend;
  735. $this->tearDownFiles();
  736. $this->doTestGetFileStat( $path, $content, $alreadyExists );
  737. $this->tearDownFiles();
  738. }
  739. private function doTestGetFileStat( $path, $content, $alreadyExists ) {
  740. $backendName = $this->backendClass();
  741. if ( $alreadyExists ) {
  742. $this->prepare( array( 'dir' => dirname( $path ) ) );
  743. $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
  744. $this->assertGoodStatus( $status,
  745. "Creation of file at $path succeeded ($backendName)." );
  746. $size = $this->backend->getFileSize( array( 'src' => $path ) );
  747. $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
  748. $stat = $this->backend->getFileStat( array( 'src' => $path ) );
  749. $this->assertEquals( strlen( $content ), $size,
  750. "Correct file size of '$path'" );
  751. $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
  752. "Correct file timestamp of '$path'" );
  753. $size = $stat['size'];
  754. $time = $stat['mtime'];
  755. $this->assertEquals( strlen( $content ), $size,
  756. "Correct file size of '$path'" );
  757. $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
  758. "Correct file timestamp of '$path'" );
  759. $this->backend->clearCache( array( $path ) );
  760. $size = $this->backend->getFileSize( array( 'src' => $path ) );
  761. $this->assertEquals( strlen( $content ), $size,
  762. "Correct file size of '$path'" );
  763. $this->backend->preloadCache( array( $path ) );
  764. $size = $this->backend->getFileSize( array( 'src' => $path ) );
  765. $this->assertEquals( strlen( $content ), $size,
  766. "Correct file size of '$path'" );
  767. } else {
  768. $size = $this->backend->getFileSize( array( 'src' => $path ) );
  769. $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
  770. $stat = $this->backend->getFileStat( array( 'src' => $path ) );
  771. $this->assertFalse( $size, "Correct file size of '$path'" );
  772. $this->assertFalse( $time, "Correct file timestamp of '$path'" );
  773. $this->assertFalse( $stat, "Correct file stat of '$path'" );
  774. }
  775. }
  776. function provider_testGetFileStat() {
  777. $cases = array();
  778. $base = $this->baseStorePath();
  779. $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
  780. $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
  781. $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
  782. return $cases;
  783. }
  784. /**
  785. * @dataProvider provider_testGetFileContents
  786. */
  787. public function testGetFileContents( $source, $content ) {
  788. $this->backend = $this->singleBackend;
  789. $this->tearDownFiles();
  790. $this->doTestGetFileContents( $source, $content );
  791. $this->tearDownFiles();
  792. $this->backend = $this->multiBackend;
  793. $this->tearDownFiles();
  794. $this->doTestGetFileContents( $source, $content );
  795. $this->tearDownFiles();
  796. }
  797. private function doTestGetFileContents( $source, $content ) {
  798. $backendName = $this->backendClass();
  799. $this->prepare( array( 'dir' => dirname( $source ) ) );
  800. $status = $this->backend->doOperation(
  801. array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
  802. $this->assertGoodStatus( $status,
  803. "Creation of file at $source succeeded ($backendName)." );
  804. $this->assertEquals( true, $status->isOK(),
  805. "Creation of file at $source succeeded with OK status ($backendName)." );
  806. $newContents = $this->backend->getFileContents( array( 'src' => $source, 'latest' => 1 ) );
  807. $this->assertNotEquals( false, $newContents,
  808. "Read of file at $source succeeded ($backendName)." );
  809. $this->assertEquals( $content, $newContents,
  810. "Contents read match data at $source ($backendName)." );
  811. }
  812. function provider_testGetFileContents() {
  813. $cases = array();
  814. $base = $this->baseStorePath();
  815. $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
  816. $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
  817. return $cases;
  818. }
  819. /**
  820. * @dataProvider provider_testGetLocalCopy
  821. */
  822. public function testGetLocalCopy( $source, $content ) {
  823. $this->backend = $this->singleBackend;
  824. $this->tearDownFiles();
  825. $this->doTestGetLocalCopy( $source, $content );
  826. $this->tearDownFiles();
  827. $this->backend = $this->multiBackend;
  828. $this->tearDownFiles();
  829. $this->doTestGetLocalCopy( $source, $content );
  830. $this->tearDownFiles();
  831. }
  832. private function doTestGetLocalCopy( $source, $content ) {
  833. $backendName = $this->backendClass();
  834. $this->prepare( array( 'dir' => dirname( $source ) ) );
  835. $status = $this->backend->doOperation(
  836. array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
  837. $this->assertGoodStatus( $status,
  838. "Creation of file at $source succeeded ($backendName)." );
  839. $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
  840. $this->assertNotNull( $tmpFile,
  841. "Creation of local copy of $source succeeded ($backendName)." );
  842. $contents = file_get_contents( $tmpFile->getPath() );
  843. $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
  844. }
  845. function provider_testGetLocalCopy() {
  846. $cases = array();
  847. $base = $this->baseStorePath();
  848. $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
  849. $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
  850. return $cases;
  851. }
  852. /**
  853. * @dataProvider provider_testGetLocalReference
  854. */
  855. public function testGetLocalReference( $source, $content ) {
  856. $this->backend = $this->singleBackend;
  857. $this->tearDownFiles();
  858. $this->doTestGetLocalReference( $source, $content );
  859. $this->tearDownFiles();
  860. $this->backend = $this->multiBackend;
  861. $this->tearDownFiles();
  862. $this->doTestGetLocalReference( $source, $content );
  863. $this->tearDownFiles();
  864. }
  865. private function doTestGetLocalReference( $source, $content ) {
  866. $backendName = $this->backendClass();
  867. $this->prepare( array( 'dir' => dirname( $source ) ) );
  868. $status = $this->create( array( 'content' => $content, 'dst' => $source ) );
  869. $this->assertGoodStatus( $status,
  870. "Creation of file at $source succeeded ($backendName)." );
  871. $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
  872. $this->assertNotNull( $tmpFile,
  873. "Creation of local copy of $source succeeded ($backendName)." );
  874. $contents = file_get_contents( $tmpFile->getPath() );
  875. $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
  876. }
  877. function provider_testGetLocalReference() {
  878. $cases = array();
  879. $base = $this->baseStorePath();
  880. $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
  881. $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
  882. return $cases;
  883. }
  884. /**
  885. * @dataProvider provider_testPrepareAndClean
  886. */
  887. public function testPrepareAndClean( $path, $isOK ) {
  888. $this->backend = $this->singleBackend;
  889. $this->doTestPrepareAndClean( $path, $isOK );
  890. $this->tearDownFiles();
  891. $this->backend = $this->multiBackend;
  892. $this->doTestPrepareAndClean( $path, $isOK );
  893. $this->tearDownFiles();
  894. }
  895. function provider_testPrepareAndClean() {
  896. $base = $this->baseStorePath();
  897. return array(
  898. array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
  899. array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
  900. # Specific to FS backend with no basePath field set
  901. #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
  902. );
  903. }
  904. private function doTestPrepareAndClean( $path, $isOK ) {
  905. $backendName = $this->backendClass();
  906. $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
  907. if ( $isOK ) {
  908. $this->assertGoodStatus( $status,
  909. "Preparing dir $path succeeded without warnings ($backendName)." );
  910. $this->assertEquals( true, $status->isOK(),
  911. "Preparing dir $path succeeded ($backendName)." );
  912. } else {
  913. $this->assertEquals( false, $status->isOK(),
  914. "Preparing dir $path failed ($backendName)." );
  915. }
  916. $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
  917. if ( $isOK ) {
  918. $this->assertGoodStatus( $status,
  919. "Cleaning dir $path succeeded without warnings ($backendName)." );
  920. $this->assertEquals( true, $status->isOK(),
  921. "Cleaning dir $path succeeded ($backendName)." );
  922. } else {
  923. $this->assertEquals( false, $status->isOK(),
  924. "Cleaning dir $path failed ($backendName)." );
  925. }
  926. }
  927. public function testRecursiveClean() {
  928. $this->backend = $this->singleBackend;
  929. $this->doTestRecursiveClean();
  930. $this->tearDownFiles();
  931. $this->backend = $this->multiBackend;
  932. $this->doTestRecursiveClean();
  933. $this->tearDownFiles();
  934. }
  935. private function doTestRecursiveClean() {
  936. $backendName = $this->backendClass();
  937. $base = $this->baseStorePath();
  938. $dirs = array(
  939. "$base/unittest-cont1/e/a",
  940. "$base/unittest-cont1/e/a/b",
  941. "$base/unittest-cont1/e/a/b/c",
  942. "$base/unittest-cont1/e/a/b/c/d0",
  943. "$base/unittest-cont1/e/a/b/c/d1",
  944. "$base/unittest-cont1/e/a/b/c/d2",
  945. "$base/unittest-cont1/e/a/b/c/d0/1",
  946. "$base/unittest-cont1/e/a/b/c/d0/2",
  947. "$base/unittest-cont1/e/a/b/c/d1/3",
  948. "$base/unittest-cont1/e/a/b/c/d1/4",
  949. "$base/unittest-cont1/e/a/b/c/d2/5",
  950. "$base/unittest-cont1/e/a/b/c/d2/6"
  951. );
  952. foreach ( $dirs as $dir ) {
  953. $status = $this->prepare( array( 'dir' => $dir ) );
  954. $this->assertGoodStatus( $status,
  955. "Preparing dir $dir succeeded without warnings ($backendName)." );
  956. }
  957. if ( $this->backend instanceof FSFileBackend ) {
  958. foreach ( $dirs as $dir ) {
  959. $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ),
  960. "Dir $dir exists ($backendName)." );
  961. }
  962. }
  963. $status = $this->backend->clean(
  964. array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
  965. $this->assertGoodStatus( $status,
  966. "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
  967. foreach ( $dirs as $dir ) {
  968. $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ),
  969. "Dir $dir no longer exists ($backendName)." );
  970. }
  971. }
  972. // @TODO: testSecure
  973. public function testDoOperations() {
  974. $this->backend = $this->singleBackend;
  975. $this->tearDownFiles();
  976. $this->doTestDoOperations();
  977. $this->tearDownFiles();
  978. $this->backend = $this->multiBackend;
  979. $this->tearDownFiles();
  980. $this->doTestDoOperations();
  981. $this->tearDownFiles();
  982. }
  983. private function doTestDoOperations() {
  984. $base = $this->baseStorePath();
  985. $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
  986. $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
  987. $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
  988. $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
  989. $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
  990. $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
  991. $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
  992. $this->prepare( array( 'dir' => dirname( $fileA ) ) );
  993. $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
  994. $this->prepare( array( 'dir' => dirname( $fileB ) ) );
  995. $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
  996. $this->prepare( array( 'dir' => dirname( $fileC ) ) );
  997. $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
  998. $this->prepare( array( 'dir' => dirname( $fileD ) ) );
  999. $status = $this->backend->doOperations( array(
  1000. array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
  1001. // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
  1002. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1003. // Now: A:<A>, B:<B>, C:<A>, D:<empty>
  1004. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
  1005. // Now: A:<A>, B:<B>, C:<empty>, D:<A>
  1006. array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
  1007. // Now: A:<A>, B:<empty>, C:<B>, D:<A>
  1008. array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1009. // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
  1010. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
  1011. // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
  1012. array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
  1013. // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
  1014. array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1015. // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
  1016. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
  1017. // Does nothing
  1018. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1019. // Does nothing
  1020. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
  1021. // Does nothing
  1022. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1023. // Does nothing
  1024. array( 'op' => 'null' ),
  1025. // Does nothing
  1026. ) );
  1027. $this->assertGoodStatus( $status, "Operation batch succeeded" );
  1028. $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
  1029. $this->assertEquals( 13, count( $status->success ),
  1030. "Operation batch has correct success array" );
  1031. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
  1032. "File does not exist at $fileA" );
  1033. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
  1034. "File does not exist at $fileB" );
  1035. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
  1036. "File does not exist at $fileD" );
  1037. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
  1038. "File exists at $fileC" );
  1039. $this->assertEquals( $fileBContents,
  1040. $this->backend->getFileContents( array( 'src' => $fileC ) ),
  1041. "Correct file contents of $fileC" );
  1042. $this->assertEquals( strlen( $fileBContents ),
  1043. $this->backend->getFileSize( array( 'src' => $fileC ) ),
  1044. "Correct file size of $fileC" );
  1045. $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
  1046. $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
  1047. "Correct file SHA-1 of $fileC" );
  1048. }
  1049. public function testDoOperationsPipeline() {
  1050. $this->backend = $this->singleBackend;
  1051. $this->tearDownFiles();
  1052. $this->doTestDoOperationsPipeline();
  1053. $this->tearDownFiles();
  1054. $this->backend = $this->multiBackend;
  1055. $this->tearDownFiles();
  1056. $this->doTestDoOperationsPipeline();
  1057. $this->tearDownFiles();
  1058. }
  1059. // concurrency orientated
  1060. private function doTestDoOperationsPipeline() {
  1061. $base = $this->baseStorePath();
  1062. $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
  1063. $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
  1064. $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
  1065. $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
  1066. file_put_contents( $tmpNameA, $fileAContents );
  1067. $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
  1068. file_put_contents( $tmpNameB, $fileBContents );
  1069. $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
  1070. file_put_contents( $tmpNameC, $fileCContents );
  1071. $this->filesToPrune[] = $tmpNameA; # avoid file leaking
  1072. $this->filesToPrune[] = $tmpNameB; # avoid file leaking
  1073. $this->filesToPrune[] = $tmpNameC; # avoid file leaking
  1074. $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
  1075. $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
  1076. $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
  1077. $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
  1078. $this->prepare( array( 'dir' => dirname( $fileA ) ) );
  1079. $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
  1080. $this->prepare( array( 'dir' => dirname( $fileB ) ) );
  1081. $this->prepare( array( 'dir' => dirname( $fileC ) ) );
  1082. $this->prepare( array( 'dir' => dirname( $fileD ) ) );
  1083. $status = $this->backend->doOperations( array(
  1084. array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1085. array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
  1086. array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
  1087. array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
  1088. // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
  1089. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1090. // Now: A:<A>, B:<B>, C:<A>, D:<empty>
  1091. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
  1092. // Now: A:<A>, B:<B>, C:<empty>, D:<A>
  1093. array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
  1094. // Now: A:<A>, B:<empty>, C:<B>, D:<A>
  1095. array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1096. // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
  1097. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
  1098. // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
  1099. array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
  1100. // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
  1101. array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1102. // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
  1103. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
  1104. // Does nothing
  1105. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1106. // Does nothing
  1107. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
  1108. // Does nothing
  1109. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1110. // Does nothing
  1111. array( 'op' => 'null' ),
  1112. // Does nothing
  1113. ) );
  1114. $this->assertGoodStatus( $status, "Operation batch succeeded" );
  1115. $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
  1116. $this->assertEquals( 16, count( $status->success ),
  1117. "Operation batch has correct success array" );
  1118. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
  1119. "File does not exist at $fileA" );
  1120. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
  1121. "File does not exist at $fileB" );
  1122. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
  1123. "File does not exist at $fileD" );
  1124. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
  1125. "File exists at $fileC" );
  1126. $this->assertEquals( $fileBContents,
  1127. $this->backend->getFileContents( array( 'src' => $fileC ) ),
  1128. "Correct file contents of $fileC" );
  1129. $this->assertEquals( strlen( $fileBContents ),
  1130. $this->backend->getFileSize( array( 'src' => $fileC ) ),
  1131. "Correct file size of $fileC" );
  1132. $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
  1133. $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
  1134. "Correct file SHA-1 of $fileC" );
  1135. }
  1136. public function testDoOperationsFailing() {
  1137. $this->backend = $this->singleBackend;
  1138. $this->tearDownFiles();
  1139. $this->doTestDoOperationsFailing();
  1140. $this->tearDownFiles();
  1141. $this->backend = $this->multiBackend;
  1142. $this->tearDownFiles();
  1143. $this->doTestDoOperationsFailing();
  1144. $this->tearDownFiles();
  1145. }
  1146. private function doTestDoOperationsFailing() {
  1147. $base = $this->baseStorePath();
  1148. $fileA = "$base/unittest-cont2/a/b/fileA.txt";
  1149. $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
  1150. $fileB = "$base/unittest-cont2/a/b/fileB.txt";
  1151. $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
  1152. $fileC = "$base/unittest-cont2/a/b/fileC.txt";
  1153. $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
  1154. $fileD = "$base/unittest-cont2/a/b/fileD.txt";
  1155. $this->prepare( array( 'dir' => dirname( $fileA ) ) );
  1156. $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
  1157. $this->prepare( array( 'dir' => dirname( $fileB ) ) );
  1158. $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
  1159. $this->prepare( array( 'dir' => dirname( $fileC ) ) );
  1160. $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
  1161. $status = $this->backend->doOperations( array(
  1162. array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
  1163. // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
  1164. array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
  1165. // Now: A:<A>, B:<B>, C:<A>, D:<empty>
  1166. array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
  1167. // Now: A:<A>, B:<B>, C:<A>, D:<B>
  1168. array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
  1169. // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
  1170. array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
  1171. // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
  1172. array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
  1173. // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
  1174. array( 'op' => 'delete', 'src' => $fileD ),
  1175. // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
  1176. array( 'op' => 'null' ),
  1177. // Does nothing
  1178. ), array( 'force' => 1 ) );
  1179. $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
  1180. $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
  1181. $this->assertEquals( 8, count( $status->success ),
  1182. "Operation batch has correct success array" );
  1183. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
  1184. "File does not exist at $fileB" );
  1185. $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
  1186. "File does not exist at $fileD" );
  1187. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
  1188. "File does not exist at $fileA" );
  1189. $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
  1190. "File exists at $fileC" );
  1191. $this->assertEquals( $fileBContents,
  1192. $this->backend->getFileContents( array( 'src' => $fileA ) ),
  1193. "Correct file contents of $fileA" );
  1194. $this->assertEquals( strlen( $fileBContents ),
  1195. $this->backend->getFileSize( array( 'src' => $fileA ) ),
  1196. "Correct file size of $fileA" );
  1197. $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
  1198. $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
  1199. "Correct file SHA-1 of $fileA" );
  1200. }
  1201. public function testGetFileList() {
  1202. $this->backend = $this->singleBackend;
  1203. $this->tearDownFiles();
  1204. $this->doTestGetFileList();
  1205. $this->tearDownFiles();
  1206. $this->backend = $this->multiBackend;
  1207. $this->tearDownFiles();
  1208. $this->doTestGetFileList();
  1209. $this->tearDownFiles();
  1210. }
  1211. private function doTestGetFileList() {
  1212. $backendName = $this->backendClass();
  1213. $base = $this->baseStorePath();
  1214. // Should have no errors
  1215. $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
  1216. $files = array(
  1217. "$base/unittest-cont1/e/test1.txt",
  1218. "$base/unittest-cont1/e/test2.txt",
  1219. "$base/unittest-cont1/e/test3.txt",
  1220. "$base/unittest-cont1/e/subdir1/test1.txt",
  1221. "$base/unittest-cont1/e/su…

Large files files are truncated, but you can click here to view the full file