0d15b75bfb8342ff8a728f8c6aaa991fd64ad1af
8 class FileBackendTest
extends MediaWikiTestCase
{
10 /** @var FileBackend */
12 /** @var FileBackendMultiWrite */
13 private $multiBackend;
14 /** @var FSFileBackend */
15 public $singleBackend;
16 private static $backendToUse;
18 protected function setUp() {
19 global $wgFileBackends;
21 $uniqueId = time() . '-' . mt_rand();
22 $tmpDir = $this->getNewTempDirectory();
23 if ( $this->getCliArg( 'use-filebackend' ) ) {
24 if ( self
::$backendToUse ) {
25 $this->singleBackend
= self
::$backendToUse;
27 $name = $this->getCliArg( 'use-filebackend' );
29 foreach ( $wgFileBackends as $conf ) {
30 if ( $conf['name'] == $name ) {
35 $useConfig['name'] = 'localtesting'; // swap name
36 $useConfig['shardViaHashLevels'] = array( // test sharding
37 'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
39 if ( isset( $useConfig['fileJournal'] ) ) {
40 $useConfig['fileJournal'] = FileJournal
::factory( $useConfig['fileJournal'], $name );
42 $useConfig['lockManager'] = LockManagerGroup
::singleton()->get( $useConfig['lockManager'] );
43 $class = $useConfig['class'];
44 self
::$backendToUse = new $class( $useConfig );
45 $this->singleBackend
= self
::$backendToUse;
48 $this->singleBackend
= new FSFileBackend( array(
49 'name' => 'localtesting',
50 'lockManager' => LockManagerGroup
::singleton()->get( 'fsLockManager' ),
51 'wikiId' => wfWikiID(),
52 'containerPaths' => array(
53 'unittest-cont1' => "{$tmpDir}/localtesting-cont1",
54 'unittest-cont2' => "{$tmpDir}/localtesting-cont2" )
57 $this->multiBackend
= new FileBackendMultiWrite( array(
58 'name' => 'localtesting',
59 'lockManager' => LockManagerGroup
::singleton()->get( 'fsLockManager' ),
60 'parallelize' => 'implicit',
61 'wikiId' => wfWikiId() . $uniqueId,
64 'name' => 'localmultitesting1',
65 'class' => 'FSFileBackend',
66 'containerPaths' => array(
67 'unittest-cont1' => "{$tmpDir}/localtestingmulti1-cont1",
68 'unittest-cont2' => "{$tmpDir}/localtestingmulti1-cont2" ),
69 'isMultiMaster' => false
72 'name' => 'localmultitesting2',
73 'class' => 'FSFileBackend',
74 'containerPaths' => array(
75 'unittest-cont1' => "{$tmpDir}/localtestingmulti2-cont1",
76 'unittest-cont2' => "{$tmpDir}/localtestingmulti2-cont2" ),
77 'isMultiMaster' => true
83 protected function tearDown() {
85 DeferredUpdates
::forceDeferral( false );
88 private static function baseStorePath() {
89 return 'mwstore://localtesting';
92 private function backendClass() {
93 return get_class( $this->backend
);
97 * @dataProvider provider_testIsStoragePath
98 * @covers FileBackend::isStoragePath
100 public function testIsStoragePath( $path, $isStorePath ) {
101 $this->assertEquals( $isStorePath, FileBackend
::isStoragePath( $path ),
102 "FileBackend::isStoragePath on path '$path'" );
105 public static function provider_testIsStoragePath() {
107 array( 'mwstore://', true ),
108 array( 'mwstore://backend', true ),
109 array( 'mwstore://backend/container', true ),
110 array( 'mwstore://backend/container/', true ),
111 array( 'mwstore://backend/container/path', true ),
112 array( 'mwstore://backend//container/', true ),
113 array( 'mwstore://backend//container//', true ),
114 array( 'mwstore://backend//container//path', true ),
115 array( 'mwstore:///', true ),
116 array( 'mwstore:/', false ),
117 array( 'mwstore:', false ),
122 * @dataProvider provider_testSplitStoragePath
123 * @covers FileBackend::splitStoragePath
125 public function testSplitStoragePath( $path, $res ) {
126 $this->assertEquals( $res, FileBackend
::splitStoragePath( $path ),
127 "FileBackend::splitStoragePath on path '$path'" );
130 public static function provider_testSplitStoragePath() {
132 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
133 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
134 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
135 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
136 array( 'mwstore://backend//container/path', array( null, null, null ) ),
137 array( 'mwstore://backend//container//path', array( null, null, null ) ),
138 array( 'mwstore://', array( null, null, null ) ),
139 array( 'mwstore://backend', array( null, null, null ) ),
140 array( 'mwstore:///', array( null, null, null ) ),
141 array( 'mwstore:/', array( null, null, null ) ),
142 array( 'mwstore:', array( null, null, null ) )
147 * @dataProvider provider_normalizeStoragePath
148 * @covers FileBackend::normalizeStoragePath
150 public function testNormalizeStoragePath( $path, $res ) {
151 $this->assertEquals( $res, FileBackend
::normalizeStoragePath( $path ),
152 "FileBackend::normalizeStoragePath on path '$path'" );
155 public static function provider_normalizeStoragePath() {
157 array( 'mwstore://backend/container', 'mwstore://backend/container' ),
158 array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
159 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
160 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
161 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
163 'mwstore://backend/container///path//to///obj',
164 'mwstore://backend/container/path/to/obj'
166 array( 'mwstore://', null ),
167 array( 'mwstore://backend', null ),
168 array( 'mwstore://backend//container/path', null ),
169 array( 'mwstore://backend//container//path', null ),
170 array( 'mwstore:///', null ),
171 array( 'mwstore:/', null ),
172 array( 'mwstore:', null ),
177 * @dataProvider provider_testParentStoragePath
178 * @covers FileBackend::parentStoragePath
180 public function testParentStoragePath( $path, $res ) {
181 $this->assertEquals( $res, FileBackend
::parentStoragePath( $path ),
182 "FileBackend::parentStoragePath on path '$path'" );
185 public static function provider_testParentStoragePath() {
187 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
188 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
189 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
190 array( 'mwstore://backend/container', null ),
191 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
192 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
193 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
194 array( 'mwstore://backend/container/', null ),
199 * @dataProvider provider_testExtensionFromPath
200 * @covers FileBackend::extensionFromPath
202 public function testExtensionFromPath( $path, $res ) {
203 $this->assertEquals( $res, FileBackend
::extensionFromPath( $path ),
204 "FileBackend::extensionFromPath on path '$path'" );
207 public static function provider_testExtensionFromPath() {
209 array( 'mwstore://backend/container/path.txt', 'txt' ),
210 array( 'mwstore://backend/container/path.svg.png', 'png' ),
211 array( 'mwstore://backend/container/path', '' ),
212 array( 'mwstore://backend/container/path.', '' ),
217 * @dataProvider provider_testStore
219 public function testStore( $op ) {
220 $this->addTmpFiles( $op['src'] );
222 $this->backend
= $this->singleBackend
;
223 $this->tearDownFiles();
224 $this->doTestStore( $op );
225 $this->tearDownFiles();
227 $this->backend
= $this->multiBackend
;
228 $this->tearDownFiles();
229 $this->doTestStore( $op );
230 $this->tearDownFiles();
234 * @covers FileBackend::doOperation
236 private function doTestStore( $op ) {
237 $backendName = $this->backendClass();
239 $source = $op['src'];
241 $this->prepare( array( 'dir' => dirname( $dest ) ) );
243 file_put_contents( $source, "Unit test file" );
245 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
246 $this->backend
->store( $op );
249 $status = $this->backend
->doOperation( $op );
251 $this->assertGoodStatus( $status,
252 "Store from $source to $dest succeeded without warnings ($backendName)." );
253 $this->assertEquals( true, $status->isOK(),
254 "Store from $source to $dest succeeded ($backendName)." );
255 $this->assertEquals( array( 0 => true ), $status->success
,
256 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
257 $this->assertEquals( true, file_exists( $source ),
258 "Source file $source still exists ($backendName)." );
259 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
260 "Destination file $dest exists ($backendName)." );
262 $this->assertEquals( filesize( $source ),
263 $this->backend
->getFileSize( array( 'src' => $dest ) ),
264 "Destination file $dest has correct size ($backendName)." );
266 $props1 = FSFile
::getPropsFromPath( $source );
267 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
268 $this->assertEquals( $props1, $props2,
269 "Source and destination have the same props ($backendName)." );
271 $this->assertBackendPathsConsistent( array( $dest ) );
274 public static function provider_testStore() {
277 $tmpName = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
278 $toPath = self
::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
279 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
280 $cases[] = array( $op );
283 $op2['overwrite'] = true;
284 $cases[] = array( $op2 );
287 $op3['overwriteSame'] = true;
288 $cases[] = array( $op3 );
294 * @dataProvider provider_testCopy
295 * @covers FileBackend::doOperation
297 public function testCopy( $op ) {
298 $this->backend
= $this->singleBackend
;
299 $this->tearDownFiles();
300 $this->doTestCopy( $op );
301 $this->tearDownFiles();
303 $this->backend
= $this->multiBackend
;
304 $this->tearDownFiles();
305 $this->doTestCopy( $op );
306 $this->tearDownFiles();
309 private function doTestCopy( $op ) {
310 $backendName = $this->backendClass();
312 $source = $op['src'];
314 $this->prepare( array( 'dir' => dirname( $source ) ) );
315 $this->prepare( array( 'dir' => dirname( $dest ) ) );
317 if ( isset( $op['ignoreMissingSource'] ) ) {
318 $status = $this->backend
->doOperation( $op );
319 $this->assertGoodStatus( $status,
320 "Move from $source to $dest succeeded without warnings ($backendName)." );
321 $this->assertEquals( array( 0 => true ), $status->success
,
322 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
323 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
324 "Source file $source does not exist ($backendName)." );
325 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $dest ) ),
326 "Destination file $dest does not exist ($backendName)." );
331 $status = $this->backend
->doOperation(
332 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
333 $this->assertGoodStatus( $status,
334 "Creation of file at $source succeeded ($backendName)." );
336 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
337 $this->backend
->copy( $op );
340 $status = $this->backend
->doOperation( $op );
342 $this->assertGoodStatus( $status,
343 "Copy from $source to $dest succeeded without warnings ($backendName)." );
344 $this->assertEquals( true, $status->isOK(),
345 "Copy from $source to $dest succeeded ($backendName)." );
346 $this->assertEquals( array( 0 => true ), $status->success
,
347 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
348 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $source ) ),
349 "Source file $source still exists ($backendName)." );
350 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
351 "Destination file $dest exists after copy ($backendName)." );
354 $this->backend
->getFileSize( array( 'src' => $source ) ),
355 $this->backend
->getFileSize( array( 'src' => $dest ) ),
356 "Destination file $dest has correct size ($backendName)." );
358 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
359 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
360 $this->assertEquals( $props1, $props2,
361 "Source and destination have the same props ($backendName)." );
363 $this->assertBackendPathsConsistent( array( $source, $dest ) );
366 public static function provider_testCopy() {
369 $source = self
::baseStorePath() . '/unittest-cont1/e/file.txt';
370 $dest = self
::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
372 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
380 $op2['overwrite'] = true;
388 $op2['overwriteSame'] = true;
396 $op2['ignoreMissingSource'] = true;
404 $op2['ignoreMissingSource'] = true;
407 self
::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
415 * @dataProvider provider_testMove
416 * @covers FileBackend::doOperation
418 public function testMove( $op ) {
419 $this->backend
= $this->singleBackend
;
420 $this->tearDownFiles();
421 $this->doTestMove( $op );
422 $this->tearDownFiles();
424 $this->backend
= $this->multiBackend
;
425 $this->tearDownFiles();
426 $this->doTestMove( $op );
427 $this->tearDownFiles();
430 private function doTestMove( $op ) {
431 $backendName = $this->backendClass();
433 $source = $op['src'];
435 $this->prepare( array( 'dir' => dirname( $source ) ) );
436 $this->prepare( array( 'dir' => dirname( $dest ) ) );
438 if ( isset( $op['ignoreMissingSource'] ) ) {
439 $status = $this->backend
->doOperation( $op );
440 $this->assertGoodStatus( $status,
441 "Move from $source to $dest succeeded without warnings ($backendName)." );
442 $this->assertEquals( array( 0 => true ), $status->success
,
443 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
444 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
445 "Source file $source does not exist ($backendName)." );
446 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $dest ) ),
447 "Destination file $dest does not exist ($backendName)." );
452 $status = $this->backend
->doOperation(
453 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
454 $this->assertGoodStatus( $status,
455 "Creation of file at $source succeeded ($backendName)." );
457 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
458 $this->backend
->copy( $op );
461 $status = $this->backend
->doOperation( $op );
462 $this->assertGoodStatus( $status,
463 "Move from $source to $dest succeeded without warnings ($backendName)." );
464 $this->assertEquals( true, $status->isOK(),
465 "Move from $source to $dest succeeded ($backendName)." );
466 $this->assertEquals( array( 0 => true ), $status->success
,
467 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
468 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
469 "Source file $source does not still exists ($backendName)." );
470 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
471 "Destination file $dest exists after move ($backendName)." );
473 $this->assertNotEquals(
474 $this->backend
->getFileSize( array( 'src' => $source ) ),
475 $this->backend
->getFileSize( array( 'src' => $dest ) ),
476 "Destination file $dest has correct size ($backendName)." );
478 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
479 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
480 $this->assertEquals( false, $props1['fileExists'],
481 "Source file does not exist accourding to props ($backendName)." );
482 $this->assertEquals( true, $props2['fileExists'],
483 "Destination file exists accourding to props ($backendName)." );
485 $this->assertBackendPathsConsistent( array( $source, $dest ) );
488 public static function provider_testMove() {
491 $source = self
::baseStorePath() . '/unittest-cont1/e/file.txt';
492 $dest = self
::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
494 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
502 $op2['overwrite'] = true;
510 $op2['overwriteSame'] = true;
518 $op2['ignoreMissingSource'] = true;
526 $op2['ignoreMissingSource'] = true;
529 self
::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
537 * @dataProvider provider_testDelete
538 * @covers FileBackend::doOperation
540 public function testDelete( $op, $withSource, $okStatus ) {
541 $this->backend
= $this->singleBackend
;
542 $this->tearDownFiles();
543 $this->doTestDelete( $op, $withSource, $okStatus );
544 $this->tearDownFiles();
546 $this->backend
= $this->multiBackend
;
547 $this->tearDownFiles();
548 $this->doTestDelete( $op, $withSource, $okStatus );
549 $this->tearDownFiles();
552 private function doTestDelete( $op, $withSource, $okStatus ) {
553 $backendName = $this->backendClass();
555 $source = $op['src'];
556 $this->prepare( array( 'dir' => dirname( $source ) ) );
559 $status = $this->backend
->doOperation(
560 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
561 $this->assertGoodStatus( $status,
562 "Creation of file at $source succeeded ($backendName)." );
565 $status = $this->backend
->doOperation( $op );
567 $this->assertGoodStatus( $status,
568 "Deletion of file at $source succeeded without warnings ($backendName)." );
569 $this->assertEquals( true, $status->isOK(),
570 "Deletion of file at $source succeeded ($backendName)." );
571 $this->assertEquals( array( 0 => true ), $status->success
,
572 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
574 $this->assertEquals( false, $status->isOK(),
575 "Deletion of file at $source failed ($backendName)." );
578 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
579 "Source file $source does not exist after move ($backendName)." );
582 $this->backend
->getFileSize( array( 'src' => $source ) ),
583 "Source file $source has correct size (false) ($backendName)." );
585 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
586 $this->assertFalse( $props1['fileExists'],
587 "Source file $source does not exist according to props ($backendName)." );
589 $this->assertBackendPathsConsistent( array( $source ) );
592 public static function provider_testDelete() {
595 $source = self
::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
597 $op = array( 'op' => 'delete', 'src' => $source );
606 false, // without source
610 $op['ignoreMissingSource'] = true;
613 false, // without source
617 $op['ignoreMissingSource'] = true;
618 $op['src'] = self
::baseStorePath() . '/unittest-cont-bad/e/file.txt';
621 false, // without source
629 * @dataProvider provider_testDescribe
630 * @covers FileBackend::doOperation
632 public function testDescribe( $op, $withSource, $okStatus ) {
633 $this->backend
= $this->singleBackend
;
634 $this->tearDownFiles();
635 $this->doTestDescribe( $op, $withSource, $okStatus );
636 $this->tearDownFiles();
638 $this->backend
= $this->multiBackend
;
639 $this->tearDownFiles();
640 $this->doTestDescribe( $op, $withSource, $okStatus );
641 $this->tearDownFiles();
644 private function doTestDescribe( $op, $withSource, $okStatus ) {
645 $backendName = $this->backendClass();
647 $source = $op['src'];
648 $this->prepare( array( 'dir' => dirname( $source ) ) );
651 $status = $this->backend
->doOperation(
652 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source,
653 'headers' => array( 'Content-Disposition' => 'xxx' ) ) );
654 $this->assertGoodStatus( $status,
655 "Creation of file at $source succeeded ($backendName)." );
656 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
657 $attr = $this->backend
->getFileXAttributes( array( 'src' => $source ) );
658 $this->assertHasHeaders( array( 'Content-Disposition' => 'xxx' ), $attr );
661 $status = $this->backend
->describe( array( 'src' => $source,
662 'headers' => array( 'Content-Disposition' => '' ) ) ); // remove
663 $this->assertGoodStatus( $status,
664 "Removal of header for $source succeeded ($backendName)." );
666 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
667 $attr = $this->backend
->getFileXAttributes( array( 'src' => $source ) );
668 $this->assertFalse( isset( $attr['headers']['content-disposition'] ),
669 "File 'Content-Disposition' header removed." );
673 $status = $this->backend
->doOperation( $op );
675 $this->assertGoodStatus( $status,
676 "Describe of file at $source succeeded without warnings ($backendName)." );
677 $this->assertEquals( true, $status->isOK(),
678 "Describe of file at $source succeeded ($backendName)." );
679 $this->assertEquals( array( 0 => true ), $status->success
,
680 "Describe of file at $source has proper 'success' field in Status ($backendName)." );
681 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
682 $attr = $this->backend
->getFileXAttributes( array( 'src' => $source ) );
683 $this->assertHasHeaders( $op['headers'], $attr );
686 $this->assertEquals( false, $status->isOK(),
687 "Describe of file at $source failed ($backendName)." );
690 $this->assertBackendPathsConsistent( array( $source ) );
693 private function assertHasHeaders( array $headers, array $attr ) {
694 foreach ( $headers as $n => $v ) {
696 $this->assertTrue( isset( $attr['headers'][strtolower( $n )] ),
697 "File has '$n' header." );
698 $this->assertEquals( $v, $attr['headers'][strtolower( $n )],
699 "File has '$n' header value." );
701 $this->assertFalse( isset( $attr['headers'][strtolower( $n )] ),
702 "File does not have '$n' header." );
707 public static function provider_testDescribe() {
710 $source = self
::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
712 $op = array( 'op' => 'describe', 'src' => $source,
713 'headers' => array( 'Content-Disposition' => 'inline' ), );
722 false, // without source
730 * @dataProvider provider_testCreate
731 * @covers FileBackend::doOperation
733 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
734 $this->backend
= $this->singleBackend
;
735 $this->tearDownFiles();
736 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
737 $this->tearDownFiles();
739 $this->backend
= $this->multiBackend
;
740 $this->tearDownFiles();
741 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
742 $this->tearDownFiles();
745 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
746 $backendName = $this->backendClass();
749 $this->prepare( array( 'dir' => dirname( $dest ) ) );
751 $oldText = 'blah...blah...waahwaah';
752 if ( $alreadyExists ) {
753 $status = $this->backend
->doOperation(
754 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
755 $this->assertGoodStatus( $status,
756 "Creation of file at $dest succeeded ($backendName)." );
759 $status = $this->backend
->doOperation( $op );
761 $this->assertGoodStatus( $status,
762 "Creation of file at $dest succeeded without warnings ($backendName)." );
763 $this->assertEquals( true, $status->isOK(),
764 "Creation of file at $dest succeeded ($backendName)." );
765 $this->assertEquals( array( 0 => true ), $status->success
,
766 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
768 $this->assertEquals( false, $status->isOK(),
769 "Creation of file at $dest failed ($backendName)." );
772 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
773 "Destination file $dest exists after creation ($backendName)." );
775 $props1 = $this->backend
->getFileProps( array( 'src' => $dest ) );
776 $this->assertEquals( true, $props1['fileExists'],
777 "Destination file $dest exists according to props ($backendName)." );
778 if ( $okStatus ) { // file content is what we saved
779 $this->assertEquals( $newSize, $props1['size'],
780 "Destination file $dest has expected size according to props ($backendName)." );
781 $this->assertEquals( $newSize,
782 $this->backend
->getFileSize( array( 'src' => $dest ) ),
783 "Destination file $dest has correct size ($backendName)." );
784 } else { // file content is some other previous text
785 $this->assertEquals( strlen( $oldText ), $props1['size'],
786 "Destination file $dest has original size according to props ($backendName)." );
787 $this->assertEquals( strlen( $oldText ),
788 $this->backend
->getFileSize( array( 'src' => $dest ) ),
789 "Destination file $dest has original size according to props ($backendName)." );
792 $this->assertBackendPathsConsistent( array( $dest ) );
796 * @dataProvider provider_testCreate
798 public static function provider_testCreate() {
801 $dest = self
::baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
803 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
806 false, // no dest already exists
808 strlen( $op['content'] )
812 $op2['content'] = "\n";
815 false, // no dest already exists
817 strlen( $op2['content'] )
821 $op2['content'] = "fsf\n waf 3kt";
824 true, // dest already exists
826 strlen( $op2['content'] )
830 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
831 $op2['overwrite'] = true;
834 true, // dest already exists
836 strlen( $op2['content'] )
840 $op2['content'] = "39qjmg3-qg";
841 $op2['overwriteSame'] = true;
844 true, // dest already exists
846 strlen( $op2['content'] )
853 * @covers FileBackend::doQuickOperations
855 public function testDoQuickOperations() {
856 $this->backend
= $this->singleBackend
;
857 $this->doTestDoQuickOperations();
858 $this->tearDownFiles();
860 $this->backend
= $this->multiBackend
;
861 $this->doTestDoQuickOperations();
862 $this->tearDownFiles();
865 private function doTestDoQuickOperations() {
866 $backendName = $this->backendClass();
868 $base = self
::baseStorePath();
870 "$base/unittest-cont1/e/fileA.a",
871 "$base/unittest-cont1/e/fileB.a",
872 "$base/unittest-cont1/e/fileC.a"
874 $createOps = array();
876 foreach ( $files as $path ) {
877 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
878 $this->assertGoodStatus( $status,
879 "Preparing $path succeeded without warnings ($backendName)." );
880 $createOps[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand( 0, 50000 ) );
881 $copyOps[] = array( 'op' => 'copy', 'src' => $path, 'dst' => "$path-2" );
882 $moveOps[] = array( 'op' => 'move', 'src' => "$path-2", 'dst' => "$path-3" );
883 $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
884 $purgeOps[] = array( 'op' => 'delete', 'src' => "$path-3" );
886 $purgeOps[] = array( 'op' => 'null' );
888 $this->assertGoodStatus(
889 $this->backend
->doQuickOperations( $createOps ),
890 "Creation of source files succeeded ($backendName)." );
891 foreach ( $files as $file ) {
892 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $file ) ),
893 "File $file exists." );
896 $this->assertGoodStatus(
897 $this->backend
->doQuickOperations( $copyOps ),
898 "Quick copy of source files succeeded ($backendName)." );
899 foreach ( $files as $file ) {
900 $this->assertTrue( $this->backend
->fileExists( array( 'src' => "$file-2" ) ),
901 "File $file-2 exists." );
904 $this->assertGoodStatus(
905 $this->backend
->doQuickOperations( $moveOps ),
906 "Quick move of source files succeeded ($backendName)." );
907 foreach ( $files as $file ) {
908 $this->assertTrue( $this->backend
->fileExists( array( 'src' => "$file-3" ) ),
909 "File $file-3 move in." );
910 $this->assertFalse( $this->backend
->fileExists( array( 'src' => "$file-2" ) ),
911 "File $file-2 moved away." );
914 $this->assertGoodStatus(
915 $this->backend
->quickCopy( array( 'src' => $files[0], 'dst' => $files[0] ) ),
916 "Copy of file {$files[0]} over itself succeeded ($backendName)." );
917 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $files[0] ) ),
918 "File {$files[0]} still exists." );
920 $this->assertGoodStatus(
921 $this->backend
->quickMove( array( 'src' => $files[0], 'dst' => $files[0] ) ),
922 "Move of file {$files[0]} over itself succeeded ($backendName)." );
923 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $files[0] ) ),
924 "File {$files[0]} still exists." );
926 $this->assertGoodStatus(
927 $this->backend
->doQuickOperations( $purgeOps ),
928 "Quick deletion of source files succeeded ($backendName)." );
929 foreach ( $files as $file ) {
930 $this->assertFalse( $this->backend
->fileExists( array( 'src' => $file ) ),
931 "File $file purged." );
932 $this->assertFalse( $this->backend
->fileExists( array( 'src' => "$file-3" ) ),
933 "File $file-3 purged." );
938 * @dataProvider provider_testConcatenate
940 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
941 $this->backend
= $this->singleBackend
;
942 $this->tearDownFiles();
943 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
944 $this->tearDownFiles();
946 $this->backend
= $this->multiBackend
;
947 $this->tearDownFiles();
948 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
949 $this->tearDownFiles();
952 private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
953 $backendName = $this->backendClass();
958 foreach ( $srcs as $i => $source ) {
959 $this->prepare( array( 'dir' => dirname( $source ) ) );
961 'op' => 'create', // operation
962 'dst' => $source, // source
963 'content' => $srcsContent[$i]
965 $expContent .= $srcsContent[$i];
967 $status = $this->backend
->doOperations( $ops );
969 $this->assertGoodStatus( $status,
970 "Creation of source files succeeded ($backendName)." );
972 $dest = $params['dst'] = $this->getNewTempFile();
973 if ( $alreadyExists ) {
974 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
975 $this->assertEquals( true, $ok,
976 "Creation of file at $dest succeeded ($backendName)." );
978 $ok = file_put_contents( $dest, '' ) !== false;
979 $this->assertEquals( true, $ok,
980 "Creation of 0-byte file at $dest succeeded ($backendName)." );
983 // Combine the files into one
984 $status = $this->backend
->concatenate( $params );
986 $this->assertGoodStatus( $status,
987 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
988 $this->assertEquals( true, $status->isOK(),
989 "Creation of concat file at $dest succeeded ($backendName)." );
991 $this->assertEquals( false, $status->isOK(),
992 "Creation of concat file at $dest failed ($backendName)." );
996 $this->assertEquals( true, is_file( $dest ),
997 "Dest concat file $dest exists after creation ($backendName)." );
999 $this->assertEquals( true, is_file( $dest ),
1000 "Dest concat file $dest exists after failed creation ($backendName)." );
1003 $contents = file_get_contents( $dest );
1004 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
1007 $this->assertEquals( $expContent, $contents,
1008 "Concat file at $dest has correct contents ($backendName)." );
1010 $this->assertNotEquals( $expContent, $contents,
1011 "Concat file at $dest has correct contents ($backendName)." );
1015 public static function provider_testConcatenate() {
1019 self
::baseStorePath() . '/unittest-cont1/e/file1.txt',
1020 self
::baseStorePath() . '/unittest-cont1/e/file2.txt',
1021 self
::baseStorePath() . '/unittest-cont1/e/file3.txt',
1022 self
::baseStorePath() . '/unittest-cont1/e/file4.txt',
1023 self
::baseStorePath() . '/unittest-cont1/e/file5.txt',
1024 self
::baseStorePath() . '/unittest-cont1/e/file6.txt',
1025 self
::baseStorePath() . '/unittest-cont1/e/file7.txt',
1026 self
::baseStorePath() . '/unittest-cont1/e/file8.txt',
1027 self
::baseStorePath() . '/unittest-cont1/e/file9.txt',
1028 self
::baseStorePath() . '/unittest-cont1/e/file10.txt'
1042 $params = array( 'srcs' => $srcs );
1045 $params, // operation
1047 $content, // content for each source
1048 false, // no dest already exists
1053 $params, // operation
1055 $content, // content for each source
1056 true, // dest already exists
1064 * @dataProvider provider_testGetFileStat
1065 * @covers FileBackend::getFileStat
1067 public function testGetFileStat( $path, $content, $alreadyExists ) {
1068 $this->backend
= $this->singleBackend
;
1069 $this->tearDownFiles();
1070 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1071 $this->tearDownFiles();
1073 $this->backend
= $this->multiBackend
;
1074 $this->tearDownFiles();
1075 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1076 $this->tearDownFiles();
1079 private function doTestGetFileStat( $path, $content, $alreadyExists ) {
1080 $backendName = $this->backendClass();
1082 if ( $alreadyExists ) {
1083 $this->prepare( array( 'dir' => dirname( $path ) ) );
1084 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1085 $this->assertGoodStatus( $status,
1086 "Creation of file at $path succeeded ($backendName)." );
1088 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1089 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
1090 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
1092 $this->assertEquals( strlen( $content ), $size,
1093 "Correct file size of '$path'" );
1094 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
1095 "Correct file timestamp of '$path'" );
1097 $size = $stat['size'];
1098 $time = $stat['mtime'];
1099 $this->assertEquals( strlen( $content ), $size,
1100 "Correct file size of '$path'" );
1101 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
1102 "Correct file timestamp of '$path'" );
1104 $this->backend
->clearCache( array( $path ) );
1106 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1108 $this->assertEquals( strlen( $content ), $size,
1109 "Correct file size of '$path'" );
1111 $this->backend
->preloadCache( array( $path ) );
1113 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1115 $this->assertEquals( strlen( $content ), $size,
1116 "Correct file size of '$path'" );
1118 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1119 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
1120 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
1122 $this->assertFalse( $size, "Correct file size of '$path'" );
1123 $this->assertFalse( $time, "Correct file timestamp of '$path'" );
1124 $this->assertFalse( $stat, "Correct file stat of '$path'" );
1128 public static function provider_testGetFileStat() {
1131 $base = self
::baseStorePath();
1132 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
1133 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
1134 $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
1140 * @dataProvider provider_testGetFileStat
1141 * @covers FileBackend::streamFile
1143 public function testStreamFile( $path, $content, $alreadyExists ) {
1144 $this->backend
= $this->singleBackend
;
1145 $this->tearDownFiles();
1146 $this->doTestStreamFile( $path, $content, $alreadyExists );
1147 $this->tearDownFiles();
1150 private function doTestStreamFile( $path, $content ) {
1151 $backendName = $this->backendClass();
1153 // Test doStreamFile() directly to avoid header madness
1154 $class = new ReflectionClass( $this->backend
);
1155 $method = $class->getMethod( 'doStreamFile' );
1156 $method->setAccessible( true );
1158 if ( $content !== null ) {
1159 $this->prepare( array( 'dir' => dirname( $path ) ) );
1160 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1161 $this->assertGoodStatus( $status,
1162 "Creation of file at $path succeeded ($backendName)." );
1165 $method->invokeArgs( $this->backend
, array( array( 'src' => $path ) ) );
1166 $data = ob_get_contents();
1169 $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
1170 } else { // 404 case
1172 $method->invokeArgs( $this->backend
, array( array( 'src' => $path ) ) );
1173 $data = ob_get_contents();
1176 $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
1180 public static function provider_testStreamFile() {
1183 $base = self
::baseStorePath();
1184 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
1185 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
1191 * @dataProvider provider_testGetFileContents
1192 * @covers FileBackend::getFileContents
1193 * @covers FileBackend::getFileContentsMulti
1195 public function testGetFileContents( $source, $content ) {
1196 $this->backend
= $this->singleBackend
;
1197 $this->tearDownFiles();
1198 $this->doTestGetFileContents( $source, $content );
1199 $this->tearDownFiles();
1201 $this->backend
= $this->multiBackend
;
1202 $this->tearDownFiles();
1203 $this->doTestGetFileContents( $source, $content );
1204 $this->tearDownFiles();
1207 private function doTestGetFileContents( $source, $content ) {
1208 $backendName = $this->backendClass();
1210 $srcs = (array)$source;
1211 $content = (array)$content;
1212 foreach ( $srcs as $i => $src ) {
1213 $this->prepare( array( 'dir' => dirname( $src ) ) );
1214 $status = $this->backend
->doOperation(
1215 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1216 $this->assertGoodStatus( $status,
1217 "Creation of file at $src succeeded ($backendName)." );
1220 if ( is_array( $source ) ) {
1221 $contents = $this->backend
->getFileContentsMulti( array( 'srcs' => $source ) );
1222 foreach ( $contents as $path => $data ) {
1223 $this->assertNotEquals( false, $data, "Contents of $path exists ($backendName)." );
1224 $this->assertEquals(
1225 current( $content ),
1227 "Contents of $path is correct ($backendName)."
1231 $this->assertEquals(
1233 array_keys( $contents ),
1234 "Contents in right order ($backendName)."
1236 $this->assertEquals(
1239 "Contents array size correct ($backendName)."
1242 $data = $this->backend
->getFileContents( array( 'src' => $source ) );
1243 $this->assertNotEquals( false, $data, "Contents of $source exists ($backendName)." );
1244 $this->assertEquals( $content[0], $data, "Contents of $source is correct ($backendName)." );
1248 public static function provider_testGetFileContents() {
1251 $base = self
::baseStorePath();
1252 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
1253 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
1255 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1256 "$base/unittest-cont1/e/a/z.txt" ),
1257 array( "contents xx", "contents xy", "contents xz" )
1264 * @dataProvider provider_testGetLocalCopy
1265 * @covers FileBackend::getLocalCopy
1267 public function testGetLocalCopy( $source, $content ) {
1268 $this->backend
= $this->singleBackend
;
1269 $this->tearDownFiles();
1270 $this->doTestGetLocalCopy( $source, $content );
1271 $this->tearDownFiles();
1273 $this->backend
= $this->multiBackend
;
1274 $this->tearDownFiles();
1275 $this->doTestGetLocalCopy( $source, $content );
1276 $this->tearDownFiles();
1279 private function doTestGetLocalCopy( $source, $content ) {
1280 $backendName = $this->backendClass();
1282 $srcs = (array)$source;
1283 $content = (array)$content;
1284 foreach ( $srcs as $i => $src ) {
1285 $this->prepare( array( 'dir' => dirname( $src ) ) );
1286 $status = $this->backend
->doOperation(
1287 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1288 $this->assertGoodStatus( $status,
1289 "Creation of file at $src succeeded ($backendName)." );
1292 if ( is_array( $source ) ) {
1293 $tmpFiles = $this->backend
->getLocalCopyMulti( array( 'srcs' => $source ) );
1294 foreach ( $tmpFiles as $path => $tmpFile ) {
1295 $this->assertNotNull( $tmpFile,
1296 "Creation of local copy of $path succeeded ($backendName)." );
1297 $contents = file_get_contents( $tmpFile->getPath() );
1298 $this->assertNotEquals( false, $contents, "Local copy of $path exists ($backendName)." );
1299 $this->assertEquals(
1300 current( $content ),
1302 "Local copy of $path is correct ($backendName)."
1306 $this->assertEquals(
1308 array_keys( $tmpFiles ),
1309 "Local copies in right order ($backendName)."
1311 $this->assertEquals(
1314 "Local copies array size correct ($backendName)."
1317 $tmpFile = $this->backend
->getLocalCopy( array( 'src' => $source ) );
1318 $this->assertNotNull( $tmpFile,
1319 "Creation of local copy of $source succeeded ($backendName)." );
1320 $contents = file_get_contents( $tmpFile->getPath() );
1321 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
1322 $this->assertEquals(
1325 "Local copy of $source is correct ($backendName)."
1329 $obj = new stdClass();
1330 $tmpFile->bind( $obj );
1333 public static function provider_testGetLocalCopy() {
1336 $base = self
::baseStorePath();
1337 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1338 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1339 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1341 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1342 "$base/unittest-cont1/e/a/z.txt" ),
1343 array( "contents xx $", "contents xy 111", "contents xz" )
1350 * @dataProvider provider_testGetLocalReference
1351 * @covers FileBackend::getLocalReference
1353 public function testGetLocalReference( $source, $content ) {
1354 $this->backend
= $this->singleBackend
;
1355 $this->tearDownFiles();
1356 $this->doTestGetLocalReference( $source, $content );
1357 $this->tearDownFiles();
1359 $this->backend
= $this->multiBackend
;
1360 $this->tearDownFiles();
1361 $this->doTestGetLocalReference( $source, $content );
1362 $this->tearDownFiles();
1365 private function doTestGetLocalReference( $source, $content ) {
1366 $backendName = $this->backendClass();
1368 $srcs = (array)$source;
1369 $content = (array)$content;
1370 foreach ( $srcs as $i => $src ) {
1371 $this->prepare( array( 'dir' => dirname( $src ) ) );
1372 $status = $this->backend
->doOperation(
1373 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1374 $this->assertGoodStatus( $status,
1375 "Creation of file at $src succeeded ($backendName)." );
1378 if ( is_array( $source ) ) {
1379 $tmpFiles = $this->backend
->getLocalReferenceMulti( array( 'srcs' => $source ) );
1380 foreach ( $tmpFiles as $path => $tmpFile ) {
1381 $this->assertNotNull( $tmpFile,
1382 "Creation of local copy of $path succeeded ($backendName)." );
1383 $contents = file_get_contents( $tmpFile->getPath() );
1384 $this->assertNotEquals( false, $contents, "Local ref of $path exists ($backendName)." );
1385 $this->assertEquals(
1386 current( $content ),
1388 "Local ref of $path is correct ($backendName)."
1392 $this->assertEquals(
1394 array_keys( $tmpFiles ),
1395 "Local refs in right order ($backendName)."
1397 $this->assertEquals(
1400 "Local refs array size correct ($backendName)."
1403 $tmpFile = $this->backend
->getLocalReference( array( 'src' => $source ) );
1404 $this->assertNotNull( $tmpFile,
1405 "Creation of local copy of $source succeeded ($backendName)." );
1406 $contents = file_get_contents( $tmpFile->getPath() );
1407 $this->assertNotEquals( false, $contents, "Local ref of $source exists ($backendName)." );
1408 $this->assertEquals( $content[0], $contents, "Local ref of $source is correct ($backendName)." );
1412 public static function provider_testGetLocalReference() {
1415 $base = self
::baseStorePath();
1416 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1417 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1418 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1420 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1421 "$base/unittest-cont1/e/a/z.txt" ),
1422 array( "contents xx 1111", "contents xy %", "contents xz $" )
1429 * @covers FileBackend::getLocalCopy
1430 * @covers FileBackend::getLocalReference
1432 public function testGetLocalCopyAndReference404() {
1433 $this->backend
= $this->singleBackend
;
1434 $this->tearDownFiles();
1435 $this->doTestGetLocalCopyAndReference404();
1436 $this->tearDownFiles();
1438 $this->backend
= $this->multiBackend
;
1439 $this->tearDownFiles();
1440 $this->doTestGetLocalCopyAndReference404();
1441 $this->tearDownFiles();
1444 public function doTestGetLocalCopyAndReference404() {
1445 $backendName = $this->backendClass();
1447 $base = self
::baseStorePath();
1449 $tmpFile = $this->backend
->getLocalCopy( array(
1450 'src' => "$base/unittest-cont1/not-there" ) );
1451 $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
1453 $tmpFile = $this->backend
->getLocalReference( array(
1454 'src' => "$base/unittest-cont1/not-there" ) );
1455 $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
1459 * @dataProvider provider_testGetFileHttpUrl
1460 * @covers FileBackend::getFileHttpUrl
1462 public function testGetFileHttpUrl( $source, $content ) {
1463 $this->backend
= $this->singleBackend
;
1464 $this->tearDownFiles();
1465 $this->doTestGetFileHttpUrl( $source, $content );
1466 $this->tearDownFiles();
1468 $this->backend
= $this->multiBackend
;
1469 $this->tearDownFiles();
1470 $this->doTestGetFileHttpUrl( $source, $content );
1471 $this->tearDownFiles();
1474 private function doTestGetFileHttpUrl( $source, $content ) {
1475 $backendName = $this->backendClass();
1477 $this->prepare( array( 'dir' => dirname( $source ) ) );
1478 $status = $this->backend
->doOperation(
1479 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
1480 $this->assertGoodStatus( $status,
1481 "Creation of file at $source succeeded ($backendName)." );
1483 $url = $this->backend
->getFileHttpUrl( array( 'src' => $source ) );
1485 if ( $url !== null ) { // supported
1486 $data = Http
::request( "GET", $url, array(), __METHOD__
);
1487 $this->assertEquals( $content, $data,
1488 "HTTP GET of URL has right contents ($backendName)." );
1492 public static function provider_testGetFileHttpUrl() {
1495 $base = self
::baseStorePath();
1496 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1497 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1498 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1504 * @dataProvider provider_testPrepareAndClean
1505 * @covers FileBackend::prepare
1506 * @covers FileBackend::clean
1508 public function testPrepareAndClean( $path, $isOK ) {
1509 $this->backend
= $this->singleBackend
;
1510 $this->doTestPrepareAndClean( $path, $isOK );
1511 $this->tearDownFiles();
1513 $this->backend
= $this->multiBackend
;
1514 $this->doTestPrepareAndClean( $path, $isOK );
1515 $this->tearDownFiles();
1518 public static function provider_testPrepareAndClean() {
1519 $base = self
::baseStorePath();
1522 array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
1523 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
1524 # Specific to FS backend with no basePath field set
1525 # array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
1529 private function doTestPrepareAndClean( $path, $isOK ) {
1530 $backendName = $this->backendClass();
1532 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
1534 $this->assertGoodStatus( $status,
1535 "Preparing dir $path succeeded without warnings ($backendName)." );
1536 $this->assertEquals( true, $status->isOK(),
1537 "Preparing dir $path succeeded ($backendName)." );
1539 $this->assertEquals( false, $status->isOK(),
1540 "Preparing dir $path failed ($backendName)." );
1543 $status = $this->backend
->secure( array( 'dir' => dirname( $path ) ) );
1545 $this->assertGoodStatus( $status,
1546 "Securing dir $path succeeded without warnings ($backendName)." );
1547 $this->assertEquals( true, $status->isOK(),
1548 "Securing dir $path succeeded ($backendName)." );
1550 $this->assertEquals( false, $status->isOK(),
1551 "Securing dir $path failed ($backendName)." );
1554 $status = $this->backend
->publish( array( 'dir' => dirname( $path ) ) );
1556 $this->assertGoodStatus( $status,
1557 "Publishing dir $path succeeded without warnings ($backendName)." );
1558 $this->assertEquals( true, $status->isOK(),
1559 "Publishing dir $path succeeded ($backendName)." );
1561 $this->assertEquals( false, $status->isOK(),
1562 "Publishing dir $path failed ($backendName)." );
1565 $status = $this->backend
->clean( array( 'dir' => dirname( $path ) ) );
1567 $this->assertGoodStatus( $status,
1568 "Cleaning dir $path succeeded without warnings ($backendName)." );
1569 $this->assertEquals( true, $status->isOK(),
1570 "Cleaning dir $path succeeded ($backendName)." );
1572 $this->assertEquals( false, $status->isOK(),
1573 "Cleaning dir $path failed ($backendName)." );
1577 public function testRecursiveClean() {
1578 $this->backend
= $this->singleBackend
;
1579 $this->doTestRecursiveClean();
1580 $this->tearDownFiles();
1582 $this->backend
= $this->multiBackend
;
1583 $this->doTestRecursiveClean();
1584 $this->tearDownFiles();
1588 * @covers FileBackend::clean
1590 private function doTestRecursiveClean() {
1591 $backendName = $this->backendClass();
1593 $base = self
::baseStorePath();
1595 "$base/unittest-cont1",
1596 "$base/unittest-cont1/e",
1597 "$base/unittest-cont1/e/a",
1598 "$base/unittest-cont1/e/a/b",
1599 "$base/unittest-cont1/e/a/b/c",
1600 "$base/unittest-cont1/e/a/b/c/d0",
1601 "$base/unittest-cont1/e/a/b/c/d1",
1602 "$base/unittest-cont1/e/a/b/c/d2",
1603 "$base/unittest-cont1/e/a/b/c/d0/1",
1604 "$base/unittest-cont1/e/a/b/c/d0/2",
1605 "$base/unittest-cont1/e/a/b/c/d1/3",
1606 "$base/unittest-cont1/e/a/b/c/d1/4",
1607 "$base/unittest-cont1/e/a/b/c/d2/5",
1608 "$base/unittest-cont1/e/a/b/c/d2/6"
1610 foreach ( $dirs as $dir ) {
1611 $status = $this->prepare( array( 'dir' => $dir ) );
1612 $this->assertGoodStatus( $status,
1613 "Preparing dir $dir succeeded without warnings ($backendName)." );
1616 if ( $this->backend
instanceof FSFileBackend
) {
1617 foreach ( $dirs as $dir ) {
1618 $this->assertEquals( true, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1619 "Dir $dir exists ($backendName)." );
1623 $status = $this->backend
->clean(
1624 array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
1625 $this->assertGoodStatus( $status,
1626 "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
1628 foreach ( $dirs as $dir ) {
1629 $this->assertEquals( false, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1630 "Dir $dir no longer exists ($backendName)." );
1635 * @covers FileBackend::doOperations
1637 public function testDoOperations() {
1638 $this->backend
= $this->singleBackend
;
1639 $this->tearDownFiles();
1640 $this->doTestDoOperations();
1641 $this->tearDownFiles();
1643 $this->backend
= $this->multiBackend
;
1644 $this->tearDownFiles();
1645 $this->doTestDoOperations();
1646 $this->tearDownFiles();
1649 private function doTestDoOperations() {
1650 $base = self
::baseStorePath();
1652 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1653 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1654 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1655 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1656 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1657 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1658 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1660 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1661 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1662 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1663 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1664 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1665 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1666 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1668 $status = $this->backend
->doOperations( array(
1669 array( 'op' => 'describe', 'src' => $fileA,
1670 'headers' => array( 'X-Content-Length' => '91.3' ), 'disposition' => 'inline' ),
1671 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1672 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1673 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1674 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1675 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1676 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1677 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1678 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1679 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1680 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1681 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1682 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1683 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1684 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1685 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1686 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1687 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1689 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1691 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1693 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1695 array( 'op' => 'null' ),
1699 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1700 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1701 $this->assertEquals( 14, count( $status->success
),
1702 "Operation batch has correct success array" );
1704 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1705 "File does not exist at $fileA" );
1706 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1707 "File does not exist at $fileB" );
1708 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1709 "File does not exist at $fileD" );
1711 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1712 "File exists at $fileC" );
1713 $this->assertEquals( $fileBContents,
1714 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1715 "Correct file contents of $fileC" );
1716 $this->assertEquals( strlen( $fileBContents ),
1717 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1718 "Correct file size of $fileC" );
1719 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1720 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1721 "Correct file SHA-1 of $fileC" );
1725 * @covers FileBackend::doOperations
1727 public function testDoOperationsPipeline() {
1728 $this->backend
= $this->singleBackend
;
1729 $this->tearDownFiles();
1730 $this->doTestDoOperationsPipeline();
1731 $this->tearDownFiles();
1733 $this->backend
= $this->multiBackend
;
1734 $this->tearDownFiles();
1735 $this->doTestDoOperationsPipeline();
1736 $this->tearDownFiles();
1739 // concurrency orientated
1740 private function doTestDoOperationsPipeline() {
1741 $base = self
::baseStorePath();
1743 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1744 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1745 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1747 $tmpNameA = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1748 $tmpNameB = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1749 $tmpNameC = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1750 $this->addTmpFiles( array( $tmpNameA, $tmpNameB, $tmpNameC ) );
1751 file_put_contents( $tmpNameA, $fileAContents );
1752 file_put_contents( $tmpNameB, $fileBContents );
1753 file_put_contents( $tmpNameC, $fileCContents );
1755 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1756 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1757 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1758 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1760 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1761 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1762 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1763 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1764 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1766 $status = $this->backend
->doOperations( array(
1767 array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
1768 array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
1769 array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
1770 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1771 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1772 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1773 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1774 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1775 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1776 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1777 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1778 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1779 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1780 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1781 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1782 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1783 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1784 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1785 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1786 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1788 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1790 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1792 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1794 array( 'op' => 'null' ),
1798 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1799 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1800 $this->assertEquals( 16, count( $status->success
),
1801 "Operation batch has correct success array" );
1803 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1804 "File does not exist at $fileA" );
1805 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1806 "File does not exist at $fileB" );
1807 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1808 "File does not exist at $fileD" );
1810 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1811 "File exists at $fileC" );
1812 $this->assertEquals( $fileBContents,
1813 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1814 "Correct file contents of $fileC" );
1815 $this->assertEquals( strlen( $fileBContents ),
1816 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1817 "Correct file size of $fileC" );
1818 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1819 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1820 "Correct file SHA-1 of $fileC" );
1824 * @covers FileBackend::doOperations
1826 public function testDoOperationsFailing() {
1827 $this->backend
= $this->singleBackend
;
1828 $this->tearDownFiles();
1829 $this->doTestDoOperationsFailing();
1830 $this->tearDownFiles();
1832 $this->backend
= $this->multiBackend
;
1833 $this->tearDownFiles();
1834 $this->doTestDoOperationsFailing();
1835 $this->tearDownFiles();
1838 private function doTestDoOperationsFailing() {
1839 $base = self
::baseStorePath();
1841 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
1842 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1843 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
1844 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1845 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
1846 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1847 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
1849 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1850 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1851 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1852 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1853 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1854 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1856 $status = $this->backend
->doOperations( array(
1857 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1858 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1859 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1860 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1861 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
1862 // Now: A:<A>, B:<B>, C:<A>, D:<B>
1863 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
1864 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1865 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
1866 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1867 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
1868 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1869 array( 'op' => 'delete', 'src' => $fileD ),
1870 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1871 array( 'op' => 'null' ),
1873 ), array( 'force' => 1 ) );
1875 $this->assertNotEquals( array(), $status->errors
, "Operation had warnings" );
1876 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1877 $this->assertEquals( 8, count( $status->success
),
1878 "Operation batch has correct success array" );
1880 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1881 "File does not exist at $fileB" );
1882 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1883 "File does not exist at $fileD" );
1885 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1886 "File does not exist at $fileA" );
1887 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1888 "File exists at $fileC" );
1889 $this->assertEquals( $fileBContents,
1890 $this->backend
->getFileContents( array( 'src' => $fileA ) ),
1891 "Correct file contents of $fileA" );
1892 $this->assertEquals( strlen( $fileBContents ),
1893 $this->backend
->getFileSize( array( 'src' => $fileA ) ),
1894 "Correct file size of $fileA" );
1895 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1896 $this->backend
->getFileSha1Base36( array( 'src' => $fileA ) ),
1897 "Correct file SHA-1 of $fileA" );
1901 * @covers FileBackend::getFileList
1903 public function testGetFileList() {
1904 $this->backend
= $this->singleBackend
;
1905 $this->tearDownFiles();
1906 $this->doTestGetFileList();
1907 $this->tearDownFiles();
1909 $this->backend
= $this->multiBackend
;
1910 $this->tearDownFiles();
1911 $this->doTestGetFileList();
1912 $this->tearDownFiles();
1915 private function doTestGetFileList() {
1916 $backendName = $this->backendClass();
1917 $base = self
::baseStorePath();
1919 // Should have no errors
1920 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
1923 "$base/unittest-cont1/e/test1.txt",
1924 "$base/unittest-cont1/e/test2.txt",
1925 "$base/unittest-cont1/e/test3.txt",
1926 "$base/unittest-cont1/e/subdir1/test1.txt",
1927 "$base/unittest-cont1/e/subdir1/test2.txt",
1928 "$base/unittest-cont1/e/subdir2/test3.txt",
1929 "$base/unittest-cont1/e/subdir2/test4.txt",
1930 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
1931 "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
1932 "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
1933 "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
1934 "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
1935 "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
1936 "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
1941 foreach ( $files as $file ) {
1942 $this->prepare( array( 'dir' => dirname( $file ) ) );
1943 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1945 $status = $this->backend
->doQuickOperations( $ops );
1946 $this->assertGoodStatus( $status,
1947 "Creation of files succeeded ($backendName)." );
1948 $this->assertEquals( true, $status->isOK(),
1949 "Creation of files succeeded with OK status ($backendName)." );
1951 // Expected listing at root
1956 "e/subdir1/test1.txt",
1957 "e/subdir1/test2.txt",
1958 "e/subdir2/test3.txt",
1959 "e/subdir2/test4.txt",
1960 "e/subdir2/subdir/test1.txt",
1961 "e/subdir2/subdir/test2.txt",
1962 "e/subdir2/subdir/test3.txt",
1963 "e/subdir2/subdir/test4.txt",
1964 "e/subdir2/subdir/test5.txt",
1965 "e/subdir2/subdir/sub/test0.txt",
1966 "e/subdir2/subdir/sub/120-px-file.txt",
1970 // Actual listing (no trailing slash) at root
1971 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1972 $list = $this->listToArray( $iter );
1974 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1976 // Actual listing (no trailing slash) at root with advise
1977 $iter = $this->backend
->getFileList( array(
1978 'dir' => "$base/unittest-cont1",
1981 $list = $this->listToArray( $iter );
1983 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1985 // Actual listing (with trailing slash) at root
1987 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1988 foreach ( $iter as $file ) {
1992 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1994 // Expected listing at subdir
2002 "sub/120-px-file.txt",
2006 // Actual listing (no trailing slash) at subdir
2007 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
2008 $list = $this->listToArray( $iter );
2010 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
2012 // Actual listing (no trailing slash) at subdir with advise
2013 $iter = $this->backend
->getFileList( array(
2014 'dir' => "$base/unittest-cont1/e/subdir2/subdir",
2017 $list = $this->listToArray( $iter );
2019 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
2021 // Actual listing (with trailing slash) at subdir
2023 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
2024 foreach ( $iter as $file ) {
2028 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
2030 // Actual listing (using iterator second time)
2031 $list = $this->listToArray( $iter );
2033 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
2035 // Actual listing (top files only) at root
2036 $iter = $this->backend
->getTopFileList( array( 'dir' => "$base/unittest-cont1" ) );
2037 $list = $this->listToArray( $iter );
2039 $this->assertEquals( array(), $list, "Correct top file listing ($backendName)." );
2041 // Expected listing (top files only) at subdir
2051 // Actual listing (top files only) at subdir
2052 $iter = $this->backend
->getTopFileList(
2053 array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" )
2055 $list = $this->listToArray( $iter );
2057 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
2059 // Actual listing (top files only) at subdir with advise
2060 $iter = $this->backend
->getTopFileList( array(
2061 'dir' => "$base/unittest-cont1/e/subdir2/subdir",
2064 $list = $this->listToArray( $iter );
2066 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
2068 foreach ( $files as $file ) { // clean up
2069 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
2072 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
2073 foreach ( $iter as $iter ) {
2079 * @covers FileBackend::getTopDirectoryList
2080 * @covers FileBackend::getDirectoryList
2082 public function testGetDirectoryList() {
2083 $this->backend
= $this->singleBackend
;
2084 $this->tearDownFiles();
2085 $this->doTestGetDirectoryList();
2086 $this->tearDownFiles();
2088 $this->backend
= $this->multiBackend
;
2089 $this->tearDownFiles();
2090 $this->doTestGetDirectoryList();
2091 $this->tearDownFiles();
2094 private function doTestGetDirectoryList() {
2095 $backendName = $this->backendClass();
2097 $base = self
::baseStorePath();
2099 "$base/unittest-cont1/e/test1.txt",
2100 "$base/unittest-cont1/e/test2.txt",
2101 "$base/unittest-cont1/e/test3.txt",
2102 "$base/unittest-cont1/e/subdir1/test1.txt",
2103 "$base/unittest-cont1/e/subdir1/test2.txt",
2104 "$base/unittest-cont1/e/subdir2/test3.txt",
2105 "$base/unittest-cont1/e/subdir2/test4.txt",
2106 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
2107 "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
2108 "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
2109 "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
2110 "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
2111 "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
2112 "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
2117 foreach ( $files as $file ) {
2118 $this->prepare( array( 'dir' => dirname( $file ) ) );
2119 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
2121 $status = $this->backend
->doQuickOperations( $ops );
2122 $this->assertGoodStatus( $status,
2123 "Creation of files succeeded ($backendName)." );
2124 $this->assertEquals( true, $status->isOK(),
2125 "Creation of files succeeded with OK status ($backendName)." );
2127 $this->assertEquals( true,
2128 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
2129 "Directory exists in ($backendName)." );
2130 $this->assertEquals( true,
2131 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
2132 "Directory exists in ($backendName)." );
2133 $this->assertEquals( false,
2134 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
2135 "Directory does not exists in ($backendName)." );
2143 // Actual listing (no trailing slash)
2145 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
2146 foreach ( $iter as $file ) {
2151 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2162 // Actual listing (no trailing slash)
2164 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
2165 foreach ( $iter as $file ) {
2170 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2172 // Actual listing (with trailing slash)
2174 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
2175 foreach ( $iter as $file ) {
2180 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2188 // Actual listing (no trailing slash)
2190 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
2191 foreach ( $iter as $file ) {
2196 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2198 // Actual listing (with trailing slash)
2200 $iter = $this->backend
->getTopDirectoryList(
2201 array( 'dir' => "$base/unittest-cont1/e/subdir2/" )
2204 foreach ( $iter as $file ) {
2209 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2211 // Actual listing (using iterator second time)
2213 foreach ( $iter as $file ) {
2218 $this->assertEquals(
2221 "Correct top dir listing ($backendName), second iteration."
2224 // Expected listing (recursive)
2234 "e/subdir4/subdir/sub",
2238 // Actual listing (recursive)
2240 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
2241 foreach ( $iter as $file ) {
2246 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2248 // Expected listing (recursive)
2255 // Actual listing (recursive)
2257 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
2258 foreach ( $iter as $file ) {
2263 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2265 // Actual listing (recursive, second time)
2267 foreach ( $iter as $file ) {
2272 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2274 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) );
2275 $items = $this->listToArray( $iter );
2276 $this->assertEquals( array(), $items, "Directory listing is empty." );
2278 foreach ( $files as $file ) { // clean up
2279 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
2282 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
2283 foreach ( $iter as $file ) {
2287 $items = $this->listToArray( $iter );
2288 $this->assertEquals( array(), $items, "Directory listing is empty." );
2290 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/not/exists" ) );
2291 $items = $this->listToArray( $iter );
2292 $this->assertEquals( array(), $items, "Directory listing is empty." );
2296 * @covers FileBackend::lockFiles
2297 * @covers FileBackend::unlockFiles
2299 public function testLockCalls() {
2300 $this->backend
= $this->singleBackend
;
2301 $this->doTestLockCalls();
2304 private function doTestLockCalls() {
2305 $backendName = $this->backendClass();
2312 "subdir1", // duplicate
2313 "subdir1/test1.txt",
2314 "subdir1/test2.txt",
2316 "subdir2", // duplicate
2317 "subdir2/test3.txt",
2318 "subdir2/test4.txt",
2320 "subdir2/subdir/test1.txt",
2321 "subdir2/subdir/test2.txt",
2322 "subdir2/subdir/test3.txt",
2323 "subdir2/subdir/test4.txt",
2324 "subdir2/subdir/test5.txt",
2325 "subdir2/subdir/sub",
2326 "subdir2/subdir/sub/test0.txt",
2327 "subdir2/subdir/sub/120-px-file.txt",
2330 for ( $i = 0; $i < 25; $i++
) {
2331 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_EX
);
2332 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2333 "Locking of files succeeded ($backendName) ($i)." );
2334 $this->assertEquals( true, $status->isOK(),
2335 "Locking of files succeeded with OK status ($backendName) ($i)." );
2337 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_SH
);
2338 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2339 "Locking of files succeeded ($backendName) ($i)." );
2340 $this->assertEquals( true, $status->isOK(),
2341 "Locking of files succeeded with OK status ($backendName) ($i)." );
2343 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_SH
);
2344 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2345 "Locking of files succeeded ($backendName) ($i)." );
2346 $this->assertEquals( true, $status->isOK(),
2347 "Locking of files succeeded with OK status ($backendName) ($i)." );
2349 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_EX
);
2350 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2351 "Locking of files succeeded ($backendName). ($i)" );
2352 $this->assertEquals( true, $status->isOK(),
2353 "Locking of files succeeded with OK status ($backendName) ($i)." );
2355 # # Flip the acquire/release ordering around ##
2357 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_SH
);
2358 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2359 "Locking of files succeeded ($backendName) ($i)." );
2360 $this->assertEquals( true, $status->isOK(),
2361 "Locking of files succeeded with OK status ($backendName) ($i)." );
2363 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_EX
);
2364 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2365 "Locking of files succeeded ($backendName) ($i)." );
2366 $this->assertEquals( true, $status->isOK(),
2367 "Locking of files succeeded with OK status ($backendName) ($i)." );
2369 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_EX
);
2370 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2371 "Locking of files succeeded ($backendName). ($i)" );
2372 $this->assertEquals( true, $status->isOK(),
2373 "Locking of files succeeded with OK status ($backendName) ($i)." );
2375 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_SH
);
2376 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2377 "Locking of files succeeded ($backendName) ($i)." );
2378 $this->assertEquals( true, $status->isOK(),
2379 "Locking of files succeeded with OK status ($backendName) ($i)." );
2382 $status = Status
::newGood();
2383 $sl = $this->backend
->getScopedFileLocks( $paths, LockManager
::LOCK_EX
, $status );
2384 $this->assertInstanceOf( 'ScopedLock', $sl,
2385 "Scoped locking of files succeeded ($backendName)." );
2386 $this->assertEquals( array(), $status->errors
,
2387 "Scoped locking of files succeeded ($backendName)." );
2388 $this->assertEquals( true, $status->isOK(),
2389 "Scoped locking of files succeeded with OK status ($backendName)." );
2391 ScopedLock
::release( $sl );
2392 $this->assertEquals( null, $sl,
2393 "Scoped unlocking of files succeeded ($backendName)." );
2394 $this->assertEquals( array(), $status->errors
,
2395 "Scoped unlocking of files succeeded ($backendName)." );
2396 $this->assertEquals( true, $status->isOK(),
2397 "Scoped unlocking of files succeeded with OK status ($backendName)." );
2400 public function testReadAffinity() {
2401 $be = TestingAccessWrapper
::newFromObject(
2402 new FileBackendMultiWrite( array(
2403 'name' => 'localtesting',
2404 'wikiId' => wfWikiId() . mt_rand(),
2405 'backends' => array(
2407 'name' => 'multitesting0',
2408 'class' => 'MemoryFileBackend',
2409 'isMultiMaster' => false,
2410 'readAffinity' => true
2413 'name' => 'multitesting1',
2414 'class' => 'MemoryFileBackend',
2415 'isMultiMaster' => true
2421 $this->assertEquals(
2423 $be->getReadIndexFromParams( array( 'latest' => 1 ) ),
2424 'Reads with "latest" flag use backend 1'
2426 $this->assertEquals(
2428 $be->getReadIndexFromParams( array( 'latest' => 0 ) ),
2429 'Reads without "latest" flag use backend 0'
2432 $p = 'container/test-cont/file.txt';
2433 $be->backends
[0]->quickCreate( array(
2434 'dst' => "mwstore://multitesting0/$p", 'content' => 'cattitude' ) );
2435 $be->backends
[1]->quickCreate( array(
2436 'dst' => "mwstore://multitesting1/$p", 'content' => 'princess of power' ) );
2438 $this->assertEquals(
2440 $be->getFileContents( array( 'src' => "mwstore://localtesting/$p" ) ),
2441 "Non-latest read came from backend 0"
2443 $this->assertEquals(
2444 'princess of power',
2445 $be->getFileContents( array( 'src' => "mwstore://localtesting/$p", 'latest' => 1 ) ),
2446 "Latest read came from backend1"
2450 public function testAsyncWrites() {
2451 $be = TestingAccessWrapper
::newFromObject(
2452 new FileBackendMultiWrite( array(
2453 'name' => 'localtesting',
2454 'wikiId' => wfWikiId() . mt_rand(),
2455 'backends' => array(
2457 'name' => 'multitesting0',
2458 'class' => 'MemoryFileBackend',
2459 'isMultiMaster' => false
2462 'name' => 'multitesting1',
2463 'class' => 'MemoryFileBackend',
2464 'isMultiMaster' => true
2467 'replication' => 'async'
2471 DeferredUpdates
::forceDeferral( true );
2473 $p = 'container/test-cont/file.txt';
2474 $be->quickCreate( array(
2475 'dst' => "mwstore://localtesting/$p", 'content' => 'cattitude' ) );
2477 $this->assertEquals(
2479 $be->backends
[0]->getFileContents( array( 'src' => "mwstore://multitesting0/$p" ) ),
2480 "File not yet written to backend 0"
2482 $this->assertEquals(
2484 $be->backends
[1]->getFileContents( array( 'src' => "mwstore://multitesting1/$p" ) ),
2485 "File already written to backend 1"
2488 DeferredUpdates
::doUpdates();
2489 DeferredUpdates
::forceDeferral( false );
2491 $this->assertEquals(
2493 $be->backends
[0]->getFileContents( array( 'src' => "mwstore://multitesting0/$p" ) ),
2494 "File now written to backend 0"
2499 private function listToArray( $iter ) {
2500 return is_array( $iter ) ?
$iter : iterator_to_array( $iter );
2503 // test helper wrapper for backend prepare() function
2504 private function prepare( array $params ) {
2505 return $this->backend
->prepare( $params );
2508 // test helper wrapper for backend prepare() function
2509 private function create( array $params ) {
2510 $params['op'] = 'create';
2512 return $this->backend
->doQuickOperations( array( $params ) );
2515 function tearDownFiles() {
2516 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont-bad' );
2517 foreach ( $containers as $container ) {
2518 $this->deleteFiles( $container );
2522 private function deleteFiles( $container ) {
2523 $base = self
::baseStorePath();
2524 $iter = $this->backend
->getFileList( array( 'dir' => "$base/$container" ) );
2526 foreach ( $iter as $file ) {
2527 $this->backend
->quickDelete( array( 'src' => "$base/$container/$file" ) );
2529 // free the directory, to avoid Permission denied under windows on rmdir
2532 $this->backend
->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
2535 function assertBackendPathsConsistent( array $paths ) {
2536 if ( $this->backend
instanceof FileBackendMultiWrite
) {
2537 $status = $this->backend
->consistencyCheck( $paths );
2538 $this->assertGoodStatus( $status, "Files synced: " . implode( ',', $paths ) );
2542 function assertGoodStatus( $status, $msg ) {
2543 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors
, 1 ), $msg );