8 class FileBackendTest
extends MediaWikiTestCase
{
10 /** @var FileBackend */
12 /** @var FileBackendMultiWrite */
13 private $multiBackend;
14 /** @var FSFileBackend */
15 public $singleBackend;
16 private $filesToPrune = array();
17 private static $backendToUse;
19 protected function setUp() {
20 global $wgFileBackends;
22 $uniqueId = time() . '-' . mt_rand();
23 $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . $uniqueId;
24 if ( $this->getCliArg( 'use-filebackend=' ) ) {
25 if ( self
::$backendToUse ) {
26 $this->singleBackend
= self
::$backendToUse;
28 $name = $this->getCliArg( 'use-filebackend=' );
30 foreach ( $wgFileBackends as $conf ) {
31 if ( $conf['name'] == $name ) {
36 $useConfig['name'] = 'localtesting'; // swap name
37 $useConfig['shardViaHashLevels'] = array( // test sharding
38 'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
40 if ( isset( $useConfig['fileJournal'] ) ) {
41 $useConfig['fileJournal'] = FileJournal
::factory( $useConfig['fileJournal'], $name );
43 $useConfig['lockManager'] = LockManagerGroup
::singleton()->get( $useConfig['lockManager'] );
44 $class = $useConfig['class'];
45 self
::$backendToUse = new $class( $useConfig );
46 $this->singleBackend
= self
::$backendToUse;
49 $this->singleBackend
= new FSFileBackend( array(
50 'name' => 'localtesting',
51 'lockManager' => LockManagerGroup
::singleton()->get( 'fsLockManager' ),
52 'wikiId' => wfWikiID(),
53 'containerPaths' => array(
54 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
55 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
58 $this->multiBackend
= new FileBackendMultiWrite( array(
59 'name' => 'localtesting',
60 'lockManager' => LockManagerGroup
::singleton()->get( 'fsLockManager' ),
61 'parallelize' => 'implicit',
62 'wikiId' => wfWikiId() . $uniqueId,
65 'name' => 'localmultitesting1',
66 'class' => 'FSFileBackend',
67 'containerPaths' => array(
68 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
69 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
70 'isMultiMaster' => false
73 'name' => 'localmultitesting2',
74 'class' => 'FSFileBackend',
75 'containerPaths' => array(
76 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
77 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
78 'isMultiMaster' => true
82 $this->filesToPrune
= array();
85 private static function baseStorePath() {
86 return 'mwstore://localtesting';
89 private function backendClass() {
90 return get_class( $this->backend
);
94 * @dataProvider provider_testIsStoragePath
95 * @covers FileBackend::isStoragePath
97 public function testIsStoragePath( $path, $isStorePath ) {
98 $this->assertEquals( $isStorePath, FileBackend
::isStoragePath( $path ),
99 "FileBackend::isStoragePath on path '$path'" );
102 public static function provider_testIsStoragePath() {
104 array( 'mwstore://', true ),
105 array( 'mwstore://backend', true ),
106 array( 'mwstore://backend/container', true ),
107 array( 'mwstore://backend/container/', true ),
108 array( 'mwstore://backend/container/path', true ),
109 array( 'mwstore://backend//container/', true ),
110 array( 'mwstore://backend//container//', true ),
111 array( 'mwstore://backend//container//path', true ),
112 array( 'mwstore:///', true ),
113 array( 'mwstore:/', false ),
114 array( 'mwstore:', false ),
119 * @dataProvider provider_testSplitStoragePath
120 * @covers FileBackend::splitStoragePath
122 public function testSplitStoragePath( $path, $res ) {
123 $this->assertEquals( $res, FileBackend
::splitStoragePath( $path ),
124 "FileBackend::splitStoragePath on path '$path'" );
127 public static function provider_testSplitStoragePath() {
129 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
130 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
131 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
132 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
133 array( 'mwstore://backend//container/path', array( null, null, null ) ),
134 array( 'mwstore://backend//container//path', array( null, null, null ) ),
135 array( 'mwstore://', array( null, null, null ) ),
136 array( 'mwstore://backend', array( null, null, null ) ),
137 array( 'mwstore:///', array( null, null, null ) ),
138 array( 'mwstore:/', array( null, null, null ) ),
139 array( 'mwstore:', array( null, null, null ) )
144 * @dataProvider provider_normalizeStoragePath
145 * @covers FileBackend::normalizeStoragePath
147 public function testNormalizeStoragePath( $path, $res ) {
148 $this->assertEquals( $res, FileBackend
::normalizeStoragePath( $path ),
149 "FileBackend::normalizeStoragePath on path '$path'" );
152 public static function provider_normalizeStoragePath() {
154 array( 'mwstore://backend/container', 'mwstore://backend/container' ),
155 array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
156 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
157 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
158 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
159 array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj' ),
160 array( 'mwstore://', null ),
161 array( 'mwstore://backend', null ),
162 array( 'mwstore://backend//container/path', null ),
163 array( 'mwstore://backend//container//path', null ),
164 array( 'mwstore:///', null ),
165 array( 'mwstore:/', null ),
166 array( 'mwstore:', null ),
171 * @dataProvider provider_testParentStoragePath
172 * @covers FileBackend::parentStoragePath
174 public function testParentStoragePath( $path, $res ) {
175 $this->assertEquals( $res, FileBackend
::parentStoragePath( $path ),
176 "FileBackend::parentStoragePath on path '$path'" );
179 public static function provider_testParentStoragePath() {
181 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
182 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
183 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
184 array( 'mwstore://backend/container', null ),
185 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
186 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
187 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
188 array( 'mwstore://backend/container/', null ),
193 * @dataProvider provider_testExtensionFromPath
194 * @covers FileBackend::extensionFromPath
196 public function testExtensionFromPath( $path, $res ) {
197 $this->assertEquals( $res, FileBackend
::extensionFromPath( $path ),
198 "FileBackend::extensionFromPath on path '$path'" );
201 public static function provider_testExtensionFromPath() {
203 array( 'mwstore://backend/container/path.txt', 'txt' ),
204 array( 'mwstore://backend/container/path.svg.png', 'png' ),
205 array( 'mwstore://backend/container/path', '' ),
206 array( 'mwstore://backend/container/path.', '' ),
211 * @dataProvider provider_testStore
213 public function testStore( $op ) {
214 $this->filesToPrune
[] = $op['src'];
216 $this->backend
= $this->singleBackend
;
217 $this->tearDownFiles();
218 $this->doTestStore( $op );
219 $this->tearDownFiles();
221 $this->backend
= $this->multiBackend
;
222 $this->tearDownFiles();
223 $this->doTestStore( $op );
224 $this->filesToPrune
[] = $op['src']; # avoid file leaking
225 $this->tearDownFiles();
229 * @covers FileBackend::doOperation
231 private function doTestStore( $op ) {
232 $backendName = $this->backendClass();
234 $source = $op['src'];
236 $this->prepare( array( 'dir' => dirname( $dest ) ) );
238 file_put_contents( $source, "Unit test file" );
240 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
241 $this->backend
->store( $op );
244 $status = $this->backend
->doOperation( $op );
246 $this->assertGoodStatus( $status,
247 "Store from $source to $dest succeeded without warnings ($backendName)." );
248 $this->assertEquals( true, $status->isOK(),
249 "Store from $source to $dest succeeded ($backendName)." );
250 $this->assertEquals( array( 0 => true ), $status->success
,
251 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
252 $this->assertEquals( true, file_exists( $source ),
253 "Source file $source still exists ($backendName)." );
254 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
255 "Destination file $dest exists ($backendName)." );
257 $this->assertEquals( filesize( $source ),
258 $this->backend
->getFileSize( array( 'src' => $dest ) ),
259 "Destination file $dest has correct size ($backendName)." );
261 $props1 = FSFile
::getPropsFromPath( $source );
262 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
263 $this->assertEquals( $props1, $props2,
264 "Source and destination have the same props ($backendName)." );
266 $this->assertBackendPathsConsistent( array( $dest ) );
269 public static function provider_testStore() {
272 $tmpName = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
273 $toPath = self
::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
274 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
282 $op2['overwrite'] = true;
290 $op2['overwriteSame'] = true;
301 * @dataProvider provider_testCopy
302 * @covers FileBackend::doOperation
304 public function testCopy( $op ) {
305 $this->backend
= $this->singleBackend
;
306 $this->tearDownFiles();
307 $this->doTestCopy( $op );
308 $this->tearDownFiles();
310 $this->backend
= $this->multiBackend
;
311 $this->tearDownFiles();
312 $this->doTestCopy( $op );
313 $this->tearDownFiles();
316 private function doTestCopy( $op ) {
317 $backendName = $this->backendClass();
319 $source = $op['src'];
321 $this->prepare( array( 'dir' => dirname( $source ) ) );
322 $this->prepare( array( 'dir' => dirname( $dest ) ) );
324 if ( isset( $op['ignoreMissingSource'] ) ) {
325 $status = $this->backend
->doOperation( $op );
326 $this->assertGoodStatus( $status,
327 "Move from $source to $dest succeeded without warnings ($backendName)." );
328 $this->assertEquals( array( 0 => true ), $status->success
,
329 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
330 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
331 "Source file $source does not exist ($backendName)." );
332 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $dest ) ),
333 "Destination file $dest does not exist ($backendName)." );
338 $status = $this->backend
->doOperation(
339 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
340 $this->assertGoodStatus( $status,
341 "Creation of file at $source succeeded ($backendName)." );
343 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
344 $this->backend
->copy( $op );
347 $status = $this->backend
->doOperation( $op );
349 $this->assertGoodStatus( $status,
350 "Copy from $source to $dest succeeded without warnings ($backendName)." );
351 $this->assertEquals( true, $status->isOK(),
352 "Copy from $source to $dest succeeded ($backendName)." );
353 $this->assertEquals( array( 0 => true ), $status->success
,
354 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
355 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $source ) ),
356 "Source file $source still exists ($backendName)." );
357 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
358 "Destination file $dest exists after copy ($backendName)." );
361 $this->backend
->getFileSize( array( 'src' => $source ) ),
362 $this->backend
->getFileSize( array( 'src' => $dest ) ),
363 "Destination file $dest has correct size ($backendName)." );
365 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
366 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
367 $this->assertEquals( $props1, $props2,
368 "Source and destination have the same props ($backendName)." );
370 $this->assertBackendPathsConsistent( array( $source, $dest ) );
373 public static function provider_testCopy() {
376 $source = self
::baseStorePath() . '/unittest-cont1/e/file.txt';
377 $dest = self
::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
379 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
387 $op2['overwrite'] = true;
395 $op2['overwriteSame'] = true;
403 $op2['ignoreMissingSource'] = true;
411 $op2['ignoreMissingSource'] = true;
414 self
::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
422 * @dataProvider provider_testMove
423 * @covers FileBackend::doOperation
425 public function testMove( $op ) {
426 $this->backend
= $this->singleBackend
;
427 $this->tearDownFiles();
428 $this->doTestMove( $op );
429 $this->tearDownFiles();
431 $this->backend
= $this->multiBackend
;
432 $this->tearDownFiles();
433 $this->doTestMove( $op );
434 $this->tearDownFiles();
437 private function doTestMove( $op ) {
438 $backendName = $this->backendClass();
440 $source = $op['src'];
442 $this->prepare( array( 'dir' => dirname( $source ) ) );
443 $this->prepare( array( 'dir' => dirname( $dest ) ) );
445 if ( isset( $op['ignoreMissingSource'] ) ) {
446 $status = $this->backend
->doOperation( $op );
447 $this->assertGoodStatus( $status,
448 "Move from $source to $dest succeeded without warnings ($backendName)." );
449 $this->assertEquals( array( 0 => true ), $status->success
,
450 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
451 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
452 "Source file $source does not exist ($backendName)." );
453 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $dest ) ),
454 "Destination file $dest does not exist ($backendName)." );
459 $status = $this->backend
->doOperation(
460 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
461 $this->assertGoodStatus( $status,
462 "Creation of file at $source succeeded ($backendName)." );
464 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
465 $this->backend
->copy( $op );
468 $status = $this->backend
->doOperation( $op );
469 $this->assertGoodStatus( $status,
470 "Move from $source to $dest succeeded without warnings ($backendName)." );
471 $this->assertEquals( true, $status->isOK(),
472 "Move from $source to $dest succeeded ($backendName)." );
473 $this->assertEquals( array( 0 => true ), $status->success
,
474 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
475 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
476 "Source file $source does not still exists ($backendName)." );
477 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
478 "Destination file $dest exists after move ($backendName)." );
480 $this->assertNotEquals(
481 $this->backend
->getFileSize( array( 'src' => $source ) ),
482 $this->backend
->getFileSize( array( 'src' => $dest ) ),
483 "Destination file $dest has correct size ($backendName)." );
485 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
486 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
487 $this->assertEquals( false, $props1['fileExists'],
488 "Source file does not exist accourding to props ($backendName)." );
489 $this->assertEquals( true, $props2['fileExists'],
490 "Destination file exists accourding to props ($backendName)." );
492 $this->assertBackendPathsConsistent( array( $source, $dest ) );
495 public static function provider_testMove() {
498 $source = self
::baseStorePath() . '/unittest-cont1/e/file.txt';
499 $dest = self
::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
501 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
509 $op2['overwrite'] = true;
517 $op2['overwriteSame'] = true;
525 $op2['ignoreMissingSource'] = true;
533 $op2['ignoreMissingSource'] = true;
536 self
::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
544 * @dataProvider provider_testDelete
545 * @covers FileBackend::doOperation
547 public function testDelete( $op, $withSource, $okStatus ) {
548 $this->backend
= $this->singleBackend
;
549 $this->tearDownFiles();
550 $this->doTestDelete( $op, $withSource, $okStatus );
551 $this->tearDownFiles();
553 $this->backend
= $this->multiBackend
;
554 $this->tearDownFiles();
555 $this->doTestDelete( $op, $withSource, $okStatus );
556 $this->tearDownFiles();
559 private function doTestDelete( $op, $withSource, $okStatus ) {
560 $backendName = $this->backendClass();
562 $source = $op['src'];
563 $this->prepare( array( 'dir' => dirname( $source ) ) );
566 $status = $this->backend
->doOperation(
567 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
568 $this->assertGoodStatus( $status,
569 "Creation of file at $source succeeded ($backendName)." );
572 $status = $this->backend
->doOperation( $op );
574 $this->assertGoodStatus( $status,
575 "Deletion of file at $source succeeded without warnings ($backendName)." );
576 $this->assertEquals( true, $status->isOK(),
577 "Deletion of file at $source succeeded ($backendName)." );
578 $this->assertEquals( array( 0 => true ), $status->success
,
579 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
581 $this->assertEquals( false, $status->isOK(),
582 "Deletion of file at $source failed ($backendName)." );
585 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
586 "Source file $source does not exist after move ($backendName)." );
589 $this->backend
->getFileSize( array( 'src' => $source ) ),
590 "Source file $source has correct size (false) ($backendName)." );
592 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
593 $this->assertFalse( $props1['fileExists'],
594 "Source file $source does not exist according to props ($backendName)." );
596 $this->assertBackendPathsConsistent( array( $source ) );
599 public static function provider_testDelete() {
602 $source = self
::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
604 $op = array( 'op' => 'delete', 'src' => $source );
613 false, // without source
617 $op['ignoreMissingSource'] = true;
620 false, // without source
624 $op['ignoreMissingSource'] = true;
625 $op['src'] = self
::baseStorePath() . '/unittest-cont-bad/e/file.txt';
628 false, // without source
636 * @dataProvider provider_testDescribe
637 * @covers FileBackend::doOperation
639 public function testDescribe( $op, $withSource, $okStatus ) {
640 $this->backend
= $this->singleBackend
;
641 $this->tearDownFiles();
642 $this->doTestDescribe( $op, $withSource, $okStatus );
643 $this->tearDownFiles();
645 $this->backend
= $this->multiBackend
;
646 $this->tearDownFiles();
647 $this->doTestDescribe( $op, $withSource, $okStatus );
648 $this->tearDownFiles();
651 private function doTestDescribe( $op, $withSource, $okStatus ) {
652 $backendName = $this->backendClass();
654 $source = $op['src'];
655 $this->prepare( array( 'dir' => dirname( $source ) ) );
658 $status = $this->backend
->doOperation(
659 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source,
660 'headers' => array( 'Content-Disposition' => 'xxx' ) ) );
661 $this->assertGoodStatus( $status,
662 "Creation of file at $source succeeded ($backendName)." );
663 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
664 $attr = $this->backend
->getFileXAttributes( array( 'src' => $source ) );
665 $this->assertHasHeaders( array( 'Content-Disposition' => 'xxx' ), $attr );
668 $status = $this->backend
->describe( array( 'src' => $source,
669 'headers' => array( 'Content-Disposition' => '' ) ) ); // remove
670 $this->assertGoodStatus( $status,
671 "Removal of header for $source succeeded ($backendName)." );
673 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
674 $attr = $this->backend
->getFileXAttributes( array( 'src' => $source ) );
675 $this->assertFalse( isset( $attr['headers']['content-disposition'] ),
676 "File 'Content-Disposition' header removed." );
680 $status = $this->backend
->doOperation( $op );
682 $this->assertGoodStatus( $status,
683 "Describe of file at $source succeeded without warnings ($backendName)." );
684 $this->assertEquals( true, $status->isOK(),
685 "Describe of file at $source succeeded ($backendName)." );
686 $this->assertEquals( array( 0 => true ), $status->success
,
687 "Describe of file at $source has proper 'success' field in Status ($backendName)." );
688 if ( $this->backend
->hasFeatures( FileBackend
::ATTR_HEADERS
) ) {
689 $this->assertHasHeaders( $op['headers'], $attr );
692 $this->assertEquals( false, $status->isOK(),
693 "Describe of file at $source failed ($backendName)." );
696 $this->assertBackendPathsConsistent( array( $source ) );
699 private function assertHasHeaders( array $headers, array $attr ) {
700 foreach ( $headers as $n => $v ) {
702 $this->assertTrue( isset( $attr['headers'][strtolower( $n )] ),
703 "File has '$n' header." );
704 $this->assertEquals( $v, $attr['headers'][strtolower( $n )],
705 "File has '$n' header value." );
707 $this->assertFalse( isset( $attr['headers'][strtolower( $n )] ),
708 "File does not have '$n' header." );
713 public static function provider_testDescribe() {
716 $source = self
::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
718 $op = array( 'op' => 'describe', 'src' => $source,
719 'headers' => array( 'Content-Disposition' => 'inline' ), );
728 false, // without source
736 * @dataProvider provider_testCreate
737 * @covers FileBackend::doOperation
739 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
740 $this->backend
= $this->singleBackend
;
741 $this->tearDownFiles();
742 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
743 $this->tearDownFiles();
745 $this->backend
= $this->multiBackend
;
746 $this->tearDownFiles();
747 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
748 $this->tearDownFiles();
751 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
752 $backendName = $this->backendClass();
755 $this->prepare( array( 'dir' => dirname( $dest ) ) );
757 $oldText = 'blah...blah...waahwaah';
758 if ( $alreadyExists ) {
759 $status = $this->backend
->doOperation(
760 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
761 $this->assertGoodStatus( $status,
762 "Creation of file at $dest succeeded ($backendName)." );
765 $status = $this->backend
->doOperation( $op );
767 $this->assertGoodStatus( $status,
768 "Creation of file at $dest succeeded without warnings ($backendName)." );
769 $this->assertEquals( true, $status->isOK(),
770 "Creation of file at $dest succeeded ($backendName)." );
771 $this->assertEquals( array( 0 => true ), $status->success
,
772 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
774 $this->assertEquals( false, $status->isOK(),
775 "Creation of file at $dest failed ($backendName)." );
778 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
779 "Destination file $dest exists after creation ($backendName)." );
781 $props1 = $this->backend
->getFileProps( array( 'src' => $dest ) );
782 $this->assertEquals( true, $props1['fileExists'],
783 "Destination file $dest exists according to props ($backendName)." );
784 if ( $okStatus ) { // file content is what we saved
785 $this->assertEquals( $newSize, $props1['size'],
786 "Destination file $dest has expected size according to props ($backendName)." );
787 $this->assertEquals( $newSize,
788 $this->backend
->getFileSize( array( 'src' => $dest ) ),
789 "Destination file $dest has correct size ($backendName)." );
790 } else { // file content is some other previous text
791 $this->assertEquals( strlen( $oldText ), $props1['size'],
792 "Destination file $dest has original size according to props ($backendName)." );
793 $this->assertEquals( strlen( $oldText ),
794 $this->backend
->getFileSize( array( 'src' => $dest ) ),
795 "Destination file $dest has original size according to props ($backendName)." );
798 $this->assertBackendPathsConsistent( array( $dest ) );
802 * @dataProvider provider_testCreate
804 public static function provider_testCreate() {
807 $dest = self
::baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
809 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
812 false, // no dest already exists
814 strlen( $op['content'] )
818 $op2['content'] = "\n";
821 false, // no dest already exists
823 strlen( $op2['content'] )
827 $op2['content'] = "fsf\n waf 3kt";
830 true, // dest already exists
832 strlen( $op2['content'] )
836 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
837 $op2['overwrite'] = true;
840 true, // dest already exists
842 strlen( $op2['content'] )
846 $op2['content'] = "39qjmg3-qg";
847 $op2['overwriteSame'] = true;
850 true, // dest already exists
852 strlen( $op2['content'] )
859 * @covers FileBackend::doQuickOperations
861 public function testDoQuickOperations() {
862 $this->backend
= $this->singleBackend
;
863 $this->doTestDoQuickOperations();
864 $this->tearDownFiles();
866 $this->backend
= $this->multiBackend
;
867 $this->doTestDoQuickOperations();
868 $this->tearDownFiles();
871 private function doTestDoQuickOperations() {
872 $backendName = $this->backendClass();
874 $base = self
::baseStorePath();
876 "$base/unittest-cont1/e/fileA.a",
877 "$base/unittest-cont1/e/fileB.a",
878 "$base/unittest-cont1/e/fileC.a"
880 $createOps = array();
882 foreach ( $files as $path ) {
883 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
884 $this->assertGoodStatus( $status,
885 "Preparing $path succeeded without warnings ($backendName)." );
886 $createOps[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand( 0, 50000 ) );
887 $copyOps[] = array( 'op' => 'copy', 'src' => $path, 'dst' => "$path-2" );
888 $moveOps[] = array( 'op' => 'move', 'src' => "$path-2", 'dst' => "$path-3" );
889 $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
890 $purgeOps[] = array( 'op' => 'delete', 'src' => "$path-3" );
892 $purgeOps[] = array( 'op' => 'null' );
894 $this->assertGoodStatus(
895 $this->backend
->doQuickOperations( $createOps ),
896 "Creation of source files succeeded ($backendName)." );
897 foreach ( $files as $file ) {
898 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $file ) ),
899 "File $file exists." );
902 $this->assertGoodStatus(
903 $this->backend
->doQuickOperations( $copyOps ),
904 "Quick copy of source files succeeded ($backendName)." );
905 foreach ( $files as $file ) {
906 $this->assertTrue( $this->backend
->fileExists( array( 'src' => "$file-2" ) ),
907 "File $file-2 exists." );
910 $this->assertGoodStatus(
911 $this->backend
->doQuickOperations( $moveOps ),
912 "Quick move of source files succeeded ($backendName)." );
913 foreach ( $files as $file ) {
914 $this->assertTrue( $this->backend
->fileExists( array( 'src' => "$file-3" ) ),
915 "File $file-3 move in." );
916 $this->assertFalse( $this->backend
->fileExists( array( 'src' => "$file-2" ) ),
917 "File $file-2 moved away." );
920 $this->assertGoodStatus(
921 $this->backend
->quickCopy( array( 'src' => $files[0], 'dst' => $files[0] ) ),
922 "Copy 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
->quickMove( array( 'src' => $files[0], 'dst' => $files[0] ) ),
928 "Move of file {$files[0]} over itself succeeded ($backendName)." );
929 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $files[0] ) ),
930 "File {$files[0]} still exists." );
932 $this->assertGoodStatus(
933 $this->backend
->doQuickOperations( $purgeOps ),
934 "Quick deletion of source files succeeded ($backendName)." );
935 foreach ( $files as $file ) {
936 $this->assertFalse( $this->backend
->fileExists( array( 'src' => $file ) ),
937 "File $file purged." );
938 $this->assertFalse( $this->backend
->fileExists( array( 'src' => "$file-3" ) ),
939 "File $file-3 purged." );
944 * @dataProvider provider_testConcatenate
946 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
947 $this->filesToPrune
[] = $op['dst'];
949 $this->backend
= $this->singleBackend
;
950 $this->tearDownFiles();
951 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
952 $this->filesToPrune
[] = $op['dst']; # avoid file leaking
953 $this->tearDownFiles();
955 $this->backend
= $this->multiBackend
;
956 $this->tearDownFiles();
957 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
958 $this->filesToPrune
[] = $op['dst']; # avoid file leaking
959 $this->tearDownFiles();
962 private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
963 $backendName = $this->backendClass();
968 foreach ( $srcs as $i => $source ) {
969 $this->prepare( array( 'dir' => dirname( $source ) ) );
971 'op' => 'create', // operation
972 'dst' => $source, // source
973 'content' => $srcsContent[$i]
975 $expContent .= $srcsContent[$i];
977 $status = $this->backend
->doOperations( $ops );
979 $this->assertGoodStatus( $status,
980 "Creation of source files succeeded ($backendName)." );
982 $dest = $params['dst'];
983 if ( $alreadyExists ) {
984 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
985 $this->assertEquals( true, $ok,
986 "Creation of file at $dest succeeded ($backendName)." );
988 $ok = file_put_contents( $dest, '' ) !== false;
989 $this->assertEquals( true, $ok,
990 "Creation of 0-byte file at $dest succeeded ($backendName)." );
993 // Combine the files into one
994 $status = $this->backend
->concatenate( $params );
996 $this->assertGoodStatus( $status,
997 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
998 $this->assertEquals( true, $status->isOK(),
999 "Creation of concat file at $dest succeeded ($backendName)." );
1001 $this->assertEquals( false, $status->isOK(),
1002 "Creation of concat file at $dest failed ($backendName)." );
1006 $this->assertEquals( true, is_file( $dest ),
1007 "Dest concat file $dest exists after creation ($backendName)." );
1009 $this->assertEquals( true, is_file( $dest ),
1010 "Dest concat file $dest exists after failed creation ($backendName)." );
1013 $contents = file_get_contents( $dest );
1014 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
1017 $this->assertEquals( $expContent, $contents,
1018 "Concat file at $dest has correct contents ($backendName)." );
1020 $this->assertNotEquals( $expContent, $contents,
1021 "Concat file at $dest has correct contents ($backendName)." );
1025 public static function provider_testConcatenate() {
1028 $rand = mt_rand( 0, 2000000000 ) . time();
1029 $dest = wfTempDir() . "/randomfile!$rand.txt";
1031 self
::baseStorePath() . '/unittest-cont1/e/file1.txt',
1032 self
::baseStorePath() . '/unittest-cont1/e/file2.txt',
1033 self
::baseStorePath() . '/unittest-cont1/e/file3.txt',
1034 self
::baseStorePath() . '/unittest-cont1/e/file4.txt',
1035 self
::baseStorePath() . '/unittest-cont1/e/file5.txt',
1036 self
::baseStorePath() . '/unittest-cont1/e/file6.txt',
1037 self
::baseStorePath() . '/unittest-cont1/e/file7.txt',
1038 self
::baseStorePath() . '/unittest-cont1/e/file8.txt',
1039 self
::baseStorePath() . '/unittest-cont1/e/file9.txt',
1040 self
::baseStorePath() . '/unittest-cont1/e/file10.txt'
1054 $params = array( 'srcs' => $srcs, 'dst' => $dest );
1057 $params, // operation
1059 $content, // content for each source
1060 false, // no dest already exists
1065 $params, // operation
1067 $content, // content for each source
1068 true, // dest already exists
1076 * @dataProvider provider_testGetFileStat
1077 * @covers FileBackend::getFileStat
1079 public function testGetFileStat( $path, $content, $alreadyExists ) {
1080 $this->backend
= $this->singleBackend
;
1081 $this->tearDownFiles();
1082 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1083 $this->tearDownFiles();
1085 $this->backend
= $this->multiBackend
;
1086 $this->tearDownFiles();
1087 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1088 $this->tearDownFiles();
1091 private function doTestGetFileStat( $path, $content, $alreadyExists ) {
1092 $backendName = $this->backendClass();
1094 if ( $alreadyExists ) {
1095 $this->prepare( array( 'dir' => dirname( $path ) ) );
1096 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1097 $this->assertGoodStatus( $status,
1098 "Creation of file at $path succeeded ($backendName)." );
1100 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1101 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
1102 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
1104 $this->assertEquals( strlen( $content ), $size,
1105 "Correct file size of '$path'" );
1106 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
1107 "Correct file timestamp of '$path'" );
1109 $size = $stat['size'];
1110 $time = $stat['mtime'];
1111 $this->assertEquals( strlen( $content ), $size,
1112 "Correct file size of '$path'" );
1113 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
1114 "Correct file timestamp of '$path'" );
1116 $this->backend
->clearCache( array( $path ) );
1118 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1120 $this->assertEquals( strlen( $content ), $size,
1121 "Correct file size of '$path'" );
1123 $this->backend
->preloadCache( array( $path ) );
1125 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1127 $this->assertEquals( strlen( $content ), $size,
1128 "Correct file size of '$path'" );
1130 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
1131 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
1132 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
1134 $this->assertFalse( $size, "Correct file size of '$path'" );
1135 $this->assertFalse( $time, "Correct file timestamp of '$path'" );
1136 $this->assertFalse( $stat, "Correct file stat of '$path'" );
1140 public static function provider_testGetFileStat() {
1143 $base = self
::baseStorePath();
1144 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
1145 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
1146 $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
1152 * @dataProvider provider_testGetFileStat
1153 * @covers FileBackend::streamFile
1155 public function testStreamFile( $path, $content, $alreadyExists ) {
1156 $this->backend
= $this->singleBackend
;
1157 $this->tearDownFiles();
1158 $this->doTestStreamFile( $path, $content, $alreadyExists );
1159 $this->tearDownFiles();
1162 private function doTestStreamFile( $path, $content ) {
1163 $backendName = $this->backendClass();
1165 // Test doStreamFile() directly to avoid header madness
1166 $class = new ReflectionClass( $this->backend
);
1167 $method = $class->getMethod( 'doStreamFile' );
1168 $method->setAccessible( true );
1170 if ( $content !== null ) {
1171 $this->prepare( array( 'dir' => dirname( $path ) ) );
1172 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1173 $this->assertGoodStatus( $status,
1174 "Creation of file at $path succeeded ($backendName)." );
1177 $method->invokeArgs( $this->backend
, array( array( 'src' => $path ) ) );
1178 $data = ob_get_contents();
1181 $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
1182 } else { // 404 case
1184 $method->invokeArgs( $this->backend
, array( array( 'src' => $path ) ) );
1185 $data = ob_get_contents();
1188 $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
1192 public static function provider_testStreamFile() {
1195 $base = self
::baseStorePath();
1196 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
1197 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
1203 * @dataProvider provider_testGetFileContents
1204 * @covers FileBackend::getFileContents
1205 * @covers FileBackend::getFileContentsMulti
1207 public function testGetFileContents( $source, $content ) {
1208 $this->backend
= $this->singleBackend
;
1209 $this->tearDownFiles();
1210 $this->doTestGetFileContents( $source, $content );
1211 $this->tearDownFiles();
1213 $this->backend
= $this->multiBackend
;
1214 $this->tearDownFiles();
1215 $this->doTestGetFileContents( $source, $content );
1216 $this->tearDownFiles();
1219 private function doTestGetFileContents( $source, $content ) {
1220 $backendName = $this->backendClass();
1222 $srcs = (array)$source;
1223 $content = (array)$content;
1224 foreach ( $srcs as $i => $src ) {
1225 $this->prepare( array( 'dir' => dirname( $src ) ) );
1226 $status = $this->backend
->doOperation(
1227 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1228 $this->assertGoodStatus( $status,
1229 "Creation of file at $src succeeded ($backendName)." );
1232 if ( is_array( $source ) ) {
1233 $contents = $this->backend
->getFileContentsMulti( array( 'srcs' => $source ) );
1234 foreach ( $contents as $path => $data ) {
1235 $this->assertNotEquals( false, $data, "Contents of $path exists ($backendName)." );
1236 $this->assertEquals( current( $content ), $data, "Contents of $path is correct ($backendName)." );
1239 $this->assertEquals( $source, array_keys( $contents ), "Contents in right order ($backendName)." );
1240 $this->assertEquals( count( $source ), count( $contents ), "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( current( $content ), $contents, "Local copy of $path is correct ($backendName)." );
1302 $this->assertEquals( $source, array_keys( $tmpFiles ), "Local copies in right order ($backendName)." );
1303 $this->assertEquals( count( $source ), count( $tmpFiles ), "Local copies array size correct ($backendName)." );
1305 $tmpFile = $this->backend
->getLocalCopy( array( 'src' => $source ) );
1306 $this->assertNotNull( $tmpFile,
1307 "Creation of local copy of $source succeeded ($backendName)." );
1308 $contents = file_get_contents( $tmpFile->getPath() );
1309 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
1310 $this->assertEquals( $content[0], $contents, "Local copy of $source is correct ($backendName)." );
1313 $obj = new stdClass();
1314 $tmpFile->bind( $obj );
1317 public static function provider_testGetLocalCopy() {
1320 $base = self
::baseStorePath();
1321 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1322 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1323 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1325 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1326 "$base/unittest-cont1/e/a/z.txt" ),
1327 array( "contents xx $", "contents xy 111", "contents xz" )
1334 * @dataProvider provider_testGetLocalReference
1335 * @covers FileBackend::getLocalReference
1337 public function testGetLocalReference( $source, $content ) {
1338 $this->backend
= $this->singleBackend
;
1339 $this->tearDownFiles();
1340 $this->doTestGetLocalReference( $source, $content );
1341 $this->tearDownFiles();
1343 $this->backend
= $this->multiBackend
;
1344 $this->tearDownFiles();
1345 $this->doTestGetLocalReference( $source, $content );
1346 $this->tearDownFiles();
1349 private function doTestGetLocalReference( $source, $content ) {
1350 $backendName = $this->backendClass();
1352 $srcs = (array)$source;
1353 $content = (array)$content;
1354 foreach ( $srcs as $i => $src ) {
1355 $this->prepare( array( 'dir' => dirname( $src ) ) );
1356 $status = $this->backend
->doOperation(
1357 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1358 $this->assertGoodStatus( $status,
1359 "Creation of file at $src succeeded ($backendName)." );
1362 if ( is_array( $source ) ) {
1363 $tmpFiles = $this->backend
->getLocalReferenceMulti( array( 'srcs' => $source ) );
1364 foreach ( $tmpFiles as $path => $tmpFile ) {
1365 $this->assertNotNull( $tmpFile,
1366 "Creation of local copy of $path succeeded ($backendName)." );
1367 $contents = file_get_contents( $tmpFile->getPath() );
1368 $this->assertNotEquals( false, $contents, "Local ref of $path exists ($backendName)." );
1369 $this->assertEquals( current( $content ), $contents, "Local ref of $path is correct ($backendName)." );
1372 $this->assertEquals( $source, array_keys( $tmpFiles ), "Local refs in right order ($backendName)." );
1373 $this->assertEquals( count( $source ), count( $tmpFiles ), "Local refs array size correct ($backendName)." );
1375 $tmpFile = $this->backend
->getLocalReference( array( 'src' => $source ) );
1376 $this->assertNotNull( $tmpFile,
1377 "Creation of local copy of $source succeeded ($backendName)." );
1378 $contents = file_get_contents( $tmpFile->getPath() );
1379 $this->assertNotEquals( false, $contents, "Local ref of $source exists ($backendName)." );
1380 $this->assertEquals( $content[0], $contents, "Local ref of $source is correct ($backendName)." );
1384 public static function provider_testGetLocalReference() {
1387 $base = self
::baseStorePath();
1388 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1389 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1390 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1392 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1393 "$base/unittest-cont1/e/a/z.txt" ),
1394 array( "contents xx 1111", "contents xy %", "contents xz $" )
1401 * @covers FileBackend::getLocalCopy
1402 * @covers FileBackend::getLocalReference
1404 public function testGetLocalCopyAndReference404() {
1405 $this->backend
= $this->singleBackend
;
1406 $this->tearDownFiles();
1407 $this->doTestGetLocalCopyAndReference404();
1408 $this->tearDownFiles();
1410 $this->backend
= $this->multiBackend
;
1411 $this->tearDownFiles();
1412 $this->doTestGetLocalCopyAndReference404();
1413 $this->tearDownFiles();
1416 public function doTestGetLocalCopyAndReference404() {
1417 $backendName = $this->backendClass();
1419 $base = self
::baseStorePath();
1421 $tmpFile = $this->backend
->getLocalCopy( array(
1422 'src' => "$base/unittest-cont1/not-there" ) );
1423 $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
1425 $tmpFile = $this->backend
->getLocalReference( array(
1426 'src' => "$base/unittest-cont1/not-there" ) );
1427 $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
1431 * @dataProvider provider_testGetFileHttpUrl
1432 * @covers FileBackend::getFileHttpUrl
1434 public function testGetFileHttpUrl( $source, $content ) {
1435 $this->backend
= $this->singleBackend
;
1436 $this->tearDownFiles();
1437 $this->doTestGetFileHttpUrl( $source, $content );
1438 $this->tearDownFiles();
1440 $this->backend
= $this->multiBackend
;
1441 $this->tearDownFiles();
1442 $this->doTestGetFileHttpUrl( $source, $content );
1443 $this->tearDownFiles();
1446 private function doTestGetFileHttpUrl( $source, $content ) {
1447 $backendName = $this->backendClass();
1449 $this->prepare( array( 'dir' => dirname( $source ) ) );
1450 $status = $this->backend
->doOperation(
1451 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
1452 $this->assertGoodStatus( $status,
1453 "Creation of file at $source succeeded ($backendName)." );
1455 $url = $this->backend
->getFileHttpUrl( array( 'src' => $source ) );
1457 if ( $url !== null ) { // supported
1458 $data = Http
::request( "GET", $url );
1459 $this->assertEquals( $content, $data,
1460 "HTTP GET of URL has right contents ($backendName)." );
1464 public static function provider_testGetFileHttpUrl() {
1467 $base = self
::baseStorePath();
1468 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1469 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1470 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1476 * @dataProvider provider_testPrepareAndClean
1477 * @covers FileBackend::prepare
1478 * @covers FileBackend::clean
1480 public function testPrepareAndClean( $path, $isOK ) {
1481 $this->backend
= $this->singleBackend
;
1482 $this->doTestPrepareAndClean( $path, $isOK );
1483 $this->tearDownFiles();
1485 $this->backend
= $this->multiBackend
;
1486 $this->doTestPrepareAndClean( $path, $isOK );
1487 $this->tearDownFiles();
1490 public static function provider_testPrepareAndClean() {
1491 $base = self
::baseStorePath();
1494 array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
1495 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
1496 # Specific to FS backend with no basePath field set
1497 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
1501 private function doTestPrepareAndClean( $path, $isOK ) {
1502 $backendName = $this->backendClass();
1504 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
1506 $this->assertGoodStatus( $status,
1507 "Preparing dir $path succeeded without warnings ($backendName)." );
1508 $this->assertEquals( true, $status->isOK(),
1509 "Preparing dir $path succeeded ($backendName)." );
1511 $this->assertEquals( false, $status->isOK(),
1512 "Preparing dir $path failed ($backendName)." );
1515 $status = $this->backend
->secure( array( 'dir' => dirname( $path ) ) );
1517 $this->assertGoodStatus( $status,
1518 "Securing dir $path succeeded without warnings ($backendName)." );
1519 $this->assertEquals( true, $status->isOK(),
1520 "Securing dir $path succeeded ($backendName)." );
1522 $this->assertEquals( false, $status->isOK(),
1523 "Securing dir $path failed ($backendName)." );
1526 $status = $this->backend
->publish( array( 'dir' => dirname( $path ) ) );
1528 $this->assertGoodStatus( $status,
1529 "Publishing dir $path succeeded without warnings ($backendName)." );
1530 $this->assertEquals( true, $status->isOK(),
1531 "Publishing dir $path succeeded ($backendName)." );
1533 $this->assertEquals( false, $status->isOK(),
1534 "Publishing dir $path failed ($backendName)." );
1537 $status = $this->backend
->clean( array( 'dir' => dirname( $path ) ) );
1539 $this->assertGoodStatus( $status,
1540 "Cleaning dir $path succeeded without warnings ($backendName)." );
1541 $this->assertEquals( true, $status->isOK(),
1542 "Cleaning dir $path succeeded ($backendName)." );
1544 $this->assertEquals( false, $status->isOK(),
1545 "Cleaning dir $path failed ($backendName)." );
1549 public function testRecursiveClean() {
1550 $this->backend
= $this->singleBackend
;
1551 $this->doTestRecursiveClean();
1552 $this->tearDownFiles();
1554 $this->backend
= $this->multiBackend
;
1555 $this->doTestRecursiveClean();
1556 $this->tearDownFiles();
1560 * @covers FileBackend::clean
1562 private function doTestRecursiveClean() {
1563 $backendName = $this->backendClass();
1565 $base = self
::baseStorePath();
1567 "$base/unittest-cont1",
1568 "$base/unittest-cont1/e",
1569 "$base/unittest-cont1/e/a",
1570 "$base/unittest-cont1/e/a/b",
1571 "$base/unittest-cont1/e/a/b/c",
1572 "$base/unittest-cont1/e/a/b/c/d0",
1573 "$base/unittest-cont1/e/a/b/c/d1",
1574 "$base/unittest-cont1/e/a/b/c/d2",
1575 "$base/unittest-cont1/e/a/b/c/d0/1",
1576 "$base/unittest-cont1/e/a/b/c/d0/2",
1577 "$base/unittest-cont1/e/a/b/c/d1/3",
1578 "$base/unittest-cont1/e/a/b/c/d1/4",
1579 "$base/unittest-cont1/e/a/b/c/d2/5",
1580 "$base/unittest-cont1/e/a/b/c/d2/6"
1582 foreach ( $dirs as $dir ) {
1583 $status = $this->prepare( array( 'dir' => $dir ) );
1584 $this->assertGoodStatus( $status,
1585 "Preparing dir $dir succeeded without warnings ($backendName)." );
1588 if ( $this->backend
instanceof FSFileBackend
) {
1589 foreach ( $dirs as $dir ) {
1590 $this->assertEquals( true, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1591 "Dir $dir exists ($backendName)." );
1595 $status = $this->backend
->clean(
1596 array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
1597 $this->assertGoodStatus( $status,
1598 "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
1600 foreach ( $dirs as $dir ) {
1601 $this->assertEquals( false, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1602 "Dir $dir no longer exists ($backendName)." );
1607 * @covers FileBackend::doOperations
1609 public function testDoOperations() {
1610 $this->backend
= $this->singleBackend
;
1611 $this->tearDownFiles();
1612 $this->doTestDoOperations();
1613 $this->tearDownFiles();
1615 $this->backend
= $this->multiBackend
;
1616 $this->tearDownFiles();
1617 $this->doTestDoOperations();
1618 $this->tearDownFiles();
1621 private function doTestDoOperations() {
1622 $base = self
::baseStorePath();
1624 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1625 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1626 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1627 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1628 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1629 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1630 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1632 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1633 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1634 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1635 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1636 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1637 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1638 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1640 $status = $this->backend
->doOperations( array(
1641 array( 'op' => 'describe', 'src' => $fileA,
1642 'headers' => array( 'X-Content-Length' => '91.3' ), 'disposition' => 'inline' ),
1643 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1644 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1645 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1646 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1647 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1648 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1649 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1650 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1651 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1652 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1653 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1654 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1655 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1656 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1657 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1658 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1659 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1661 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1663 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1665 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1667 array( 'op' => 'null' ),
1671 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1672 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1673 $this->assertEquals( 14, count( $status->success
),
1674 "Operation batch has correct success array" );
1676 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1677 "File does not exist at $fileA" );
1678 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1679 "File does not exist at $fileB" );
1680 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1681 "File does not exist at $fileD" );
1683 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1684 "File exists at $fileC" );
1685 $this->assertEquals( $fileBContents,
1686 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1687 "Correct file contents of $fileC" );
1688 $this->assertEquals( strlen( $fileBContents ),
1689 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1690 "Correct file size of $fileC" );
1691 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1692 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1693 "Correct file SHA-1 of $fileC" );
1697 * @covers FileBackend::doOperations
1699 public function testDoOperationsPipeline() {
1700 $this->backend
= $this->singleBackend
;
1701 $this->tearDownFiles();
1702 $this->doTestDoOperationsPipeline();
1703 $this->tearDownFiles();
1705 $this->backend
= $this->multiBackend
;
1706 $this->tearDownFiles();
1707 $this->doTestDoOperationsPipeline();
1708 $this->tearDownFiles();
1711 // concurrency orientated
1712 private function doTestDoOperationsPipeline() {
1713 $base = self
::baseStorePath();
1715 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1716 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1717 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1719 $tmpNameA = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1720 file_put_contents( $tmpNameA, $fileAContents );
1721 $tmpNameB = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1722 file_put_contents( $tmpNameB, $fileBContents );
1723 $tmpNameC = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1724 file_put_contents( $tmpNameC, $fileCContents );
1726 $this->filesToPrune
[] = $tmpNameA; # avoid file leaking
1727 $this->filesToPrune
[] = $tmpNameB; # avoid file leaking
1728 $this->filesToPrune
[] = $tmpNameC; # avoid file leaking
1730 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1731 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1732 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1733 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1735 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1736 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1737 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1738 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1739 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1741 $status = $this->backend
->doOperations( array(
1742 array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
1743 array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
1744 array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
1745 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1746 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1747 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1748 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1749 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1750 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1751 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1752 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1753 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1754 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1755 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1756 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1757 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1758 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1759 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1760 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1761 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1763 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1765 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1767 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1769 array( 'op' => 'null' ),
1773 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1774 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1775 $this->assertEquals( 16, count( $status->success
),
1776 "Operation batch has correct success array" );
1778 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1779 "File does not exist at $fileA" );
1780 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1781 "File does not exist at $fileB" );
1782 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1783 "File does not exist at $fileD" );
1785 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1786 "File exists at $fileC" );
1787 $this->assertEquals( $fileBContents,
1788 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1789 "Correct file contents of $fileC" );
1790 $this->assertEquals( strlen( $fileBContents ),
1791 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1792 "Correct file size of $fileC" );
1793 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1794 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1795 "Correct file SHA-1 of $fileC" );
1799 * @covers FileBackend::doOperations
1801 public function testDoOperationsFailing() {
1802 $this->backend
= $this->singleBackend
;
1803 $this->tearDownFiles();
1804 $this->doTestDoOperationsFailing();
1805 $this->tearDownFiles();
1807 $this->backend
= $this->multiBackend
;
1808 $this->tearDownFiles();
1809 $this->doTestDoOperationsFailing();
1810 $this->tearDownFiles();
1813 private function doTestDoOperationsFailing() {
1814 $base = self
::baseStorePath();
1816 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
1817 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1818 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
1819 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1820 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
1821 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1822 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
1824 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1825 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1826 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1827 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1828 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1829 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1831 $status = $this->backend
->doOperations( array(
1832 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1833 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1834 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1835 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1836 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
1837 // Now: A:<A>, B:<B>, C:<A>, D:<B>
1838 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
1839 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1840 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
1841 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1842 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
1843 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1844 array( 'op' => 'delete', 'src' => $fileD ),
1845 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1846 array( 'op' => 'null' ),
1848 ), array( 'force' => 1 ) );
1850 $this->assertNotEquals( array(), $status->errors
, "Operation had warnings" );
1851 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1852 $this->assertEquals( 8, count( $status->success
),
1853 "Operation batch has correct success array" );
1855 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1856 "File does not exist at $fileB" );
1857 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1858 "File does not exist at $fileD" );
1860 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1861 "File does not exist at $fileA" );
1862 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1863 "File exists at $fileC" );
1864 $this->assertEquals( $fileBContents,
1865 $this->backend
->getFileContents( array( 'src' => $fileA ) ),
1866 "Correct file contents of $fileA" );
1867 $this->assertEquals( strlen( $fileBContents ),
1868 $this->backend
->getFileSize( array( 'src' => $fileA ) ),
1869 "Correct file size of $fileA" );
1870 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1871 $this->backend
->getFileSha1Base36( array( 'src' => $fileA ) ),
1872 "Correct file SHA-1 of $fileA" );
1876 * @covers FileBackend::getFileList
1878 public function testGetFileList() {
1879 $this->backend
= $this->singleBackend
;
1880 $this->tearDownFiles();
1881 $this->doTestGetFileList();
1882 $this->tearDownFiles();
1884 $this->backend
= $this->multiBackend
;
1885 $this->tearDownFiles();
1886 $this->doTestGetFileList();
1887 $this->tearDownFiles();
1890 private function doTestGetFileList() {
1891 $backendName = $this->backendClass();
1892 $base = self
::baseStorePath();
1894 // Should have no errors
1895 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
1898 "$base/unittest-cont1/e/test1.txt",
1899 "$base/unittest-cont1/e/test2.txt",
1900 "$base/unittest-cont1/e/test3.txt",
1901 "$base/unittest-cont1/e/subdir1/test1.txt",
1902 "$base/unittest-cont1/e/subdir1/test2.txt",
1903 "$base/unittest-cont1/e/subdir2/test3.txt",
1904 "$base/unittest-cont1/e/subdir2/test4.txt",
1905 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
1906 "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
1907 "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
1908 "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
1909 "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
1910 "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
1911 "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
1916 foreach ( $files as $file ) {
1917 $this->prepare( array( 'dir' => dirname( $file ) ) );
1918 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1920 $status = $this->backend
->doQuickOperations( $ops );
1921 $this->assertGoodStatus( $status,
1922 "Creation of files succeeded ($backendName)." );
1923 $this->assertEquals( true, $status->isOK(),
1924 "Creation of files succeeded with OK status ($backendName)." );
1926 // Expected listing at root
1931 "e/subdir1/test1.txt",
1932 "e/subdir1/test2.txt",
1933 "e/subdir2/test3.txt",
1934 "e/subdir2/test4.txt",
1935 "e/subdir2/subdir/test1.txt",
1936 "e/subdir2/subdir/test2.txt",
1937 "e/subdir2/subdir/test3.txt",
1938 "e/subdir2/subdir/test4.txt",
1939 "e/subdir2/subdir/test5.txt",
1940 "e/subdir2/subdir/sub/test0.txt",
1941 "e/subdir2/subdir/sub/120-px-file.txt",
1945 // Actual listing (no trailing slash) at root
1946 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1947 $list = $this->listToArray( $iter );
1949 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1951 // Actual listing (no trailing slash) at root with advise
1952 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1", 'adviseStat' => 1 ) );
1953 $list = $this->listToArray( $iter );
1955 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1957 // Actual listing (with trailing slash) at root
1959 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1960 foreach ( $iter as $file ) {
1964 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1966 // Expected listing at subdir
1974 "sub/120-px-file.txt",
1978 // Actual listing (no trailing slash) at subdir
1979 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
1980 $list = $this->listToArray( $iter );
1982 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1984 // Actual listing (no trailing slash) at subdir with advise
1985 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir", 'adviseStat' => 1 ) );
1986 $list = $this->listToArray( $iter );
1988 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1990 // Actual listing (with trailing slash) at subdir
1992 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
1993 foreach ( $iter as $file ) {
1997 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1999 // Actual listing (using iterator second time)
2000 $list = $this->listToArray( $iter );
2002 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
2004 // Actual listing (top files only) at root
2005 $iter = $this->backend
->getTopFileList( array( 'dir' => "$base/unittest-cont1" ) );
2006 $list = $this->listToArray( $iter );
2008 $this->assertEquals( array(), $list, "Correct top file listing ($backendName)." );
2010 // Expected listing (top files only) at subdir
2020 // Actual listing (top files only) at subdir
2021 $iter = $this->backend
->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
2022 $list = $this->listToArray( $iter );
2024 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
2026 // Actual listing (top files only) at subdir with advise
2027 $iter = $this->backend
->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir", 'adviseStat' => 1 ) );
2028 $list = $this->listToArray( $iter );
2030 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
2032 foreach ( $files as $file ) { // clean up
2033 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
2036 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
2037 foreach ( $iter as $iter ) {
2043 * @covers FileBackend::getTopDirectoryList
2044 * @covers FileBackend::getDirectoryList
2046 public function testGetDirectoryList() {
2047 $this->backend
= $this->singleBackend
;
2048 $this->tearDownFiles();
2049 $this->doTestGetDirectoryList();
2050 $this->tearDownFiles();
2052 $this->backend
= $this->multiBackend
;
2053 $this->tearDownFiles();
2054 $this->doTestGetDirectoryList();
2055 $this->tearDownFiles();
2058 private function doTestGetDirectoryList() {
2059 $backendName = $this->backendClass();
2061 $base = self
::baseStorePath();
2063 "$base/unittest-cont1/e/test1.txt",
2064 "$base/unittest-cont1/e/test2.txt",
2065 "$base/unittest-cont1/e/test3.txt",
2066 "$base/unittest-cont1/e/subdir1/test1.txt",
2067 "$base/unittest-cont1/e/subdir1/test2.txt",
2068 "$base/unittest-cont1/e/subdir2/test3.txt",
2069 "$base/unittest-cont1/e/subdir2/test4.txt",
2070 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
2071 "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
2072 "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
2073 "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
2074 "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
2075 "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
2076 "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
2081 foreach ( $files as $file ) {
2082 $this->prepare( array( 'dir' => dirname( $file ) ) );
2083 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
2085 $status = $this->backend
->doQuickOperations( $ops );
2086 $this->assertGoodStatus( $status,
2087 "Creation of files succeeded ($backendName)." );
2088 $this->assertEquals( true, $status->isOK(),
2089 "Creation of files succeeded with OK status ($backendName)." );
2091 $this->assertEquals( true,
2092 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
2093 "Directory exists in ($backendName)." );
2094 $this->assertEquals( true,
2095 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
2096 "Directory exists in ($backendName)." );
2097 $this->assertEquals( false,
2098 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
2099 "Directory does not exists in ($backendName)." );
2107 // Actual listing (no trailing slash)
2109 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
2110 foreach ( $iter as $file ) {
2115 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2126 // Actual listing (no trailing slash)
2128 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
2129 foreach ( $iter as $file ) {
2134 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2136 // Actual listing (with trailing slash)
2138 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
2139 foreach ( $iter as $file ) {
2144 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2152 // Actual listing (no trailing slash)
2154 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
2155 foreach ( $iter as $file ) {
2160 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2162 // Actual listing (with trailing slash)
2164 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2/" ) );
2165 foreach ( $iter as $file ) {
2170 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2172 // Actual listing (using iterator second time)
2174 foreach ( $iter as $file ) {
2179 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
2181 // Expected listing (recursive)
2191 "e/subdir4/subdir/sub",
2195 // Actual listing (recursive)
2197 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
2198 foreach ( $iter as $file ) {
2203 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2205 // Expected listing (recursive)
2212 // Actual listing (recursive)
2214 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
2215 foreach ( $iter as $file ) {
2220 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2222 // Actual listing (recursive, second time)
2224 foreach ( $iter as $file ) {
2229 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2231 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) );
2232 $items = $this->listToArray( $iter );
2233 $this->assertEquals( array(), $items, "Directory listing is empty." );
2235 foreach ( $files as $file ) { // clean up
2236 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
2239 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
2240 foreach ( $iter as $file ) {
2244 $items = $this->listToArray( $iter );
2245 $this->assertEquals( array(), $items, "Directory listing is empty." );
2247 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/not/exists" ) );
2248 $items = $this->listToArray( $iter );
2249 $this->assertEquals( array(), $items, "Directory listing is empty." );
2253 * @covers FileBackend::lockFiles
2254 * @covers FileBackend::unlockFiles
2256 public function testLockCalls() {
2257 $this->backend
= $this->singleBackend
;
2258 $this->doTestLockCalls();
2261 private function doTestLockCalls() {
2262 $backendName = $this->backendClass();
2269 "subdir1", // duplicate
2270 "subdir1/test1.txt",
2271 "subdir1/test2.txt",
2273 "subdir2", // duplicate
2274 "subdir2/test3.txt",
2275 "subdir2/test4.txt",
2277 "subdir2/subdir/test1.txt",
2278 "subdir2/subdir/test2.txt",
2279 "subdir2/subdir/test3.txt",
2280 "subdir2/subdir/test4.txt",
2281 "subdir2/subdir/test5.txt",
2282 "subdir2/subdir/sub",
2283 "subdir2/subdir/sub/test0.txt",
2284 "subdir2/subdir/sub/120-px-file.txt",
2287 for ( $i = 0; $i < 25; $i++
) {
2288 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_EX
);
2289 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2290 "Locking of files succeeded ($backendName) ($i)." );
2291 $this->assertEquals( true, $status->isOK(),
2292 "Locking of files succeeded with OK status ($backendName) ($i)." );
2294 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_SH
);
2295 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2296 "Locking of files succeeded ($backendName) ($i)." );
2297 $this->assertEquals( true, $status->isOK(),
2298 "Locking of files succeeded with OK status ($backendName) ($i)." );
2300 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_SH
);
2301 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2302 "Locking of files succeeded ($backendName) ($i)." );
2303 $this->assertEquals( true, $status->isOK(),
2304 "Locking of files succeeded with OK status ($backendName) ($i)." );
2306 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_EX
);
2307 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2308 "Locking of files succeeded ($backendName). ($i)" );
2309 $this->assertEquals( true, $status->isOK(),
2310 "Locking of files succeeded with OK status ($backendName) ($i)." );
2312 ## Flip the acquire/release ordering around ##
2314 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_SH
);
2315 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2316 "Locking of files succeeded ($backendName) ($i)." );
2317 $this->assertEquals( true, $status->isOK(),
2318 "Locking of files succeeded with OK status ($backendName) ($i)." );
2320 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_EX
);
2321 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2322 "Locking of files succeeded ($backendName) ($i)." );
2323 $this->assertEquals( true, $status->isOK(),
2324 "Locking of files succeeded with OK status ($backendName) ($i)." );
2326 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_EX
);
2327 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2328 "Locking of files succeeded ($backendName). ($i)" );
2329 $this->assertEquals( true, $status->isOK(),
2330 "Locking of files succeeded with OK status ($backendName) ($i)." );
2332 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_SH
);
2333 $this->assertEquals( print_r( array(), true ), print_r( $status->errors
, true ),
2334 "Locking of files succeeded ($backendName) ($i)." );
2335 $this->assertEquals( true, $status->isOK(),
2336 "Locking of files succeeded with OK status ($backendName) ($i)." );
2339 $status = Status
::newGood();
2340 $sl = $this->backend
->getScopedFileLocks( $paths, LockManager
::LOCK_EX
, $status );
2341 $this->assertType( 'ScopedLock', $sl,
2342 "Scoped locking of files succeeded ($backendName)." );
2343 $this->assertEquals( array(), $status->errors
,
2344 "Scoped locking of files succeeded ($backendName)." );
2345 $this->assertEquals( true, $status->isOK(),
2346 "Scoped locking of files succeeded with OK status ($backendName)." );
2348 ScopedLock
::release( $sl );
2349 $this->assertEquals( null, $sl,
2350 "Scoped unlocking of files succeeded ($backendName)." );
2351 $this->assertEquals( array(), $status->errors
,
2352 "Scoped unlocking of files succeeded ($backendName)." );
2353 $this->assertEquals( true, $status->isOK(),
2354 "Scoped unlocking of files succeeded with OK status ($backendName)." );
2358 private function listToArray( $iter ) {
2359 return is_array( $iter ) ?
$iter : iterator_to_array( $iter );
2362 // test helper wrapper for backend prepare() function
2363 private function prepare( array $params ) {
2364 return $this->backend
->prepare( $params );
2367 // test helper wrapper for backend prepare() function
2368 private function create( array $params ) {
2369 $params['op'] = 'create';
2371 return $this->backend
->doQuickOperations( array( $params ) );
2374 function tearDownFiles() {
2375 foreach ( $this->filesToPrune
as $file ) {
2376 if ( is_file( $file ) ) {
2380 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont-bad' );
2381 foreach ( $containers as $container ) {
2382 $this->deleteFiles( $container );
2384 $this->filesToPrune
= array();
2387 private function deleteFiles( $container ) {
2388 $base = self
::baseStorePath();
2389 $iter = $this->backend
->getFileList( array( 'dir' => "$base/$container" ) );
2391 foreach ( $iter as $file ) {
2392 $this->backend
->quickDelete( array( 'src' => "$base/$container/$file" ) );
2394 // free the directory, to avoid Permission denied under windows on rmdir
2397 $this->backend
->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
2400 function assertBackendPathsConsistent( array $paths ) {
2401 if ( $this->backend
instanceof FileBackendMultiWrite
) {
2402 $status = $this->backend
->consistencyCheck( $paths );
2403 $this->assertGoodStatus( $status, "Files synced: " . implode( ',', $paths ) );
2407 function assertGoodStatus( $status, $msg ) {
2408 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors
, 1 ), $msg );