7 class FileBackendTest
extends MediaWikiTestCase
{
8 private $backend, $multiBackend;
9 private $filesToPrune = array();
10 private static $backendToUse;
13 global $wgFileBackends;
15 $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand();
16 if ( $this->getCliArg( 'use-filebackend=' ) ) {
17 if ( self
::$backendToUse ) {
18 $this->singleBackend
= self
::$backendToUse;
20 $name = $this->getCliArg( 'use-filebackend=' );
22 foreach ( $wgFileBackends as $conf ) {
23 if ( $conf['name'] == $name ) {
28 $useConfig['name'] = 'localtesting'; // swap name
29 $useConfig['shardViaHashLevels'] = array( // test sharding
30 'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
32 $class = $useConfig['class'];
33 self
::$backendToUse = new $class( $useConfig );
34 $this->singleBackend
= self
::$backendToUse;
37 $this->singleBackend
= new FSFileBackend( array(
38 'name' => 'localtesting',
39 'lockManager' => 'fsLockManager',
40 #'parallelize' => 'implicit',
41 'containerPaths' => array(
42 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
43 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
46 $this->multiBackend
= new FileBackendMultiWrite( array(
47 'name' => 'localtesting',
48 'lockManager' => 'fsLockManager',
49 'parallelize' => 'implicit',
52 'name' => 'localmutlitesting1',
53 'class' => 'FSFileBackend',
54 'lockManager' => 'nullLockManager',
55 'containerPaths' => array(
56 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
57 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
58 'isMultiMaster' => false
61 'name' => 'localmutlitesting2',
62 'class' => 'FSFileBackend',
63 'lockManager' => 'nullLockManager',
64 'containerPaths' => array(
65 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
66 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
67 'isMultiMaster' => true
71 $this->filesToPrune
= array();
74 private function baseStorePath() {
75 return 'mwstore://localtesting';
78 private function backendClass() {
79 return get_class( $this->backend
);
83 * @dataProvider provider_testIsStoragePath
85 public function testIsStoragePath( $path, $isStorePath ) {
86 $this->assertEquals( $isStorePath, FileBackend
::isStoragePath( $path ),
87 "FileBackend::isStoragePath on path '$path'" );
90 function provider_testIsStoragePath() {
92 array( 'mwstore://', true ),
93 array( 'mwstore://backend', true ),
94 array( 'mwstore://backend/container', true ),
95 array( 'mwstore://backend/container/', true ),
96 array( 'mwstore://backend/container/path', true ),
97 array( 'mwstore://backend//container/', true ),
98 array( 'mwstore://backend//container//', true ),
99 array( 'mwstore://backend//container//path', true ),
100 array( 'mwstore:///', true ),
101 array( 'mwstore:/', false ),
102 array( 'mwstore:', false ),
107 * @dataProvider provider_testSplitStoragePath
109 public function testSplitStoragePath( $path, $res ) {
110 $this->assertEquals( $res, FileBackend
::splitStoragePath( $path ),
111 "FileBackend::splitStoragePath on path '$path'" );
114 function provider_testSplitStoragePath() {
116 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
117 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
118 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
119 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
120 array( 'mwstore://backend//container/path', array( null, null, null ) ),
121 array( 'mwstore://backend//container//path', array( null, null, null ) ),
122 array( 'mwstore://', array( null, null, null ) ),
123 array( 'mwstore://backend', array( null, null, null ) ),
124 array( 'mwstore:///', array( null, null, null ) ),
125 array( 'mwstore:/', array( null, null, null ) ),
126 array( 'mwstore:', array( null, null, null ) )
131 * @dataProvider provider_normalizeStoragePath
133 public function testNormalizeStoragePath( $path, $res ) {
134 $this->assertEquals( $res, FileBackend
::normalizeStoragePath( $path ),
135 "FileBackend::normalizeStoragePath on path '$path'" );
138 function provider_normalizeStoragePath() {
140 array( 'mwstore://backend/container', 'mwstore://backend/container' ),
141 array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
142 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
143 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
144 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
145 array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj',
146 array( 'mwstore://', null ),
147 array( 'mwstore://backend', null ),
148 array( 'mwstore://backend//container/path', null ),
149 array( 'mwstore://backend//container//path', null ),
150 array( 'mwstore:///', null ),
151 array( 'mwstore:/', null ),
152 array( 'mwstore:', null ), )
157 * @dataProvider provider_testParentStoragePath
159 public function testParentStoragePath( $path, $res ) {
160 $this->assertEquals( $res, FileBackend
::parentStoragePath( $path ),
161 "FileBackend::parentStoragePath on path '$path'" );
164 function provider_testParentStoragePath() {
166 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
167 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
168 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
169 array( 'mwstore://backend/container', null ),
170 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
171 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
172 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
173 array( 'mwstore://backend/container/', null ),
178 * @dataProvider provider_testExtensionFromPath
180 public function testExtensionFromPath( $path, $res ) {
181 $this->assertEquals( $res, FileBackend
::extensionFromPath( $path ),
182 "FileBackend::extensionFromPath on path '$path'" );
185 function provider_testExtensionFromPath() {
187 array( 'mwstore://backend/container/path.txt', 'txt' ),
188 array( 'mwstore://backend/container/path.svg.png', 'png' ),
189 array( 'mwstore://backend/container/path', '' ),
190 array( 'mwstore://backend/container/path.', '' ),
195 * @dataProvider provider_testStore
197 public function testStore( $op ) {
198 $this->filesToPrune
[] = $op['src'];
200 $this->backend
= $this->singleBackend
;
201 $this->tearDownFiles();
202 $this->doTestStore( $op );
203 $this->tearDownFiles();
205 $this->backend
= $this->multiBackend
;
206 $this->tearDownFiles();
207 $this->doTestStore( $op );
208 $this->filesToPrune
[] = $op['src']; # avoid file leaking
209 $this->tearDownFiles();
212 private function doTestStore( $op ) {
213 $backendName = $this->backendClass();
215 $source = $op['src'];
217 $this->prepare( array( 'dir' => dirname( $dest ) ) );
219 file_put_contents( $source, "Unit test file" );
221 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
222 $this->backend
->store( $op );
225 $status = $this->backend
->doOperation( $op );
227 $this->assertGoodStatus( $status,
228 "Store from $source to $dest succeeded without warnings ($backendName)." );
229 $this->assertEquals( true, $status->isOK(),
230 "Store from $source to $dest succeeded ($backendName)." );
231 $this->assertEquals( array( 0 => true ), $status->success
,
232 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
233 $this->assertEquals( true, file_exists( $source ),
234 "Source file $source still exists ($backendName)." );
235 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
236 "Destination file $dest exists ($backendName)." );
238 $this->assertEquals( filesize( $source ),
239 $this->backend
->getFileSize( array( 'src' => $dest ) ),
240 "Destination file $dest has correct size ($backendName)." );
242 $props1 = FSFile
::getPropsFromPath( $source );
243 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
244 $this->assertEquals( $props1, $props2,
245 "Source and destination have the same props ($backendName)." );
248 public function provider_testStore() {
251 $tmpName = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
252 $toPath = $this->baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
253 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
261 $op2['overwrite'] = true;
269 $op2['overwriteSame'] = true;
280 * @dataProvider provider_testCopy
282 public function testCopy( $op ) {
283 $this->backend
= $this->singleBackend
;
284 $this->tearDownFiles();
285 $this->doTestCopy( $op );
286 $this->tearDownFiles();
288 $this->backend
= $this->multiBackend
;
289 $this->tearDownFiles();
290 $this->doTestCopy( $op );
291 $this->tearDownFiles();
294 private function doTestCopy( $op ) {
295 $backendName = $this->backendClass();
297 $source = $op['src'];
299 $this->prepare( array( 'dir' => dirname( $source ) ) );
300 $this->prepare( array( 'dir' => dirname( $dest ) ) );
302 $status = $this->backend
->doOperation(
303 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
304 $this->assertGoodStatus( $status,
305 "Creation of file at $source succeeded ($backendName)." );
307 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
308 $this->backend
->copy( $op );
311 $status = $this->backend
->doOperation( $op );
313 $this->assertGoodStatus( $status,
314 "Copy from $source to $dest succeeded without warnings ($backendName)." );
315 $this->assertEquals( true, $status->isOK(),
316 "Copy from $source to $dest succeeded ($backendName)." );
317 $this->assertEquals( array( 0 => true ), $status->success
,
318 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
319 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $source ) ),
320 "Source file $source still exists ($backendName)." );
321 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
322 "Destination file $dest exists after copy ($backendName)." );
325 $this->backend
->getFileSize( array( 'src' => $source ) ),
326 $this->backend
->getFileSize( array( 'src' => $dest ) ),
327 "Destination file $dest has correct size ($backendName)." );
329 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
330 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
331 $this->assertEquals( $props1, $props2,
332 "Source and destination have the same props ($backendName)." );
335 public function provider_testCopy() {
338 $source = $this->baseStorePath() . '/unittest-cont1/e/file.txt';
339 $dest = $this->baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
341 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
349 $op2['overwrite'] = true;
357 $op2['overwriteSame'] = true;
368 * @dataProvider provider_testMove
370 public function testMove( $op ) {
371 $this->backend
= $this->singleBackend
;
372 $this->tearDownFiles();
373 $this->doTestMove( $op );
374 $this->tearDownFiles();
376 $this->backend
= $this->multiBackend
;
377 $this->tearDownFiles();
378 $this->doTestMove( $op );
379 $this->tearDownFiles();
382 private function doTestMove( $op ) {
383 $backendName = $this->backendClass();
385 $source = $op['src'];
387 $this->prepare( array( 'dir' => dirname( $source ) ) );
388 $this->prepare( array( 'dir' => dirname( $dest ) ) );
390 $status = $this->backend
->doOperation(
391 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
392 $this->assertGoodStatus( $status,
393 "Creation of file at $source succeeded ($backendName)." );
395 if ( isset( $op['overwrite'] ) ||
isset( $op['overwriteSame'] ) ) {
396 $this->backend
->copy( $op );
399 $status = $this->backend
->doOperation( $op );
400 $this->assertGoodStatus( $status,
401 "Move from $source to $dest succeeded without warnings ($backendName)." );
402 $this->assertEquals( true, $status->isOK(),
403 "Move from $source to $dest succeeded ($backendName)." );
404 $this->assertEquals( array( 0 => true ), $status->success
,
405 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
406 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
407 "Source file $source does not still exists ($backendName)." );
408 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
409 "Destination file $dest exists after move ($backendName)." );
411 $this->assertNotEquals(
412 $this->backend
->getFileSize( array( 'src' => $source ) ),
413 $this->backend
->getFileSize( array( 'src' => $dest ) ),
414 "Destination file $dest has correct size ($backendName)." );
416 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
417 $props2 = $this->backend
->getFileProps( array( 'src' => $dest ) );
418 $this->assertEquals( false, $props1['fileExists'],
419 "Source file does not exist accourding to props ($backendName)." );
420 $this->assertEquals( true, $props2['fileExists'],
421 "Destination file exists accourding to props ($backendName)." );
424 public function provider_testMove() {
427 $source = $this->baseStorePath() . '/unittest-cont1/e/file.txt';
428 $dest = $this->baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
430 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
438 $op2['overwrite'] = true;
446 $op2['overwriteSame'] = true;
457 * @dataProvider provider_testDelete
459 public function testDelete( $op, $withSource, $okStatus ) {
460 $this->backend
= $this->singleBackend
;
461 $this->tearDownFiles();
462 $this->doTestDelete( $op, $withSource, $okStatus );
463 $this->tearDownFiles();
465 $this->backend
= $this->multiBackend
;
466 $this->tearDownFiles();
467 $this->doTestDelete( $op, $withSource, $okStatus );
468 $this->tearDownFiles();
471 private function doTestDelete( $op, $withSource, $okStatus ) {
472 $backendName = $this->backendClass();
474 $source = $op['src'];
475 $this->prepare( array( 'dir' => dirname( $source ) ) );
478 $status = $this->backend
->doOperation(
479 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
480 $this->assertGoodStatus( $status,
481 "Creation of file at $source succeeded ($backendName)." );
484 $status = $this->backend
->doOperation( $op );
486 $this->assertGoodStatus( $status,
487 "Deletion of file at $source succeeded without warnings ($backendName)." );
488 $this->assertEquals( true, $status->isOK(),
489 "Deletion of file at $source succeeded ($backendName)." );
490 $this->assertEquals( array( 0 => true ), $status->success
,
491 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
493 $this->assertEquals( false, $status->isOK(),
494 "Deletion of file at $source failed ($backendName)." );
497 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $source ) ),
498 "Source file $source does not exist after move ($backendName)." );
501 $this->backend
->getFileSize( array( 'src' => $source ) ),
502 "Source file $source has correct size (false) ($backendName)." );
504 $props1 = $this->backend
->getFileProps( array( 'src' => $source ) );
505 $this->assertFalse( $props1['fileExists'],
506 "Source file $source does not exist according to props ($backendName)." );
509 public function provider_testDelete() {
512 $source = $this->baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
514 $op = array( 'op' => 'delete', 'src' => $source );
523 false, // without source
527 $op['ignoreMissingSource'] = true;
530 false, // without source
538 * @dataProvider provider_testCreate
540 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
541 $this->backend
= $this->singleBackend
;
542 $this->tearDownFiles();
543 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
544 $this->tearDownFiles();
546 $this->backend
= $this->multiBackend
;
547 $this->tearDownFiles();
548 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
549 $this->tearDownFiles();
552 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
553 $backendName = $this->backendClass();
556 $this->prepare( array( 'dir' => dirname( $dest ) ) );
558 $oldText = 'blah...blah...waahwaah';
559 if ( $alreadyExists ) {
560 $status = $this->backend
->doOperation(
561 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
562 $this->assertGoodStatus( $status,
563 "Creation of file at $dest succeeded ($backendName)." );
566 $status = $this->backend
->doOperation( $op );
568 $this->assertGoodStatus( $status,
569 "Creation of file at $dest succeeded without warnings ($backendName)." );
570 $this->assertEquals( true, $status->isOK(),
571 "Creation of file at $dest succeeded ($backendName)." );
572 $this->assertEquals( array( 0 => true ), $status->success
,
573 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
575 $this->assertEquals( false, $status->isOK(),
576 "Creation of file at $dest failed ($backendName)." );
579 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $dest ) ),
580 "Destination file $dest exists after creation ($backendName)." );
582 $props1 = $this->backend
->getFileProps( array( 'src' => $dest ) );
583 $this->assertEquals( true, $props1['fileExists'],
584 "Destination file $dest exists according to props ($backendName)." );
585 if ( $okStatus ) { // file content is what we saved
586 $this->assertEquals( $newSize, $props1['size'],
587 "Destination file $dest has expected size according to props ($backendName)." );
588 $this->assertEquals( $newSize,
589 $this->backend
->getFileSize( array( 'src' => $dest ) ),
590 "Destination file $dest has correct size ($backendName)." );
591 } else { // file content is some other previous text
592 $this->assertEquals( strlen( $oldText ), $props1['size'],
593 "Destination file $dest has original size according to props ($backendName)." );
594 $this->assertEquals( strlen( $oldText ),
595 $this->backend
->getFileSize( array( 'src' => $dest ) ),
596 "Destination file $dest has original size according to props ($backendName)." );
601 * @dataProvider provider_testCreate
603 public function provider_testCreate() {
606 $dest = $this->baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
608 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
611 false, // no dest already exists
613 strlen( $op['content'] )
617 $op2['content'] = "\n";
620 false, // no dest already exists
622 strlen( $op2['content'] )
626 $op2['content'] = "fsf\n waf 3kt";
629 true, // dest already exists
631 strlen( $op2['content'] )
635 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
636 $op2['overwrite'] = true;
639 true, // dest already exists
641 strlen( $op2['content'] )
645 $op2['content'] = "39qjmg3-qg";
646 $op2['overwriteSame'] = true;
649 true, // dest already exists
651 strlen( $op2['content'] )
657 public function testDoQuickOperations() {
658 $this->backend
= $this->singleBackend
;
659 $this->doTestDoQuickOperations();
660 $this->tearDownFiles();
662 $this->backend
= $this->multiBackend
;
663 $this->doTestDoQuickOperations();
664 $this->tearDownFiles();
667 private function doTestDoQuickOperations() {
668 $backendName = $this->backendClass();
670 $base = $this->baseStorePath();
672 "$base/unittest-cont1/e/fileA.a",
673 "$base/unittest-cont1/e/fileB.a",
674 "$base/unittest-cont1/e/fileC.a"
678 foreach ( $files as $path ) {
679 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
680 $this->assertGoodStatus( $status,
681 "Preparing $path succeeded without warnings ($backendName)." );
682 $ops[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand(0,50000) );
683 $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
685 $purgeOps[] = array( 'op' => 'null' );
686 $status = $this->backend
->doQuickOperations( $ops );
687 $this->assertGoodStatus( $status,
688 "Creation of source files succeeded ($backendName)." );
690 foreach ( $files as $file ) {
691 $this->assertTrue( $this->backend
->fileExists( array( 'src' => $file ) ),
692 "File $file exists." );
695 $status = $this->backend
->doQuickOperations( $purgeOps );
696 $this->assertGoodStatus( $status,
697 "Quick deletion of source files succeeded ($backendName)." );
699 foreach ( $files as $file ) {
700 $this->assertFalse( $this->backend
->fileExists( array( 'src' => $file ) ),
701 "File $file purged." );
706 * @dataProvider provider_testConcatenate
708 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
709 $this->filesToPrune
[] = $op['dst'];
711 $this->backend
= $this->singleBackend
;
712 $this->tearDownFiles();
713 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
714 $this->tearDownFiles();
716 $this->backend
= $this->multiBackend
;
717 $this->tearDownFiles();
718 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
719 $this->filesToPrune
[] = $op['dst']; # avoid file leaking
720 $this->tearDownFiles();
723 private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
724 $backendName = $this->backendClass();
729 foreach ( $srcs as $i => $source ) {
730 $this->prepare( array( 'dir' => dirname( $source ) ) );
732 'op' => 'create', // operation
733 'dst' => $source, // source
734 'content' => $srcsContent[$i]
736 $expContent .= $srcsContent[$i];
738 $status = $this->backend
->doOperations( $ops );
740 $this->assertGoodStatus( $status,
741 "Creation of source files succeeded ($backendName)." );
743 $dest = $params['dst'];
744 if ( $alreadyExists ) {
745 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
746 $this->assertEquals( true, $ok,
747 "Creation of file at $dest succeeded ($backendName)." );
749 $ok = file_put_contents( $dest, '' ) !== false;
750 $this->assertEquals( true, $ok,
751 "Creation of 0-byte file at $dest succeeded ($backendName)." );
754 // Combine the files into one
755 $status = $this->backend
->concatenate( $params );
757 $this->assertGoodStatus( $status,
758 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
759 $this->assertEquals( true, $status->isOK(),
760 "Creation of concat file at $dest succeeded ($backendName)." );
762 $this->assertEquals( false, $status->isOK(),
763 "Creation of concat file at $dest failed ($backendName)." );
767 $this->assertEquals( true, is_file( $dest ),
768 "Dest concat file $dest exists after creation ($backendName)." );
770 $this->assertEquals( true, is_file( $dest ),
771 "Dest concat file $dest exists after failed creation ($backendName)." );
774 $contents = file_get_contents( $dest );
775 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
778 $this->assertEquals( $expContent, $contents,
779 "Concat file at $dest has correct contents ($backendName)." );
781 $this->assertNotEquals( $expContent, $contents,
782 "Concat file at $dest has correct contents ($backendName)." );
786 function provider_testConcatenate() {
789 $rand = mt_rand( 0, 2000000000 ) . time();
790 $dest = wfTempDir() . "/randomfile!$rand.txt";
792 $this->baseStorePath() . '/unittest-cont1/e/file1.txt',
793 $this->baseStorePath() . '/unittest-cont1/e/file2.txt',
794 $this->baseStorePath() . '/unittest-cont1/e/file3.txt',
795 $this->baseStorePath() . '/unittest-cont1/e/file4.txt',
796 $this->baseStorePath() . '/unittest-cont1/e/file5.txt',
797 $this->baseStorePath() . '/unittest-cont1/e/file6.txt',
798 $this->baseStorePath() . '/unittest-cont1/e/file7.txt',
799 $this->baseStorePath() . '/unittest-cont1/e/file8.txt',
800 $this->baseStorePath() . '/unittest-cont1/e/file9.txt',
801 $this->baseStorePath() . '/unittest-cont1/e/file10.txt'
815 $params = array( 'srcs' => $srcs, 'dst' => $dest );
818 $params, // operation
820 $content, // content for each source
821 false, // no dest already exists
826 $params, // operation
828 $content, // content for each source
829 true, // dest already exists
837 * @dataProvider provider_testGetFileStat
839 public function testGetFileStat( $path, $content, $alreadyExists ) {
840 $this->backend
= $this->singleBackend
;
841 $this->tearDownFiles();
842 $this->doTestGetFileStat( $path, $content, $alreadyExists );
843 $this->tearDownFiles();
845 $this->backend
= $this->multiBackend
;
846 $this->tearDownFiles();
847 $this->doTestGetFileStat( $path, $content, $alreadyExists );
848 $this->tearDownFiles();
851 private function doTestGetFileStat( $path, $content, $alreadyExists ) {
852 $backendName = $this->backendClass();
854 if ( $alreadyExists ) {
855 $this->prepare( array( 'dir' => dirname( $path ) ) );
856 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
857 $this->assertGoodStatus( $status,
858 "Creation of file at $path succeeded ($backendName)." );
860 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
861 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
862 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
864 $this->assertEquals( strlen( $content ), $size,
865 "Correct file size of '$path'" );
866 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
867 "Correct file timestamp of '$path'" );
869 $size = $stat['size'];
870 $time = $stat['mtime'];
871 $this->assertEquals( strlen( $content ), $size,
872 "Correct file size of '$path'" );
873 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX
, $time ) ) < 10,
874 "Correct file timestamp of '$path'" );
876 $size = $this->backend
->getFileSize( array( 'src' => $path ) );
877 $time = $this->backend
->getFileTimestamp( array( 'src' => $path ) );
878 $stat = $this->backend
->getFileStat( array( 'src' => $path ) );
880 $this->assertFalse( $size, "Correct file size of '$path'" );
881 $this->assertFalse( $time, "Correct file timestamp of '$path'" );
882 $this->assertFalse( $stat, "Correct file stat of '$path'" );
886 function provider_testGetFileStat() {
889 $base = $this->baseStorePath();
890 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
891 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
892 $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
898 * @dataProvider provider_testGetFileContents
900 public function testGetFileContents( $source, $content ) {
901 $this->backend
= $this->singleBackend
;
902 $this->tearDownFiles();
903 $this->doTestGetFileContents( $source, $content );
904 $this->tearDownFiles();
906 $this->backend
= $this->multiBackend
;
907 $this->tearDownFiles();
908 $this->doTestGetFileContents( $source, $content );
909 $this->tearDownFiles();
912 private function doTestGetFileContents( $source, $content ) {
913 $backendName = $this->backendClass();
915 $this->prepare( array( 'dir' => dirname( $source ) ) );
917 $status = $this->backend
->doOperation(
918 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
919 $this->assertGoodStatus( $status,
920 "Creation of file at $source succeeded ($backendName)." );
921 $this->assertEquals( true, $status->isOK(),
922 "Creation of file at $source succeeded with OK status ($backendName)." );
924 $newContents = $this->backend
->getFileContents( array( 'src' => $source, 'latest' => 1 ) );
925 $this->assertNotEquals( false, $newContents,
926 "Read of file at $source succeeded ($backendName)." );
928 $this->assertEquals( $content, $newContents,
929 "Contents read match data at $source ($backendName)." );
932 function provider_testGetFileContents() {
935 $base = $this->baseStorePath();
936 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
937 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
943 * @dataProvider provider_testGetLocalCopy
945 public function testGetLocalCopy( $source, $content ) {
946 $this->backend
= $this->singleBackend
;
947 $this->tearDownFiles();
948 $this->doTestGetLocalCopy( $source, $content );
949 $this->tearDownFiles();
951 $this->backend
= $this->multiBackend
;
952 $this->tearDownFiles();
953 $this->doTestGetLocalCopy( $source, $content );
954 $this->tearDownFiles();
957 private function doTestGetLocalCopy( $source, $content ) {
958 $backendName = $this->backendClass();
960 $this->prepare( array( 'dir' => dirname( $source ) ) );
962 $status = $this->backend
->doOperation(
963 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
964 $this->assertGoodStatus( $status,
965 "Creation of file at $source succeeded ($backendName)." );
967 $tmpFile = $this->backend
->getLocalCopy( array( 'src' => $source ) );
968 $this->assertNotNull( $tmpFile,
969 "Creation of local copy of $source succeeded ($backendName)." );
971 $contents = file_get_contents( $tmpFile->getPath() );
972 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
975 function provider_testGetLocalCopy() {
978 $base = $this->baseStorePath();
979 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
980 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
986 * @dataProvider provider_testGetLocalReference
988 public function testGetLocalReference( $source, $content ) {
989 $this->backend
= $this->singleBackend
;
990 $this->tearDownFiles();
991 $this->doTestGetLocalReference( $source, $content );
992 $this->tearDownFiles();
994 $this->backend
= $this->multiBackend
;
995 $this->tearDownFiles();
996 $this->doTestGetLocalReference( $source, $content );
997 $this->tearDownFiles();
1000 private function doTestGetLocalReference( $source, $content ) {
1001 $backendName = $this->backendClass();
1003 $this->prepare( array( 'dir' => dirname( $source ) ) );
1005 $status = $this->create( array( 'content' => $content, 'dst' => $source ) );
1006 $this->assertGoodStatus( $status,
1007 "Creation of file at $source succeeded ($backendName)." );
1009 $tmpFile = $this->backend
->getLocalReference( array( 'src' => $source ) );
1010 $this->assertNotNull( $tmpFile,
1011 "Creation of local copy of $source succeeded ($backendName)." );
1013 $contents = file_get_contents( $tmpFile->getPath() );
1014 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
1017 function provider_testGetLocalReference() {
1020 $base = $this->baseStorePath();
1021 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1022 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1028 * @dataProvider provider_testPrepareAndClean
1030 public function testPrepareAndClean( $path, $isOK ) {
1031 $this->backend
= $this->singleBackend
;
1032 $this->doTestPrepareAndClean( $path, $isOK );
1033 $this->tearDownFiles();
1035 $this->backend
= $this->multiBackend
;
1036 $this->doTestPrepareAndClean( $path, $isOK );
1037 $this->tearDownFiles();
1040 function provider_testPrepareAndClean() {
1041 $base = $this->baseStorePath();
1043 array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
1044 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
1045 # Specific to FS backend with no basePath field set
1046 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
1050 private function doTestPrepareAndClean( $path, $isOK ) {
1051 $backendName = $this->backendClass();
1053 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
1055 $this->assertGoodStatus( $status,
1056 "Preparing dir $path succeeded without warnings ($backendName)." );
1057 $this->assertEquals( true, $status->isOK(),
1058 "Preparing dir $path succeeded ($backendName)." );
1060 $this->assertEquals( false, $status->isOK(),
1061 "Preparing dir $path failed ($backendName)." );
1064 $status = $this->backend
->clean( array( 'dir' => dirname( $path ) ) );
1066 $this->assertGoodStatus( $status,
1067 "Cleaning dir $path succeeded without warnings ($backendName)." );
1068 $this->assertEquals( true, $status->isOK(),
1069 "Cleaning dir $path succeeded ($backendName)." );
1071 $this->assertEquals( false, $status->isOK(),
1072 "Cleaning dir $path failed ($backendName)." );
1076 public function testRecursiveClean() {
1077 $this->backend
= $this->singleBackend
;
1078 $this->doTestRecursiveClean();
1079 $this->tearDownFiles();
1081 $this->backend
= $this->multiBackend
;
1082 $this->doTestRecursiveClean();
1083 $this->tearDownFiles();
1086 private function doTestRecursiveClean() {
1087 $backendName = $this->backendClass();
1089 $base = $this->baseStorePath();
1091 "$base/unittest-cont1/e/a",
1092 "$base/unittest-cont1/e/a/b",
1093 "$base/unittest-cont1/e/a/b/c",
1094 "$base/unittest-cont1/e/a/b/c/d0",
1095 "$base/unittest-cont1/e/a/b/c/d1",
1096 "$base/unittest-cont1/e/a/b/c/d2",
1097 "$base/unittest-cont1/e/a/b/c/d0/1",
1098 "$base/unittest-cont1/e/a/b/c/d0/2",
1099 "$base/unittest-cont1/e/a/b/c/d1/3",
1100 "$base/unittest-cont1/e/a/b/c/d1/4",
1101 "$base/unittest-cont1/e/a/b/c/d2/5",
1102 "$base/unittest-cont1/e/a/b/c/d2/6"
1104 foreach ( $dirs as $dir ) {
1105 $status = $this->prepare( array( 'dir' => $dir ) );
1106 $this->assertGoodStatus( $status,
1107 "Preparing dir $dir succeeded without warnings ($backendName)." );
1110 if ( $this->backend
instanceof FSFileBackend
) {
1111 foreach ( $dirs as $dir ) {
1112 $this->assertEquals( true, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1113 "Dir $dir exists ($backendName)." );
1117 $status = $this->backend
->clean(
1118 array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
1119 $this->assertGoodStatus( $status,
1120 "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
1122 foreach ( $dirs as $dir ) {
1123 $this->assertEquals( false, $this->backend
->directoryExists( array( 'dir' => $dir ) ),
1124 "Dir $dir no longer exists ($backendName)." );
1128 // @TODO: testSecure
1130 public function testDoOperations() {
1131 $this->backend
= $this->singleBackend
;
1132 $this->tearDownFiles();
1133 $this->doTestDoOperations();
1134 $this->tearDownFiles();
1136 $this->backend
= $this->multiBackend
;
1137 $this->tearDownFiles();
1138 $this->doTestDoOperations();
1139 $this->tearDownFiles();
1141 $this->backend
= $this->singleBackend
;
1142 $this->tearDownFiles();
1143 $this->doTestDoOperations2();
1144 $this->tearDownFiles();
1146 $this->backend
= $this->multiBackend
;
1147 $this->tearDownFiles();
1148 $this->doTestDoOperations2();
1149 $this->tearDownFiles();
1151 $this->backend
= $this->singleBackend
;
1152 $this->tearDownFiles();
1153 $this->doTestDoOperationsFailing();
1154 $this->tearDownFiles();
1156 $this->backend
= $this->multiBackend
;
1157 $this->tearDownFiles();
1158 $this->doTestDoOperationsFailing();
1159 $this->tearDownFiles();
1162 private function doTestDoOperations() {
1163 $base = $this->baseStorePath();
1165 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1166 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1167 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1168 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1169 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1170 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1171 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1173 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1174 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1175 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1176 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1177 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1178 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1179 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1181 $status = $this->backend
->doOperations( array(
1182 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1183 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1184 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1185 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1186 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1187 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1188 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1189 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1190 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1191 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1192 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1193 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1194 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1195 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1196 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1197 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1198 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1200 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1202 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1204 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1206 array( 'op' => 'null' ),
1210 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1211 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1212 $this->assertEquals( 13, count( $status->success
),
1213 "Operation batch has correct success array" );
1215 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1216 "File does not exist at $fileA" );
1217 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1218 "File does not exist at $fileB" );
1219 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1220 "File does not exist at $fileD" );
1222 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1223 "File exists at $fileC" );
1224 $this->assertEquals( $fileBContents,
1225 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1226 "Correct file contents of $fileC" );
1227 $this->assertEquals( strlen( $fileBContents ),
1228 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1229 "Correct file size of $fileC" );
1230 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1231 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1232 "Correct file SHA-1 of $fileC" );
1235 // concurrency orientated
1236 private function doTestDoOperations2() {
1237 $base = $this->baseStorePath();
1239 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1240 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1241 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1243 $tmpNameA = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1244 file_put_contents( $tmpNameA, $fileAContents );
1245 $tmpNameB = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1246 file_put_contents( $tmpNameB, $fileBContents );
1247 $tmpNameC = TempFSFile
::factory( "unittests_", 'txt' )->getPath();
1248 file_put_contents( $tmpNameC, $fileCContents );
1250 $this->filesToPrune
[] = $tmpNameA; # avoid file leaking
1251 $this->filesToPrune
[] = $tmpNameB; # avoid file leaking
1252 $this->filesToPrune
[] = $tmpNameC; # avoid file leaking
1254 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1255 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1256 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1257 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1259 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1260 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1261 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1262 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1263 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1265 $status = $this->backend
->doOperations( array(
1266 array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
1267 array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
1268 array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
1269 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1270 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1271 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1272 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1273 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1274 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1275 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1276 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1277 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1278 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1279 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1280 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1281 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1282 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1283 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1284 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1285 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1287 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1289 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1291 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1293 array( 'op' => 'null' ),
1297 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1298 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1299 $this->assertEquals( 16, count( $status->success
),
1300 "Operation batch has correct success array" );
1302 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1303 "File does not exist at $fileA" );
1304 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1305 "File does not exist at $fileB" );
1306 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1307 "File does not exist at $fileD" );
1309 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1310 "File exists at $fileC" );
1311 $this->assertEquals( $fileBContents,
1312 $this->backend
->getFileContents( array( 'src' => $fileC ) ),
1313 "Correct file contents of $fileC" );
1314 $this->assertEquals( strlen( $fileBContents ),
1315 $this->backend
->getFileSize( array( 'src' => $fileC ) ),
1316 "Correct file size of $fileC" );
1317 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1318 $this->backend
->getFileSha1Base36( array( 'src' => $fileC ) ),
1319 "Correct file SHA-1 of $fileC" );
1322 private function doTestDoOperationsFailing() {
1323 $base = $this->baseStorePath();
1325 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
1326 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1327 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
1328 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1329 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
1330 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1331 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
1333 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1334 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1335 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1336 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1337 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1338 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1340 $status = $this->backend
->doOperations( array(
1341 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1342 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1343 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1344 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1345 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
1346 // Now: A:<A>, B:<B>, C:<A>, D:<B>
1347 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
1348 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1349 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
1350 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1351 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
1352 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1353 array( 'op' => 'delete', 'src' => $fileD ),
1354 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1355 array( 'op' => 'null' ),
1357 ), array( 'force' => 1 ) );
1359 $this->assertNotEquals( array(), $status->errors
, "Operation had warnings" );
1360 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1361 $this->assertEquals( 8, count( $status->success
),
1362 "Operation batch has correct success array" );
1364 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileB ) ),
1365 "File does not exist at $fileB" );
1366 $this->assertEquals( false, $this->backend
->fileExists( array( 'src' => $fileD ) ),
1367 "File does not exist at $fileD" );
1369 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileA ) ),
1370 "File does not exist at $fileA" );
1371 $this->assertEquals( true, $this->backend
->fileExists( array( 'src' => $fileC ) ),
1372 "File exists at $fileC" );
1373 $this->assertEquals( $fileBContents,
1374 $this->backend
->getFileContents( array( 'src' => $fileA ) ),
1375 "Correct file contents of $fileA" );
1376 $this->assertEquals( strlen( $fileBContents ),
1377 $this->backend
->getFileSize( array( 'src' => $fileA ) ),
1378 "Correct file size of $fileA" );
1379 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1380 $this->backend
->getFileSha1Base36( array( 'src' => $fileA ) ),
1381 "Correct file SHA-1 of $fileA" );
1384 public function testGetFileList() {
1385 $this->backend
= $this->singleBackend
;
1386 $this->tearDownFiles();
1387 $this->doTestGetFileList();
1388 $this->tearDownFiles();
1390 $this->backend
= $this->multiBackend
;
1391 $this->tearDownFiles();
1392 $this->doTestGetFileList();
1393 $this->tearDownFiles();
1396 private function doTestGetFileList() {
1397 $backendName = $this->backendClass();
1398 $base = $this->baseStorePath();
1400 // Should have no errors
1401 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
1404 "$base/unittest-cont1/e/test1.txt",
1405 "$base/unittest-cont1/e/test2.txt",
1406 "$base/unittest-cont1/e/test3.txt",
1407 "$base/unittest-cont1/e/subdir1/test1.txt",
1408 "$base/unittest-cont1/e/subdir1/test2.txt",
1409 "$base/unittest-cont1/e/subdir2/test3.txt",
1410 "$base/unittest-cont1/e/subdir2/test4.txt",
1411 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
1412 "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
1413 "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
1414 "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
1415 "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
1416 "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
1417 "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
1422 foreach ( $files as $file ) {
1423 $this->prepare( array( 'dir' => dirname( $file ) ) );
1424 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1426 $status = $this->backend
->doQuickOperations( $ops );
1427 $this->assertGoodStatus( $status,
1428 "Creation of files succeeded ($backendName)." );
1429 $this->assertEquals( true, $status->isOK(),
1430 "Creation of files succeeded with OK status ($backendName)." );
1437 "e/subdir1/test1.txt",
1438 "e/subdir1/test2.txt",
1439 "e/subdir2/test3.txt",
1440 "e/subdir2/test4.txt",
1441 "e/subdir2/subdir/test1.txt",
1442 "e/subdir2/subdir/test2.txt",
1443 "e/subdir2/subdir/test3.txt",
1444 "e/subdir2/subdir/test4.txt",
1445 "e/subdir2/subdir/test5.txt",
1446 "e/subdir2/subdir/sub/test0.txt",
1447 "e/subdir2/subdir/sub/120-px-file.txt",
1451 // Actual listing (no trailing slash)
1453 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1454 foreach ( $iter as $file ) {
1459 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1461 // Actual listing (with trailing slash)
1463 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1464 foreach ( $iter as $file ) {
1469 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1479 "sub/120-px-file.txt",
1483 // Actual listing (no trailing slash)
1485 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
1486 foreach ( $iter as $file ) {
1491 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1493 // Actual listing (with trailing slash)
1495 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
1496 foreach ( $iter as $file ) {
1501 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1503 // Actual listing (using iterator second time)
1505 foreach ( $iter as $file ) {
1510 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
1512 // Expected listing (top files only)
1522 // Actual listing (top files only)
1524 $iter = $this->backend
->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
1525 foreach ( $iter as $file ) {
1530 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
1532 foreach ( $files as $file ) { // clean up
1533 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1536 $iter = $this->backend
->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1537 foreach ( $iter as $iter ) {} // no errors
1540 public function testGetDirectoryList() {
1541 $this->backend
= $this->singleBackend
;
1542 $this->tearDownFiles();
1543 $this->doTestGetDirectoryList();
1544 $this->tearDownFiles();
1546 $this->backend
= $this->multiBackend
;
1547 $this->tearDownFiles();
1548 $this->doTestGetDirectoryList();
1549 $this->tearDownFiles();
1552 private function doTestGetDirectoryList() {
1553 $backendName = $this->backendClass();
1555 $base = $this->baseStorePath();
1557 "$base/unittest-cont1/e/test1.txt",
1558 "$base/unittest-cont1/e/test2.txt",
1559 "$base/unittest-cont1/e/test3.txt",
1560 "$base/unittest-cont1/e/subdir1/test1.txt",
1561 "$base/unittest-cont1/e/subdir1/test2.txt",
1562 "$base/unittest-cont1/e/subdir2/test3.txt",
1563 "$base/unittest-cont1/e/subdir2/test4.txt",
1564 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
1565 "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
1566 "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
1567 "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
1568 "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
1569 "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
1570 "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
1575 foreach ( $files as $file ) {
1576 $this->prepare( array( 'dir' => dirname( $file ) ) );
1577 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1579 $status = $this->backend
->doQuickOperations( $ops );
1580 $this->assertGoodStatus( $status,
1581 "Creation of files succeeded ($backendName)." );
1582 $this->assertEquals( true, $status->isOK(),
1583 "Creation of files succeeded with OK status ($backendName)." );
1585 $this->assertEquals( true,
1586 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
1587 "Directory exists in ($backendName)." );
1588 $this->assertEquals( true,
1589 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
1590 "Directory exists in ($backendName)." );
1591 $this->assertEquals( false,
1592 $this->backend
->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
1593 "Directory does not exists in ($backendName)." );
1601 // Actual listing (no trailing slash)
1603 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
1604 foreach ( $iter as $file ) {
1609 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1620 // Actual listing (no trailing slash)
1622 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
1623 foreach ( $iter as $file ) {
1628 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1630 // Actual listing (with trailing slash)
1632 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
1633 foreach ( $iter as $file ) {
1638 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1646 // Actual listing (no trailing slash)
1648 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
1649 foreach ( $iter as $file ) {
1654 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1656 // Actual listing (with trailing slash)
1658 $iter = $this->backend
->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2/" ) );
1659 foreach ( $iter as $file ) {
1664 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1666 // Actual listing (using iterator second time)
1668 foreach ( $iter as $file ) {
1673 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
1675 // Expected listing (recursive)
1685 "e/subdir4/subdir/sub",
1689 // Actual listing (recursive)
1691 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
1692 foreach ( $iter as $file ) {
1697 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1699 // Expected listing (recursive)
1706 // Actual listing (recursive)
1708 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
1709 foreach ( $iter as $file ) {
1714 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1716 // Actual listing (recursive, second time)
1718 foreach ( $iter as $file ) {
1723 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1725 foreach ( $files as $file ) { // clean up
1726 $this->backend
->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1729 $iter = $this->backend
->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1730 foreach ( $iter as $iter ) {} // no errors
1733 public function testLockCalls() {
1734 $this->backend
= $this->singleBackend
;
1735 $this->doTestLockCalls();
1738 private function doTestLockCalls() {
1739 $backendName = $this->backendClass();
1741 for ( $i=0; $i<50; $i++
) {
1747 "subdir1", // duplicate
1748 "subdir1/test1.txt",
1749 "subdir1/test2.txt",
1751 "subdir2", // duplicate
1752 "subdir2/test3.txt",
1753 "subdir2/test4.txt",
1755 "subdir2/subdir/test1.txt",
1756 "subdir2/subdir/test2.txt",
1757 "subdir2/subdir/test3.txt",
1758 "subdir2/subdir/test4.txt",
1759 "subdir2/subdir/test5.txt",
1760 "subdir2/subdir/sub",
1761 "subdir2/subdir/sub/test0.txt",
1762 "subdir2/subdir/sub/120-px-file.txt",
1765 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_EX
);
1766 $this->assertEquals( array(), $status->errors
,
1767 "Locking of files succeeded ($backendName)." );
1768 $this->assertEquals( true, $status->isOK(),
1769 "Locking of files succeeded with OK status ($backendName)." );
1771 $status = $this->backend
->lockFiles( $paths, LockManager
::LOCK_SH
);
1772 $this->assertEquals( array(), $status->errors
,
1773 "Locking of files succeeded ($backendName)." );
1774 $this->assertEquals( true, $status->isOK(),
1775 "Locking of files succeeded with OK status ($backendName)." );
1777 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_SH
);
1778 $this->assertEquals( array(), $status->errors
,
1779 "Locking of files succeeded ($backendName)." );
1780 $this->assertEquals( true, $status->isOK(),
1781 "Locking of files succeeded with OK status ($backendName)." );
1783 $status = $this->backend
->unlockFiles( $paths, LockManager
::LOCK_EX
);
1784 $this->assertEquals( array(), $status->errors
,
1785 "Locking of files succeeded ($backendName)." );
1786 $this->assertEquals( true, $status->isOK(),
1787 "Locking of files succeeded with OK status ($backendName)." );
1791 // test helper wrapper for backend prepare() function
1792 private function prepare( array $params ) {
1793 return $this->backend
->prepare( $params );
1796 // test helper wrapper for backend prepare() function
1797 private function create( array $params ) {
1798 $params['op'] = 'create';
1799 return $this->backend
->doQuickOperations( array( $params ) );
1802 function tearDownFiles() {
1803 foreach ( $this->filesToPrune
as $file ) {
1806 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' );
1807 foreach ( $containers as $container ) {
1808 $this->deleteFiles( $container );
1810 $this->filesToPrune
= array();
1813 private function deleteFiles( $container ) {
1814 $base = $this->baseStorePath();
1815 $iter = $this->backend
->getFileList( array( 'dir' => "$base/$container" ) );
1817 foreach ( $iter as $file ) {
1818 $this->backend
->delete( array( 'src' => "$base/$container/$file" ),
1819 array( 'force' => 1, 'nonLocking' => 1 ) );
1822 $this->backend
->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
1825 function assertGoodStatus( $status, $msg ) {
1826 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors
, 1 ), $msg );
1829 function tearDown() {