MediaWiki  REL1_24
FileBackendTest.php
Go to the documentation of this file.
00001 <?php
00002 
00008 class FileBackendTest extends MediaWikiTestCase {
00009 
00011     private $backend;
00013     private $multiBackend;
00015     public $singleBackend;
00016     private $filesToPrune = array();
00017     private static $backendToUse;
00018 
00019     protected function setUp() {
00020         global $wgFileBackends;
00021         parent::setUp();
00022         $uniqueId = time() . '-' . mt_rand();
00023         $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . $uniqueId;
00024         if ( $this->getCliArg( 'use-filebackend' ) ) {
00025             if ( self::$backendToUse ) {
00026                 $this->singleBackend = self::$backendToUse;
00027             } else {
00028                 $name = $this->getCliArg( 'use-filebackend' );
00029                 $useConfig = array();
00030                 foreach ( $wgFileBackends as $conf ) {
00031                     if ( $conf['name'] == $name ) {
00032                         $useConfig = $conf;
00033                         break;
00034                     }
00035                 }
00036                 $useConfig['name'] = 'localtesting'; // swap name
00037                 $useConfig['shardViaHashLevels'] = array( // test sharding
00038                     'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
00039                 );
00040                 if ( isset( $useConfig['fileJournal'] ) ) {
00041                     $useConfig['fileJournal'] = FileJournal::factory( $useConfig['fileJournal'], $name );
00042                 }
00043                 $useConfig['lockManager'] = LockManagerGroup::singleton()->get( $useConfig['lockManager'] );
00044                 $class = $useConfig['class'];
00045                 self::$backendToUse = new $class( $useConfig );
00046                 $this->singleBackend = self::$backendToUse;
00047             }
00048         } else {
00049             $this->singleBackend = new FSFileBackend( array(
00050                 'name' => 'localtesting',
00051                 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
00052                 'wikiId' => wfWikiID(),
00053                 'containerPaths' => array(
00054                     'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
00055                     'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
00056             ) );
00057         }
00058         $this->multiBackend = new FileBackendMultiWrite( array(
00059             'name' => 'localtesting',
00060             'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
00061             'parallelize' => 'implicit',
00062             'wikiId' => wfWikiId() . $uniqueId,
00063             'backends' => array(
00064                 array(
00065                     'name' => 'localmultitesting1',
00066                     'class' => 'FSFileBackend',
00067                     'containerPaths' => array(
00068                         'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
00069                         'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
00070                     'isMultiMaster' => false
00071                 ),
00072                 array(
00073                     'name' => 'localmultitesting2',
00074                     'class' => 'FSFileBackend',
00075                     'containerPaths' => array(
00076                         'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
00077                         'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
00078                     'isMultiMaster' => true
00079                 )
00080             )
00081         ) );
00082         $this->filesToPrune = array();
00083     }
00084 
00085     private static function baseStorePath() {
00086         return 'mwstore://localtesting';
00087     }
00088 
00089     private function backendClass() {
00090         return get_class( $this->backend );
00091     }
00092 
00097     public function testIsStoragePath( $path, $isStorePath ) {
00098         $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ),
00099             "FileBackend::isStoragePath on path '$path'" );
00100     }
00101 
00102     public static function provider_testIsStoragePath() {
00103         return array(
00104             array( 'mwstore://', true ),
00105             array( 'mwstore://backend', true ),
00106             array( 'mwstore://backend/container', true ),
00107             array( 'mwstore://backend/container/', true ),
00108             array( 'mwstore://backend/container/path', true ),
00109             array( 'mwstore://backend//container/', true ),
00110             array( 'mwstore://backend//container//', true ),
00111             array( 'mwstore://backend//container//path', true ),
00112             array( 'mwstore:///', true ),
00113             array( 'mwstore:/', false ),
00114             array( 'mwstore:', false ),
00115         );
00116     }
00117 
00122     public function testSplitStoragePath( $path, $res ) {
00123         $this->assertEquals( $res, FileBackend::splitStoragePath( $path ),
00124             "FileBackend::splitStoragePath on path '$path'" );
00125     }
00126 
00127     public static function provider_testSplitStoragePath() {
00128         return array(
00129             array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
00130             array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
00131             array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
00132             array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
00133             array( 'mwstore://backend//container/path', array( null, null, null ) ),
00134             array( 'mwstore://backend//container//path', array( null, null, null ) ),
00135             array( 'mwstore://', array( null, null, null ) ),
00136             array( 'mwstore://backend', array( null, null, null ) ),
00137             array( 'mwstore:///', array( null, null, null ) ),
00138             array( 'mwstore:/', array( null, null, null ) ),
00139             array( 'mwstore:', array( null, null, null ) )
00140         );
00141     }
00142 
00147     public function testNormalizeStoragePath( $path, $res ) {
00148         $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ),
00149             "FileBackend::normalizeStoragePath on path '$path'" );
00150     }
00151 
00152     public static function provider_normalizeStoragePath() {
00153         return array(
00154             array( 'mwstore://backend/container', 'mwstore://backend/container' ),
00155             array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
00156             array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
00157             array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
00158             array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
00159             array(
00160                 'mwstore://backend/container///path//to///obj',
00161                 'mwstore://backend/container/path/to/obj'
00162             ),
00163             array( 'mwstore://', null ),
00164             array( 'mwstore://backend', null ),
00165             array( 'mwstore://backend//container/path', null ),
00166             array( 'mwstore://backend//container//path', null ),
00167             array( 'mwstore:///', null ),
00168             array( 'mwstore:/', null ),
00169             array( 'mwstore:', null ),
00170         );
00171     }
00172 
00177     public function testParentStoragePath( $path, $res ) {
00178         $this->assertEquals( $res, FileBackend::parentStoragePath( $path ),
00179             "FileBackend::parentStoragePath on path '$path'" );
00180     }
00181 
00182     public static function provider_testParentStoragePath() {
00183         return array(
00184             array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
00185             array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
00186             array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
00187             array( 'mwstore://backend/container', null ),
00188             array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
00189             array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
00190             array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
00191             array( 'mwstore://backend/container/', null ),
00192         );
00193     }
00194 
00199     public function testExtensionFromPath( $path, $res ) {
00200         $this->assertEquals( $res, FileBackend::extensionFromPath( $path ),
00201             "FileBackend::extensionFromPath on path '$path'" );
00202     }
00203 
00204     public static function provider_testExtensionFromPath() {
00205         return array(
00206             array( 'mwstore://backend/container/path.txt', 'txt' ),
00207             array( 'mwstore://backend/container/path.svg.png', 'png' ),
00208             array( 'mwstore://backend/container/path', '' ),
00209             array( 'mwstore://backend/container/path.', '' ),
00210         );
00211     }
00212 
00216     public function testStore( $op ) {
00217         $this->filesToPrune[] = $op['src'];
00218 
00219         $this->backend = $this->singleBackend;
00220         $this->tearDownFiles();
00221         $this->doTestStore( $op );
00222         $this->tearDownFiles();
00223 
00224         $this->backend = $this->multiBackend;
00225         $this->tearDownFiles();
00226         $this->doTestStore( $op );
00227         $this->filesToPrune[] = $op['src']; # avoid file leaking
00228         $this->tearDownFiles();
00229     }
00230 
00234     private function doTestStore( $op ) {
00235         $backendName = $this->backendClass();
00236 
00237         $source = $op['src'];
00238         $dest = $op['dst'];
00239         $this->prepare( array( 'dir' => dirname( $dest ) ) );
00240 
00241         file_put_contents( $source, "Unit test file" );
00242 
00243         if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
00244             $this->backend->store( $op );
00245         }
00246 
00247         $status = $this->backend->doOperation( $op );
00248 
00249         $this->assertGoodStatus( $status,
00250             "Store from $source to $dest succeeded without warnings ($backendName)." );
00251         $this->assertEquals( true, $status->isOK(),
00252             "Store from $source to $dest succeeded ($backendName)." );
00253         $this->assertEquals( array( 0 => true ), $status->success,
00254             "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
00255         $this->assertEquals( true, file_exists( $source ),
00256             "Source file $source still exists ($backendName)." );
00257         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00258             "Destination file $dest exists ($backendName)." );
00259 
00260         $this->assertEquals( filesize( $source ),
00261             $this->backend->getFileSize( array( 'src' => $dest ) ),
00262             "Destination file $dest has correct size ($backendName)." );
00263 
00264         $props1 = FSFile::getPropsFromPath( $source );
00265         $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
00266         $this->assertEquals( $props1, $props2,
00267             "Source and destination have the same props ($backendName)." );
00268 
00269         $this->assertBackendPathsConsistent( array( $dest ) );
00270     }
00271 
00272     public static function provider_testStore() {
00273         $cases = array();
00274 
00275         $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
00276         $toPath = self::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
00277         $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
00278         $cases[] = array(
00279             $op, // operation
00280             $tmpName, // source
00281             $toPath, // dest
00282         );
00283 
00284         $op2 = $op;
00285         $op2['overwrite'] = true;
00286         $cases[] = array(
00287             $op2, // operation
00288             $tmpName, // source
00289             $toPath, // dest
00290         );
00291 
00292         $op2 = $op;
00293         $op2['overwriteSame'] = true;
00294         $cases[] = array(
00295             $op2, // operation
00296             $tmpName, // source
00297             $toPath, // dest
00298         );
00299 
00300         return $cases;
00301     }
00302 
00307     public function testCopy( $op ) {
00308         $this->backend = $this->singleBackend;
00309         $this->tearDownFiles();
00310         $this->doTestCopy( $op );
00311         $this->tearDownFiles();
00312 
00313         $this->backend = $this->multiBackend;
00314         $this->tearDownFiles();
00315         $this->doTestCopy( $op );
00316         $this->tearDownFiles();
00317     }
00318 
00319     private function doTestCopy( $op ) {
00320         $backendName = $this->backendClass();
00321 
00322         $source = $op['src'];
00323         $dest = $op['dst'];
00324         $this->prepare( array( 'dir' => dirname( $source ) ) );
00325         $this->prepare( array( 'dir' => dirname( $dest ) ) );
00326 
00327         if ( isset( $op['ignoreMissingSource'] ) ) {
00328             $status = $this->backend->doOperation( $op );
00329             $this->assertGoodStatus( $status,
00330                 "Move from $source to $dest succeeded without warnings ($backendName)." );
00331             $this->assertEquals( array( 0 => true ), $status->success,
00332                 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
00333             $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00334                 "Source file $source does not exist ($backendName)." );
00335             $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $dest ) ),
00336                 "Destination file $dest does not exist ($backendName)." );
00337 
00338             return; // done
00339         }
00340 
00341         $status = $this->backend->doOperation(
00342             array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
00343         $this->assertGoodStatus( $status,
00344             "Creation of file at $source succeeded ($backendName)." );
00345 
00346         if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
00347             $this->backend->copy( $op );
00348         }
00349 
00350         $status = $this->backend->doOperation( $op );
00351 
00352         $this->assertGoodStatus( $status,
00353             "Copy from $source to $dest succeeded without warnings ($backendName)." );
00354         $this->assertEquals( true, $status->isOK(),
00355             "Copy from $source to $dest succeeded ($backendName)." );
00356         $this->assertEquals( array( 0 => true ), $status->success,
00357             "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
00358         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
00359             "Source file $source still exists ($backendName)." );
00360         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00361             "Destination file $dest exists after copy ($backendName)." );
00362 
00363         $this->assertEquals(
00364             $this->backend->getFileSize( array( 'src' => $source ) ),
00365             $this->backend->getFileSize( array( 'src' => $dest ) ),
00366             "Destination file $dest has correct size ($backendName)." );
00367 
00368         $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
00369         $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
00370         $this->assertEquals( $props1, $props2,
00371             "Source and destination have the same props ($backendName)." );
00372 
00373         $this->assertBackendPathsConsistent( array( $source, $dest ) );
00374     }
00375 
00376     public static function provider_testCopy() {
00377         $cases = array();
00378 
00379         $source = self::baseStorePath() . '/unittest-cont1/e/file.txt';
00380         $dest = self::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
00381 
00382         $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
00383         $cases[] = array(
00384             $op, // operation
00385             $source, // source
00386             $dest, // dest
00387         );
00388 
00389         $op2 = $op;
00390         $op2['overwrite'] = true;
00391         $cases[] = array(
00392             $op2, // operation
00393             $source, // source
00394             $dest, // dest
00395         );
00396 
00397         $op2 = $op;
00398         $op2['overwriteSame'] = true;
00399         $cases[] = array(
00400             $op2, // operation
00401             $source, // source
00402             $dest, // dest
00403         );
00404 
00405         $op2 = $op;
00406         $op2['ignoreMissingSource'] = true;
00407         $cases[] = array(
00408             $op2, // operation
00409             $source, // source
00410             $dest, // dest
00411         );
00412 
00413         $op2 = $op;
00414         $op2['ignoreMissingSource'] = true;
00415         $cases[] = array(
00416             $op2, // operation
00417             self::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
00418             $dest, // dest
00419         );
00420 
00421         return $cases;
00422     }
00423 
00428     public function testMove( $op ) {
00429         $this->backend = $this->singleBackend;
00430         $this->tearDownFiles();
00431         $this->doTestMove( $op );
00432         $this->tearDownFiles();
00433 
00434         $this->backend = $this->multiBackend;
00435         $this->tearDownFiles();
00436         $this->doTestMove( $op );
00437         $this->tearDownFiles();
00438     }
00439 
00440     private function doTestMove( $op ) {
00441         $backendName = $this->backendClass();
00442 
00443         $source = $op['src'];
00444         $dest = $op['dst'];
00445         $this->prepare( array( 'dir' => dirname( $source ) ) );
00446         $this->prepare( array( 'dir' => dirname( $dest ) ) );
00447 
00448         if ( isset( $op['ignoreMissingSource'] ) ) {
00449             $status = $this->backend->doOperation( $op );
00450             $this->assertGoodStatus( $status,
00451                 "Move from $source to $dest succeeded without warnings ($backendName)." );
00452             $this->assertEquals( array( 0 => true ), $status->success,
00453                 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
00454             $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00455                 "Source file $source does not exist ($backendName)." );
00456             $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $dest ) ),
00457                 "Destination file $dest does not exist ($backendName)." );
00458 
00459             return; // done
00460         }
00461 
00462         $status = $this->backend->doOperation(
00463             array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
00464         $this->assertGoodStatus( $status,
00465             "Creation of file at $source succeeded ($backendName)." );
00466 
00467         if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
00468             $this->backend->copy( $op );
00469         }
00470 
00471         $status = $this->backend->doOperation( $op );
00472         $this->assertGoodStatus( $status,
00473             "Move from $source to $dest succeeded without warnings ($backendName)." );
00474         $this->assertEquals( true, $status->isOK(),
00475             "Move from $source to $dest succeeded ($backendName)." );
00476         $this->assertEquals( array( 0 => true ), $status->success,
00477             "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
00478         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00479             "Source file $source does not still exists ($backendName)." );
00480         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00481             "Destination file $dest exists after move ($backendName)." );
00482 
00483         $this->assertNotEquals(
00484             $this->backend->getFileSize( array( 'src' => $source ) ),
00485             $this->backend->getFileSize( array( 'src' => $dest ) ),
00486             "Destination file $dest has correct size ($backendName)." );
00487 
00488         $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
00489         $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
00490         $this->assertEquals( false, $props1['fileExists'],
00491             "Source file does not exist accourding to props ($backendName)." );
00492         $this->assertEquals( true, $props2['fileExists'],
00493             "Destination file exists accourding to props ($backendName)." );
00494 
00495         $this->assertBackendPathsConsistent( array( $source, $dest ) );
00496     }
00497 
00498     public static function provider_testMove() {
00499         $cases = array();
00500 
00501         $source = self::baseStorePath() . '/unittest-cont1/e/file.txt';
00502         $dest = self::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
00503 
00504         $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
00505         $cases[] = array(
00506             $op, // operation
00507             $source, // source
00508             $dest, // dest
00509         );
00510 
00511         $op2 = $op;
00512         $op2['overwrite'] = true;
00513         $cases[] = array(
00514             $op2, // operation
00515             $source, // source
00516             $dest, // dest
00517         );
00518 
00519         $op2 = $op;
00520         $op2['overwriteSame'] = true;
00521         $cases[] = array(
00522             $op2, // operation
00523             $source, // source
00524             $dest, // dest
00525         );
00526 
00527         $op2 = $op;
00528         $op2['ignoreMissingSource'] = true;
00529         $cases[] = array(
00530             $op2, // operation
00531             $source, // source
00532             $dest, // dest
00533         );
00534 
00535         $op2 = $op;
00536         $op2['ignoreMissingSource'] = true;
00537         $cases[] = array(
00538             $op2, // operation
00539             self::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
00540             $dest, // dest
00541         );
00542 
00543         return $cases;
00544     }
00545 
00550     public function testDelete( $op, $withSource, $okStatus ) {
00551         $this->backend = $this->singleBackend;
00552         $this->tearDownFiles();
00553         $this->doTestDelete( $op, $withSource, $okStatus );
00554         $this->tearDownFiles();
00555 
00556         $this->backend = $this->multiBackend;
00557         $this->tearDownFiles();
00558         $this->doTestDelete( $op, $withSource, $okStatus );
00559         $this->tearDownFiles();
00560     }
00561 
00562     private function doTestDelete( $op, $withSource, $okStatus ) {
00563         $backendName = $this->backendClass();
00564 
00565         $source = $op['src'];
00566         $this->prepare( array( 'dir' => dirname( $source ) ) );
00567 
00568         if ( $withSource ) {
00569             $status = $this->backend->doOperation(
00570                 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
00571             $this->assertGoodStatus( $status,
00572                 "Creation of file at $source succeeded ($backendName)." );
00573         }
00574 
00575         $status = $this->backend->doOperation( $op );
00576         if ( $okStatus ) {
00577             $this->assertGoodStatus( $status,
00578                 "Deletion of file at $source succeeded without warnings ($backendName)." );
00579             $this->assertEquals( true, $status->isOK(),
00580                 "Deletion of file at $source succeeded ($backendName)." );
00581             $this->assertEquals( array( 0 => true ), $status->success,
00582                 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
00583         } else {
00584             $this->assertEquals( false, $status->isOK(),
00585                 "Deletion of file at $source failed ($backendName)." );
00586         }
00587 
00588         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00589             "Source file $source does not exist after move ($backendName)." );
00590 
00591         $this->assertFalse(
00592             $this->backend->getFileSize( array( 'src' => $source ) ),
00593             "Source file $source has correct size (false) ($backendName)." );
00594 
00595         $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
00596         $this->assertFalse( $props1['fileExists'],
00597             "Source file $source does not exist according to props ($backendName)." );
00598 
00599         $this->assertBackendPathsConsistent( array( $source ) );
00600     }
00601 
00602     public static function provider_testDelete() {
00603         $cases = array();
00604 
00605         $source = self::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
00606 
00607         $op = array( 'op' => 'delete', 'src' => $source );
00608         $cases[] = array(
00609             $op, // operation
00610             true, // with source
00611             true // succeeds
00612         );
00613 
00614         $cases[] = array(
00615             $op, // operation
00616             false, // without source
00617             false // fails
00618         );
00619 
00620         $op['ignoreMissingSource'] = true;
00621         $cases[] = array(
00622             $op, // operation
00623             false, // without source
00624             true // succeeds
00625         );
00626 
00627         $op['ignoreMissingSource'] = true;
00628         $op['src'] = self::baseStorePath() . '/unittest-cont-bad/e/file.txt';
00629         $cases[] = array(
00630             $op, // operation
00631             false, // without source
00632             true // succeeds
00633         );
00634 
00635         return $cases;
00636     }
00637 
00642     public function testDescribe( $op, $withSource, $okStatus ) {
00643         $this->backend = $this->singleBackend;
00644         $this->tearDownFiles();
00645         $this->doTestDescribe( $op, $withSource, $okStatus );
00646         $this->tearDownFiles();
00647 
00648         $this->backend = $this->multiBackend;
00649         $this->tearDownFiles();
00650         $this->doTestDescribe( $op, $withSource, $okStatus );
00651         $this->tearDownFiles();
00652     }
00653 
00654     private function doTestDescribe( $op, $withSource, $okStatus ) {
00655         $backendName = $this->backendClass();
00656 
00657         $source = $op['src'];
00658         $this->prepare( array( 'dir' => dirname( $source ) ) );
00659 
00660         if ( $withSource ) {
00661             $status = $this->backend->doOperation(
00662                 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source,
00663                     'headers' => array( 'Content-Disposition' => 'xxx' ) ) );
00664             $this->assertGoodStatus( $status,
00665                 "Creation of file at $source succeeded ($backendName)." );
00666             if ( $this->backend->hasFeatures( FileBackend::ATTR_HEADERS ) ) {
00667                 $attr = $this->backend->getFileXAttributes( array( 'src' => $source ) );
00668                 $this->assertHasHeaders( array( 'Content-Disposition' => 'xxx' ), $attr );
00669             }
00670 
00671             $status = $this->backend->describe( array( 'src' => $source,
00672                 'headers' => array( 'Content-Disposition' => '' ) ) ); // remove
00673             $this->assertGoodStatus( $status,
00674                 "Removal of header for $source succeeded ($backendName)." );
00675 
00676             if ( $this->backend->hasFeatures( FileBackend::ATTR_HEADERS ) ) {
00677                 $attr = $this->backend->getFileXAttributes( array( 'src' => $source ) );
00678                 $this->assertFalse( isset( $attr['headers']['content-disposition'] ),
00679                     "File 'Content-Disposition' header removed." );
00680             }
00681         }
00682 
00683         $status = $this->backend->doOperation( $op );
00684         if ( $okStatus ) {
00685             $this->assertGoodStatus( $status,
00686                 "Describe of file at $source succeeded without warnings ($backendName)." );
00687             $this->assertEquals( true, $status->isOK(),
00688                 "Describe of file at $source succeeded ($backendName)." );
00689             $this->assertEquals( array( 0 => true ), $status->success,
00690                 "Describe of file at $source has proper 'success' field in Status ($backendName)." );
00691             if ( $this->backend->hasFeatures( FileBackend::ATTR_HEADERS ) ) {
00692                 $attr = $this->backend->getFileXAttributes( array( 'src' => $source ) );
00693                 $this->assertHasHeaders( $op['headers'], $attr );
00694             }
00695         } else {
00696             $this->assertEquals( false, $status->isOK(),
00697                 "Describe of file at $source failed ($backendName)." );
00698         }
00699 
00700         $this->assertBackendPathsConsistent( array( $source ) );
00701     }
00702 
00703     private function assertHasHeaders( array $headers, array $attr ) {
00704         foreach ( $headers as $n => $v ) {
00705             if ( $n !== '' ) {
00706                 $this->assertTrue( isset( $attr['headers'][strtolower( $n )] ),
00707                     "File has '$n' header." );
00708                 $this->assertEquals( $v, $attr['headers'][strtolower( $n )],
00709                     "File has '$n' header value." );
00710             } else {
00711                 $this->assertFalse( isset( $attr['headers'][strtolower( $n )] ),
00712                     "File does not have '$n' header." );
00713             }
00714         }
00715     }
00716 
00717     public static function provider_testDescribe() {
00718         $cases = array();
00719 
00720         $source = self::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
00721 
00722         $op = array( 'op' => 'describe', 'src' => $source,
00723             'headers' => array( 'Content-Disposition' => 'inline' ), );
00724         $cases[] = array(
00725             $op, // operation
00726             true, // with source
00727             true // succeeds
00728         );
00729 
00730         $cases[] = array(
00731             $op, // operation
00732             false, // without source
00733             false // fails
00734         );
00735 
00736         return $cases;
00737     }
00738 
00743     public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
00744         $this->backend = $this->singleBackend;
00745         $this->tearDownFiles();
00746         $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
00747         $this->tearDownFiles();
00748 
00749         $this->backend = $this->multiBackend;
00750         $this->tearDownFiles();
00751         $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
00752         $this->tearDownFiles();
00753     }
00754 
00755     private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
00756         $backendName = $this->backendClass();
00757 
00758         $dest = $op['dst'];
00759         $this->prepare( array( 'dir' => dirname( $dest ) ) );
00760 
00761         $oldText = 'blah...blah...waahwaah';
00762         if ( $alreadyExists ) {
00763             $status = $this->backend->doOperation(
00764                 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
00765             $this->assertGoodStatus( $status,
00766                 "Creation of file at $dest succeeded ($backendName)." );
00767         }
00768 
00769         $status = $this->backend->doOperation( $op );
00770         if ( $okStatus ) {
00771             $this->assertGoodStatus( $status,
00772                 "Creation of file at $dest succeeded without warnings ($backendName)." );
00773             $this->assertEquals( true, $status->isOK(),
00774                 "Creation of file at $dest succeeded ($backendName)." );
00775             $this->assertEquals( array( 0 => true ), $status->success,
00776                 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
00777         } else {
00778             $this->assertEquals( false, $status->isOK(),
00779                 "Creation of file at $dest failed ($backendName)." );
00780         }
00781 
00782         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00783             "Destination file $dest exists after creation ($backendName)." );
00784 
00785         $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
00786         $this->assertEquals( true, $props1['fileExists'],
00787             "Destination file $dest exists according to props ($backendName)." );
00788         if ( $okStatus ) { // file content is what we saved
00789             $this->assertEquals( $newSize, $props1['size'],
00790                 "Destination file $dest has expected size according to props ($backendName)." );
00791             $this->assertEquals( $newSize,
00792                 $this->backend->getFileSize( array( 'src' => $dest ) ),
00793                 "Destination file $dest has correct size ($backendName)." );
00794         } else { // file content is some other previous text
00795             $this->assertEquals( strlen( $oldText ), $props1['size'],
00796                 "Destination file $dest has original size according to props ($backendName)." );
00797             $this->assertEquals( strlen( $oldText ),
00798                 $this->backend->getFileSize( array( 'src' => $dest ) ),
00799                 "Destination file $dest has original size according to props ($backendName)." );
00800         }
00801 
00802         $this->assertBackendPathsConsistent( array( $dest ) );
00803     }
00804 
00808     public static function provider_testCreate() {
00809         $cases = array();
00810 
00811         $dest = self::baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
00812 
00813         $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
00814         $cases[] = array(
00815             $op, // operation
00816             false, // no dest already exists
00817             true, // succeeds
00818             strlen( $op['content'] )
00819         );
00820 
00821         $op2 = $op;
00822         $op2['content'] = "\n";
00823         $cases[] = array(
00824             $op2, // operation
00825             false, // no dest already exists
00826             true, // succeeds
00827             strlen( $op2['content'] )
00828         );
00829 
00830         $op2 = $op;
00831         $op2['content'] = "fsf\n waf 3kt";
00832         $cases[] = array(
00833             $op2, // operation
00834             true, // dest already exists
00835             false, // fails
00836             strlen( $op2['content'] )
00837         );
00838 
00839         $op2 = $op;
00840         $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
00841         $op2['overwrite'] = true;
00842         $cases[] = array(
00843             $op2, // operation
00844             true, // dest already exists
00845             true, // succeeds
00846             strlen( $op2['content'] )
00847         );
00848 
00849         $op2 = $op;
00850         $op2['content'] = "39qjmg3-qg";
00851         $op2['overwriteSame'] = true;
00852         $cases[] = array(
00853             $op2, // operation
00854             true, // dest already exists
00855             false, // succeeds
00856             strlen( $op2['content'] )
00857         );
00858 
00859         return $cases;
00860     }
00861 
00865     public function testDoQuickOperations() {
00866         $this->backend = $this->singleBackend;
00867         $this->doTestDoQuickOperations();
00868         $this->tearDownFiles();
00869 
00870         $this->backend = $this->multiBackend;
00871         $this->doTestDoQuickOperations();
00872         $this->tearDownFiles();
00873     }
00874 
00875     private function doTestDoQuickOperations() {
00876         $backendName = $this->backendClass();
00877 
00878         $base = self::baseStorePath();
00879         $files = array(
00880             "$base/unittest-cont1/e/fileA.a",
00881             "$base/unittest-cont1/e/fileB.a",
00882             "$base/unittest-cont1/e/fileC.a"
00883         );
00884         $createOps = array();
00885         $purgeOps = array();
00886         foreach ( $files as $path ) {
00887             $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
00888             $this->assertGoodStatus( $status,
00889                 "Preparing $path succeeded without warnings ($backendName)." );
00890             $createOps[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand( 0, 50000 ) );
00891             $copyOps[] = array( 'op' => 'copy', 'src' => $path, 'dst' => "$path-2" );
00892             $moveOps[] = array( 'op' => 'move', 'src' => "$path-2", 'dst' => "$path-3" );
00893             $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
00894             $purgeOps[] = array( 'op' => 'delete', 'src' => "$path-3" );
00895         }
00896         $purgeOps[] = array( 'op' => 'null' );
00897 
00898         $this->assertGoodStatus(
00899             $this->backend->doQuickOperations( $createOps ),
00900             "Creation of source files succeeded ($backendName)." );
00901         foreach ( $files as $file ) {
00902             $this->assertTrue( $this->backend->fileExists( array( 'src' => $file ) ),
00903                 "File $file exists." );
00904         }
00905 
00906         $this->assertGoodStatus(
00907             $this->backend->doQuickOperations( $copyOps ),
00908             "Quick copy of source files succeeded ($backendName)." );
00909         foreach ( $files as $file ) {
00910             $this->assertTrue( $this->backend->fileExists( array( 'src' => "$file-2" ) ),
00911                 "File $file-2 exists." );
00912         }
00913 
00914         $this->assertGoodStatus(
00915             $this->backend->doQuickOperations( $moveOps ),
00916             "Quick move of source files succeeded ($backendName)." );
00917         foreach ( $files as $file ) {
00918             $this->assertTrue( $this->backend->fileExists( array( 'src' => "$file-3" ) ),
00919                 "File $file-3 move in." );
00920             $this->assertFalse( $this->backend->fileExists( array( 'src' => "$file-2" ) ),
00921                 "File $file-2 moved away." );
00922         }
00923 
00924         $this->assertGoodStatus(
00925             $this->backend->quickCopy( array( 'src' => $files[0], 'dst' => $files[0] ) ),
00926             "Copy of file {$files[0]} over itself succeeded ($backendName)." );
00927         $this->assertTrue( $this->backend->fileExists( array( 'src' => $files[0] ) ),
00928             "File {$files[0]} still exists." );
00929 
00930         $this->assertGoodStatus(
00931             $this->backend->quickMove( array( 'src' => $files[0], 'dst' => $files[0] ) ),
00932             "Move of file {$files[0]} over itself succeeded ($backendName)." );
00933         $this->assertTrue( $this->backend->fileExists( array( 'src' => $files[0] ) ),
00934             "File {$files[0]} still exists." );
00935 
00936         $this->assertGoodStatus(
00937             $this->backend->doQuickOperations( $purgeOps ),
00938             "Quick deletion of source files succeeded ($backendName)." );
00939         foreach ( $files as $file ) {
00940             $this->assertFalse( $this->backend->fileExists( array( 'src' => $file ) ),
00941                 "File $file purged." );
00942             $this->assertFalse( $this->backend->fileExists( array( 'src' => "$file-3" ) ),
00943                 "File $file-3 purged." );
00944         }
00945     }
00946 
00950     public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
00951         $this->filesToPrune[] = $op['dst'];
00952 
00953         $this->backend = $this->singleBackend;
00954         $this->tearDownFiles();
00955         $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
00956         $this->filesToPrune[] = $op['dst']; # avoid file leaking
00957         $this->tearDownFiles();
00958 
00959         $this->backend = $this->multiBackend;
00960         $this->tearDownFiles();
00961         $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
00962         $this->filesToPrune[] = $op['dst']; # avoid file leaking
00963         $this->tearDownFiles();
00964     }
00965 
00966     private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
00967         $backendName = $this->backendClass();
00968 
00969         $expContent = '';
00970         // Create sources
00971         $ops = array();
00972         foreach ( $srcs as $i => $source ) {
00973             $this->prepare( array( 'dir' => dirname( $source ) ) );
00974             $ops[] = array(
00975                 'op' => 'create', // operation
00976                 'dst' => $source, // source
00977                 'content' => $srcsContent[$i]
00978             );
00979             $expContent .= $srcsContent[$i];
00980         }
00981         $status = $this->backend->doOperations( $ops );
00982 
00983         $this->assertGoodStatus( $status,
00984             "Creation of source files succeeded ($backendName)." );
00985 
00986         $dest = $params['dst'];
00987         if ( $alreadyExists ) {
00988             $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
00989             $this->assertEquals( true, $ok,
00990                 "Creation of file at $dest succeeded ($backendName)." );
00991         } else {
00992             $ok = file_put_contents( $dest, '' ) !== false;
00993             $this->assertEquals( true, $ok,
00994                 "Creation of 0-byte file at $dest succeeded ($backendName)." );
00995         }
00996 
00997         // Combine the files into one
00998         $status = $this->backend->concatenate( $params );
00999         if ( $okStatus ) {
01000             $this->assertGoodStatus( $status,
01001                 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
01002             $this->assertEquals( true, $status->isOK(),
01003                 "Creation of concat file at $dest succeeded ($backendName)." );
01004         } else {
01005             $this->assertEquals( false, $status->isOK(),
01006                 "Creation of concat file at $dest failed ($backendName)." );
01007         }
01008 
01009         if ( $okStatus ) {
01010             $this->assertEquals( true, is_file( $dest ),
01011                 "Dest concat file $dest exists after creation ($backendName)." );
01012         } else {
01013             $this->assertEquals( true, is_file( $dest ),
01014                 "Dest concat file $dest exists after failed creation ($backendName)." );
01015         }
01016 
01017         $contents = file_get_contents( $dest );
01018         $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
01019 
01020         if ( $okStatus ) {
01021             $this->assertEquals( $expContent, $contents,
01022                 "Concat file at $dest has correct contents ($backendName)." );
01023         } else {
01024             $this->assertNotEquals( $expContent, $contents,
01025                 "Concat file at $dest has correct contents ($backendName)." );
01026         }
01027     }
01028 
01029     public static function provider_testConcatenate() {
01030         $cases = array();
01031 
01032         $rand = mt_rand( 0, 2000000000 ) . time();
01033         $dest = wfTempDir() . "/randomfile!$rand.txt";
01034         $srcs = array(
01035             self::baseStorePath() . '/unittest-cont1/e/file1.txt',
01036             self::baseStorePath() . '/unittest-cont1/e/file2.txt',
01037             self::baseStorePath() . '/unittest-cont1/e/file3.txt',
01038             self::baseStorePath() . '/unittest-cont1/e/file4.txt',
01039             self::baseStorePath() . '/unittest-cont1/e/file5.txt',
01040             self::baseStorePath() . '/unittest-cont1/e/file6.txt',
01041             self::baseStorePath() . '/unittest-cont1/e/file7.txt',
01042             self::baseStorePath() . '/unittest-cont1/e/file8.txt',
01043             self::baseStorePath() . '/unittest-cont1/e/file9.txt',
01044             self::baseStorePath() . '/unittest-cont1/e/file10.txt'
01045         );
01046         $content = array(
01047             'egfage',
01048             'ageageag',
01049             'rhokohlr',
01050             'shgmslkg',
01051             'kenga',
01052             'owagmal',
01053             'kgmae',
01054             'g eak;g',
01055             'lkaem;a',
01056             'legma'
01057         );
01058         $params = array( 'srcs' => $srcs, 'dst' => $dest );
01059 
01060         $cases[] = array(
01061             $params, // operation
01062             $srcs, // sources
01063             $content, // content for each source
01064             false, // no dest already exists
01065             true, // succeeds
01066         );
01067 
01068         $cases[] = array(
01069             $params, // operation
01070             $srcs, // sources
01071             $content, // content for each source
01072             true, // dest already exists
01073             false, // succeeds
01074         );
01075 
01076         return $cases;
01077     }
01078 
01083     public function testGetFileStat( $path, $content, $alreadyExists ) {
01084         $this->backend = $this->singleBackend;
01085         $this->tearDownFiles();
01086         $this->doTestGetFileStat( $path, $content, $alreadyExists );
01087         $this->tearDownFiles();
01088 
01089         $this->backend = $this->multiBackend;
01090         $this->tearDownFiles();
01091         $this->doTestGetFileStat( $path, $content, $alreadyExists );
01092         $this->tearDownFiles();
01093     }
01094 
01095     private function doTestGetFileStat( $path, $content, $alreadyExists ) {
01096         $backendName = $this->backendClass();
01097 
01098         if ( $alreadyExists ) {
01099             $this->prepare( array( 'dir' => dirname( $path ) ) );
01100             $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
01101             $this->assertGoodStatus( $status,
01102                 "Creation of file at $path succeeded ($backendName)." );
01103 
01104             $size = $this->backend->getFileSize( array( 'src' => $path ) );
01105             $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
01106             $stat = $this->backend->getFileStat( array( 'src' => $path ) );
01107 
01108             $this->assertEquals( strlen( $content ), $size,
01109                 "Correct file size of '$path'" );
01110             $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
01111                 "Correct file timestamp of '$path'" );
01112 
01113             $size = $stat['size'];
01114             $time = $stat['mtime'];
01115             $this->assertEquals( strlen( $content ), $size,
01116                 "Correct file size of '$path'" );
01117             $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
01118                 "Correct file timestamp of '$path'" );
01119 
01120             $this->backend->clearCache( array( $path ) );
01121 
01122             $size = $this->backend->getFileSize( array( 'src' => $path ) );
01123 
01124             $this->assertEquals( strlen( $content ), $size,
01125                 "Correct file size of '$path'" );
01126 
01127             $this->backend->preloadCache( array( $path ) );
01128 
01129             $size = $this->backend->getFileSize( array( 'src' => $path ) );
01130 
01131             $this->assertEquals( strlen( $content ), $size,
01132                 "Correct file size of '$path'" );
01133         } else {
01134             $size = $this->backend->getFileSize( array( 'src' => $path ) );
01135             $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
01136             $stat = $this->backend->getFileStat( array( 'src' => $path ) );
01137 
01138             $this->assertFalse( $size, "Correct file size of '$path'" );
01139             $this->assertFalse( $time, "Correct file timestamp of '$path'" );
01140             $this->assertFalse( $stat, "Correct file stat of '$path'" );
01141         }
01142     }
01143 
01144     public static function provider_testGetFileStat() {
01145         $cases = array();
01146 
01147         $base = self::baseStorePath();
01148         $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
01149         $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
01150         $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
01151 
01152         return $cases;
01153     }
01154 
01159     public function testStreamFile( $path, $content, $alreadyExists ) {
01160         $this->backend = $this->singleBackend;
01161         $this->tearDownFiles();
01162         $this->doTestStreamFile( $path, $content, $alreadyExists );
01163         $this->tearDownFiles();
01164     }
01165 
01166     private function doTestStreamFile( $path, $content ) {
01167         $backendName = $this->backendClass();
01168 
01169         // Test doStreamFile() directly to avoid header madness
01170         $class = new ReflectionClass( $this->backend );
01171         $method = $class->getMethod( 'doStreamFile' );
01172         $method->setAccessible( true );
01173 
01174         if ( $content !== null ) {
01175             $this->prepare( array( 'dir' => dirname( $path ) ) );
01176             $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
01177             $this->assertGoodStatus( $status,
01178                 "Creation of file at $path succeeded ($backendName)." );
01179 
01180             ob_start();
01181             $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
01182             $data = ob_get_contents();
01183             ob_end_clean();
01184 
01185             $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
01186         } else { // 404 case
01187             ob_start();
01188             $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
01189             $data = ob_get_contents();
01190             ob_end_clean();
01191 
01192             $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
01193         }
01194     }
01195 
01196     public static function provider_testStreamFile() {
01197         $cases = array();
01198 
01199         $base = self::baseStorePath();
01200         $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
01201         $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
01202 
01203         return $cases;
01204     }
01205 
01211     public function testGetFileContents( $source, $content ) {
01212         $this->backend = $this->singleBackend;
01213         $this->tearDownFiles();
01214         $this->doTestGetFileContents( $source, $content );
01215         $this->tearDownFiles();
01216 
01217         $this->backend = $this->multiBackend;
01218         $this->tearDownFiles();
01219         $this->doTestGetFileContents( $source, $content );
01220         $this->tearDownFiles();
01221     }
01222 
01223     private function doTestGetFileContents( $source, $content ) {
01224         $backendName = $this->backendClass();
01225 
01226         $srcs = (array)$source;
01227         $content = (array)$content;
01228         foreach ( $srcs as $i => $src ) {
01229             $this->prepare( array( 'dir' => dirname( $src ) ) );
01230             $status = $this->backend->doOperation(
01231                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
01232             $this->assertGoodStatus( $status,
01233                 "Creation of file at $src succeeded ($backendName)." );
01234         }
01235 
01236         if ( is_array( $source ) ) {
01237             $contents = $this->backend->getFileContentsMulti( array( 'srcs' => $source ) );
01238             foreach ( $contents as $path => $data ) {
01239                 $this->assertNotEquals( false, $data, "Contents of $path exists ($backendName)." );
01240                 $this->assertEquals(
01241                     current( $content ),
01242                     $data,
01243                     "Contents of $path is correct ($backendName)."
01244                 );
01245                 next( $content );
01246             }
01247             $this->assertEquals(
01248                 $source,
01249                 array_keys( $contents ),
01250                 "Contents in right order ($backendName)."
01251             );
01252             $this->assertEquals(
01253                 count( $source ),
01254                 count( $contents ),
01255                 "Contents array size correct ($backendName)."
01256             );
01257         } else {
01258             $data = $this->backend->getFileContents( array( 'src' => $source ) );
01259             $this->assertNotEquals( false, $data, "Contents of $source exists ($backendName)." );
01260             $this->assertEquals( $content[0], $data, "Contents of $source is correct ($backendName)." );
01261         }
01262     }
01263 
01264     public static function provider_testGetFileContents() {
01265         $cases = array();
01266 
01267         $base = self::baseStorePath();
01268         $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
01269         $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
01270         $cases[] = array(
01271             array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01272                 "$base/unittest-cont1/e/a/z.txt" ),
01273             array( "contents xx", "contents xy", "contents xz" )
01274         );
01275 
01276         return $cases;
01277     }
01278 
01283     public function testGetLocalCopy( $source, $content ) {
01284         $this->backend = $this->singleBackend;
01285         $this->tearDownFiles();
01286         $this->doTestGetLocalCopy( $source, $content );
01287         $this->tearDownFiles();
01288 
01289         $this->backend = $this->multiBackend;
01290         $this->tearDownFiles();
01291         $this->doTestGetLocalCopy( $source, $content );
01292         $this->tearDownFiles();
01293     }
01294 
01295     private function doTestGetLocalCopy( $source, $content ) {
01296         $backendName = $this->backendClass();
01297 
01298         $srcs = (array)$source;
01299         $content = (array)$content;
01300         foreach ( $srcs as $i => $src ) {
01301             $this->prepare( array( 'dir' => dirname( $src ) ) );
01302             $status = $this->backend->doOperation(
01303                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
01304             $this->assertGoodStatus( $status,
01305                 "Creation of file at $src succeeded ($backendName)." );
01306         }
01307 
01308         if ( is_array( $source ) ) {
01309             $tmpFiles = $this->backend->getLocalCopyMulti( array( 'srcs' => $source ) );
01310             foreach ( $tmpFiles as $path => $tmpFile ) {
01311                 $this->assertNotNull( $tmpFile,
01312                     "Creation of local copy of $path succeeded ($backendName)." );
01313                 $contents = file_get_contents( $tmpFile->getPath() );
01314                 $this->assertNotEquals( false, $contents, "Local copy of $path exists ($backendName)." );
01315                 $this->assertEquals(
01316                     current( $content ),
01317                     $contents,
01318                     "Local copy of $path is correct ($backendName)."
01319                 );
01320                 next( $content );
01321             }
01322             $this->assertEquals(
01323                 $source,
01324                 array_keys( $tmpFiles ),
01325                 "Local copies in right order ($backendName)."
01326             );
01327             $this->assertEquals(
01328                 count( $source ),
01329                 count( $tmpFiles ),
01330                 "Local copies array size correct ($backendName)."
01331             );
01332         } else {
01333             $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
01334             $this->assertNotNull( $tmpFile,
01335                 "Creation of local copy of $source succeeded ($backendName)." );
01336             $contents = file_get_contents( $tmpFile->getPath() );
01337             $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
01338             $this->assertEquals(
01339                 $content[0],
01340                 $contents,
01341                 "Local copy of $source is correct ($backendName)."
01342             );
01343         }
01344 
01345         $obj = new stdClass();
01346         $tmpFile->bind( $obj );
01347     }
01348 
01349     public static function provider_testGetLocalCopy() {
01350         $cases = array();
01351 
01352         $base = self::baseStorePath();
01353         $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01354         $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01355         $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01356         $cases[] = array(
01357             array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01358                 "$base/unittest-cont1/e/a/z.txt" ),
01359             array( "contents xx $", "contents xy 111", "contents xz" )
01360         );
01361 
01362         return $cases;
01363     }
01364 
01369     public function testGetLocalReference( $source, $content ) {
01370         $this->backend = $this->singleBackend;
01371         $this->tearDownFiles();
01372         $this->doTestGetLocalReference( $source, $content );
01373         $this->tearDownFiles();
01374 
01375         $this->backend = $this->multiBackend;
01376         $this->tearDownFiles();
01377         $this->doTestGetLocalReference( $source, $content );
01378         $this->tearDownFiles();
01379     }
01380 
01381     private function doTestGetLocalReference( $source, $content ) {
01382         $backendName = $this->backendClass();
01383 
01384         $srcs = (array)$source;
01385         $content = (array)$content;
01386         foreach ( $srcs as $i => $src ) {
01387             $this->prepare( array( 'dir' => dirname( $src ) ) );
01388             $status = $this->backend->doOperation(
01389                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
01390             $this->assertGoodStatus( $status,
01391                 "Creation of file at $src succeeded ($backendName)." );
01392         }
01393 
01394         if ( is_array( $source ) ) {
01395             $tmpFiles = $this->backend->getLocalReferenceMulti( array( 'srcs' => $source ) );
01396             foreach ( $tmpFiles as $path => $tmpFile ) {
01397                 $this->assertNotNull( $tmpFile,
01398                     "Creation of local copy of $path succeeded ($backendName)." );
01399                 $contents = file_get_contents( $tmpFile->getPath() );
01400                 $this->assertNotEquals( false, $contents, "Local ref of $path exists ($backendName)." );
01401                 $this->assertEquals(
01402                     current( $content ),
01403                     $contents,
01404                     "Local ref of $path is correct ($backendName)."
01405                 );
01406                 next( $content );
01407             }
01408             $this->assertEquals(
01409                 $source,
01410                 array_keys( $tmpFiles ),
01411                 "Local refs in right order ($backendName)."
01412             );
01413             $this->assertEquals(
01414                 count( $source ),
01415                 count( $tmpFiles ),
01416                 "Local refs array size correct ($backendName)."
01417             );
01418         } else {
01419             $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
01420             $this->assertNotNull( $tmpFile,
01421                 "Creation of local copy of $source succeeded ($backendName)." );
01422             $contents = file_get_contents( $tmpFile->getPath() );
01423             $this->assertNotEquals( false, $contents, "Local ref of $source exists ($backendName)." );
01424             $this->assertEquals( $content[0], $contents, "Local ref of $source is correct ($backendName)." );
01425         }
01426     }
01427 
01428     public static function provider_testGetLocalReference() {
01429         $cases = array();
01430 
01431         $base = self::baseStorePath();
01432         $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01433         $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01434         $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01435         $cases[] = array(
01436             array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01437                 "$base/unittest-cont1/e/a/z.txt" ),
01438             array( "contents xx 1111", "contents xy %", "contents xz $" )
01439         );
01440 
01441         return $cases;
01442     }
01443 
01448     public function testGetLocalCopyAndReference404() {
01449         $this->backend = $this->singleBackend;
01450         $this->tearDownFiles();
01451         $this->doTestGetLocalCopyAndReference404();
01452         $this->tearDownFiles();
01453 
01454         $this->backend = $this->multiBackend;
01455         $this->tearDownFiles();
01456         $this->doTestGetLocalCopyAndReference404();
01457         $this->tearDownFiles();
01458     }
01459 
01460     public function doTestGetLocalCopyAndReference404() {
01461         $backendName = $this->backendClass();
01462 
01463         $base = self::baseStorePath();
01464 
01465         $tmpFile = $this->backend->getLocalCopy( array(
01466             'src' => "$base/unittest-cont1/not-there" ) );
01467         $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
01468 
01469         $tmpFile = $this->backend->getLocalReference( array(
01470             'src' => "$base/unittest-cont1/not-there" ) );
01471         $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
01472     }
01473 
01478     public function testGetFileHttpUrl( $source, $content ) {
01479         $this->backend = $this->singleBackend;
01480         $this->tearDownFiles();
01481         $this->doTestGetFileHttpUrl( $source, $content );
01482         $this->tearDownFiles();
01483 
01484         $this->backend = $this->multiBackend;
01485         $this->tearDownFiles();
01486         $this->doTestGetFileHttpUrl( $source, $content );
01487         $this->tearDownFiles();
01488     }
01489 
01490     private function doTestGetFileHttpUrl( $source, $content ) {
01491         $backendName = $this->backendClass();
01492 
01493         $this->prepare( array( 'dir' => dirname( $source ) ) );
01494         $status = $this->backend->doOperation(
01495             array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
01496         $this->assertGoodStatus( $status,
01497             "Creation of file at $source succeeded ($backendName)." );
01498 
01499         $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) );
01500 
01501         if ( $url !== null ) { // supported
01502             $data = Http::request( "GET", $url );
01503             $this->assertEquals( $content, $data,
01504                 "HTTP GET of URL has right contents ($backendName)." );
01505         }
01506     }
01507 
01508     public static function provider_testGetFileHttpUrl() {
01509         $cases = array();
01510 
01511         $base = self::baseStorePath();
01512         $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01513         $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01514         $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01515 
01516         return $cases;
01517     }
01518 
01524     public function testPrepareAndClean( $path, $isOK ) {
01525         $this->backend = $this->singleBackend;
01526         $this->doTestPrepareAndClean( $path, $isOK );
01527         $this->tearDownFiles();
01528 
01529         $this->backend = $this->multiBackend;
01530         $this->doTestPrepareAndClean( $path, $isOK );
01531         $this->tearDownFiles();
01532     }
01533 
01534     public static function provider_testPrepareAndClean() {
01535         $base = self::baseStorePath();
01536 
01537         return array(
01538             array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
01539             array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
01540             # Specific to FS backend with no basePath field set
01541             #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
01542         );
01543     }
01544 
01545     private function doTestPrepareAndClean( $path, $isOK ) {
01546         $backendName = $this->backendClass();
01547 
01548         $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
01549         if ( $isOK ) {
01550             $this->assertGoodStatus( $status,
01551                 "Preparing dir $path succeeded without warnings ($backendName)." );
01552             $this->assertEquals( true, $status->isOK(),
01553                 "Preparing dir $path succeeded ($backendName)." );
01554         } else {
01555             $this->assertEquals( false, $status->isOK(),
01556                 "Preparing dir $path failed ($backendName)." );
01557         }
01558 
01559         $status = $this->backend->secure( array( 'dir' => dirname( $path ) ) );
01560         if ( $isOK ) {
01561             $this->assertGoodStatus( $status,
01562                 "Securing dir $path succeeded without warnings ($backendName)." );
01563             $this->assertEquals( true, $status->isOK(),
01564                 "Securing dir $path succeeded ($backendName)." );
01565         } else {
01566             $this->assertEquals( false, $status->isOK(),
01567                 "Securing dir $path failed ($backendName)." );
01568         }
01569 
01570         $status = $this->backend->publish( array( 'dir' => dirname( $path ) ) );
01571         if ( $isOK ) {
01572             $this->assertGoodStatus( $status,
01573                 "Publishing dir $path succeeded without warnings ($backendName)." );
01574             $this->assertEquals( true, $status->isOK(),
01575                 "Publishing dir $path succeeded ($backendName)." );
01576         } else {
01577             $this->assertEquals( false, $status->isOK(),
01578                 "Publishing dir $path failed ($backendName)." );
01579         }
01580 
01581         $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
01582         if ( $isOK ) {
01583             $this->assertGoodStatus( $status,
01584                 "Cleaning dir $path succeeded without warnings ($backendName)." );
01585             $this->assertEquals( true, $status->isOK(),
01586                 "Cleaning dir $path succeeded ($backendName)." );
01587         } else {
01588             $this->assertEquals( false, $status->isOK(),
01589                 "Cleaning dir $path failed ($backendName)." );
01590         }
01591     }
01592 
01593     public function testRecursiveClean() {
01594         $this->backend = $this->singleBackend;
01595         $this->doTestRecursiveClean();
01596         $this->tearDownFiles();
01597 
01598         $this->backend = $this->multiBackend;
01599         $this->doTestRecursiveClean();
01600         $this->tearDownFiles();
01601     }
01602 
01606     private function doTestRecursiveClean() {
01607         $backendName = $this->backendClass();
01608 
01609         $base = self::baseStorePath();
01610         $dirs = array(
01611             "$base/unittest-cont1",
01612             "$base/unittest-cont1/e",
01613             "$base/unittest-cont1/e/a",
01614             "$base/unittest-cont1/e/a/b",
01615             "$base/unittest-cont1/e/a/b/c",
01616             "$base/unittest-cont1/e/a/b/c/d0",
01617             "$base/unittest-cont1/e/a/b/c/d1",
01618             "$base/unittest-cont1/e/a/b/c/d2",
01619             "$base/unittest-cont1/e/a/b/c/d0/1",
01620             "$base/unittest-cont1/e/a/b/c/d0/2",
01621             "$base/unittest-cont1/e/a/b/c/d1/3",
01622             "$base/unittest-cont1/e/a/b/c/d1/4",
01623             "$base/unittest-cont1/e/a/b/c/d2/5",
01624             "$base/unittest-cont1/e/a/b/c/d2/6"
01625         );
01626         foreach ( $dirs as $dir ) {
01627             $status = $this->prepare( array( 'dir' => $dir ) );
01628             $this->assertGoodStatus( $status,
01629                 "Preparing dir $dir succeeded without warnings ($backendName)." );
01630         }
01631 
01632         if ( $this->backend instanceof FSFileBackend ) {
01633             foreach ( $dirs as $dir ) {
01634                 $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ),
01635                     "Dir $dir exists ($backendName)." );
01636             }
01637         }
01638 
01639         $status = $this->backend->clean(
01640             array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
01641         $this->assertGoodStatus( $status,
01642             "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
01643 
01644         foreach ( $dirs as $dir ) {
01645             $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ),
01646                 "Dir $dir no longer exists ($backendName)." );
01647         }
01648     }
01649 
01653     public function testDoOperations() {
01654         $this->backend = $this->singleBackend;
01655         $this->tearDownFiles();
01656         $this->doTestDoOperations();
01657         $this->tearDownFiles();
01658 
01659         $this->backend = $this->multiBackend;
01660         $this->tearDownFiles();
01661         $this->doTestDoOperations();
01662         $this->tearDownFiles();
01663     }
01664 
01665     private function doTestDoOperations() {
01666         $base = self::baseStorePath();
01667 
01668         $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
01669         $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01670         $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
01671         $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01672         $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
01673         $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01674         $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
01675 
01676         $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01677         $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01678         $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01679         $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
01680         $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01681         $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
01682         $this->prepare( array( 'dir' => dirname( $fileD ) ) );
01683 
01684         $status = $this->backend->doOperations( array(
01685             array( 'op' => 'describe', 'src' => $fileA,
01686                 'headers' => array( 'X-Content-Length' => '91.3' ), 'disposition' => 'inline' ),
01687             array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01688             // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01689             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01690             // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01691             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
01692             // Now: A:<A>, B:<B>, C:<empty>, D:<A>
01693             array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
01694             // Now: A:<A>, B:<empty>, C:<B>, D:<A>
01695             array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
01696             // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
01697             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
01698             // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
01699             array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
01700             // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
01701             array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
01702             // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
01703             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01704             // Does nothing
01705             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01706             // Does nothing
01707             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01708             // Does nothing
01709             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01710             // Does nothing
01711             array( 'op' => 'null' ),
01712             // Does nothing
01713         ) );
01714 
01715         $this->assertGoodStatus( $status, "Operation batch succeeded" );
01716         $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01717         $this->assertEquals( 14, count( $status->success ),
01718             "Operation batch has correct success array" );
01719 
01720         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
01721             "File does not exist at $fileA" );
01722         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01723             "File does not exist at $fileB" );
01724         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01725             "File does not exist at $fileD" );
01726 
01727         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01728             "File exists at $fileC" );
01729         $this->assertEquals( $fileBContents,
01730             $this->backend->getFileContents( array( 'src' => $fileC ) ),
01731             "Correct file contents of $fileC" );
01732         $this->assertEquals( strlen( $fileBContents ),
01733             $this->backend->getFileSize( array( 'src' => $fileC ) ),
01734             "Correct file size of $fileC" );
01735         $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01736             $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
01737             "Correct file SHA-1 of $fileC" );
01738     }
01739 
01743     public function testDoOperationsPipeline() {
01744         $this->backend = $this->singleBackend;
01745         $this->tearDownFiles();
01746         $this->doTestDoOperationsPipeline();
01747         $this->tearDownFiles();
01748 
01749         $this->backend = $this->multiBackend;
01750         $this->tearDownFiles();
01751         $this->doTestDoOperationsPipeline();
01752         $this->tearDownFiles();
01753     }
01754 
01755     // concurrency orientated
01756     private function doTestDoOperationsPipeline() {
01757         $base = self::baseStorePath();
01758 
01759         $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01760         $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01761         $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01762 
01763         $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01764         file_put_contents( $tmpNameA, $fileAContents );
01765         $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01766         file_put_contents( $tmpNameB, $fileBContents );
01767         $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01768         file_put_contents( $tmpNameC, $fileCContents );
01769 
01770         $this->filesToPrune[] = $tmpNameA; # avoid file leaking
01771         $this->filesToPrune[] = $tmpNameB; # avoid file leaking
01772         $this->filesToPrune[] = $tmpNameC; # avoid file leaking
01773 
01774         $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
01775         $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
01776         $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
01777         $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
01778 
01779         $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01780         $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01781         $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01782         $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01783         $this->prepare( array( 'dir' => dirname( $fileD ) ) );
01784 
01785         $status = $this->backend->doOperations( array(
01786             array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
01787             array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
01788             array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
01789             array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01790             // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01791             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01792             // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01793             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
01794             // Now: A:<A>, B:<B>, C:<empty>, D:<A>
01795             array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
01796             // Now: A:<A>, B:<empty>, C:<B>, D:<A>
01797             array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
01798             // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
01799             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
01800             // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
01801             array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
01802             // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
01803             array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
01804             // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
01805             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01806             // Does nothing
01807             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01808             // Does nothing
01809             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01810             // Does nothing
01811             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01812             // Does nothing
01813             array( 'op' => 'null' ),
01814             // Does nothing
01815         ) );
01816 
01817         $this->assertGoodStatus( $status, "Operation batch succeeded" );
01818         $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01819         $this->assertEquals( 16, count( $status->success ),
01820             "Operation batch has correct success array" );
01821 
01822         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
01823             "File does not exist at $fileA" );
01824         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01825             "File does not exist at $fileB" );
01826         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01827             "File does not exist at $fileD" );
01828 
01829         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01830             "File exists at $fileC" );
01831         $this->assertEquals( $fileBContents,
01832             $this->backend->getFileContents( array( 'src' => $fileC ) ),
01833             "Correct file contents of $fileC" );
01834         $this->assertEquals( strlen( $fileBContents ),
01835             $this->backend->getFileSize( array( 'src' => $fileC ) ),
01836             "Correct file size of $fileC" );
01837         $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01838             $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
01839             "Correct file SHA-1 of $fileC" );
01840     }
01841 
01845     public function testDoOperationsFailing() {
01846         $this->backend = $this->singleBackend;
01847         $this->tearDownFiles();
01848         $this->doTestDoOperationsFailing();
01849         $this->tearDownFiles();
01850 
01851         $this->backend = $this->multiBackend;
01852         $this->tearDownFiles();
01853         $this->doTestDoOperationsFailing();
01854         $this->tearDownFiles();
01855     }
01856 
01857     private function doTestDoOperationsFailing() {
01858         $base = self::baseStorePath();
01859 
01860         $fileA = "$base/unittest-cont2/a/b/fileA.txt";
01861         $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01862         $fileB = "$base/unittest-cont2/a/b/fileB.txt";
01863         $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01864         $fileC = "$base/unittest-cont2/a/b/fileC.txt";
01865         $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01866         $fileD = "$base/unittest-cont2/a/b/fileD.txt";
01867 
01868         $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01869         $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01870         $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01871         $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
01872         $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01873         $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
01874 
01875         $status = $this->backend->doOperations( array(
01876             array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01877             // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01878             array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01879             // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01880             array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
01881             // Now: A:<A>, B:<B>, C:<A>, D:<B>
01882             array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
01883             // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
01884             array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
01885             // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
01886             array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
01887             // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
01888             array( 'op' => 'delete', 'src' => $fileD ),
01889             // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
01890             array( 'op' => 'null' ),
01891             // Does nothing
01892         ), array( 'force' => 1 ) );
01893 
01894         $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
01895         $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01896         $this->assertEquals( 8, count( $status->success ),
01897             "Operation batch has correct success array" );
01898 
01899         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01900             "File does not exist at $fileB" );
01901         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01902             "File does not exist at $fileD" );
01903 
01904         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
01905             "File does not exist at $fileA" );
01906         $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01907             "File exists at $fileC" );
01908         $this->assertEquals( $fileBContents,
01909             $this->backend->getFileContents( array( 'src' => $fileA ) ),
01910             "Correct file contents of $fileA" );
01911         $this->assertEquals( strlen( $fileBContents ),
01912             $this->backend->getFileSize( array( 'src' => $fileA ) ),
01913             "Correct file size of $fileA" );
01914         $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01915             $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
01916             "Correct file SHA-1 of $fileA" );
01917     }
01918 
01922     public function testGetFileList() {
01923         $this->backend = $this->singleBackend;
01924         $this->tearDownFiles();
01925         $this->doTestGetFileList();
01926         $this->tearDownFiles();
01927 
01928         $this->backend = $this->multiBackend;
01929         $this->tearDownFiles();
01930         $this->doTestGetFileList();
01931         $this->tearDownFiles();
01932     }
01933 
01934     private function doTestGetFileList() {
01935         $backendName = $this->backendClass();
01936         $base = self::baseStorePath();
01937 
01938         // Should have no errors
01939         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
01940 
01941         $files = array(
01942             "$base/unittest-cont1/e/test1.txt",
01943             "$base/unittest-cont1/e/test2.txt",
01944             "$base/unittest-cont1/e/test3.txt",
01945             "$base/unittest-cont1/e/subdir1/test1.txt",
01946             "$base/unittest-cont1/e/subdir1/test2.txt",
01947             "$base/unittest-cont1/e/subdir2/test3.txt",
01948             "$base/unittest-cont1/e/subdir2/test4.txt",
01949             "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
01950             "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
01951             "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
01952             "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
01953             "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
01954             "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
01955             "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
01956         );
01957 
01958         // Add the files
01959         $ops = array();
01960         foreach ( $files as $file ) {
01961             $this->prepare( array( 'dir' => dirname( $file ) ) );
01962             $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
01963         }
01964         $status = $this->backend->doQuickOperations( $ops );
01965         $this->assertGoodStatus( $status,
01966             "Creation of files succeeded ($backendName)." );
01967         $this->assertEquals( true, $status->isOK(),
01968             "Creation of files succeeded with OK status ($backendName)." );
01969 
01970         // Expected listing at root
01971         $expected = array(
01972             "e/test1.txt",
01973             "e/test2.txt",
01974             "e/test3.txt",
01975             "e/subdir1/test1.txt",
01976             "e/subdir1/test2.txt",
01977             "e/subdir2/test3.txt",
01978             "e/subdir2/test4.txt",
01979             "e/subdir2/subdir/test1.txt",
01980             "e/subdir2/subdir/test2.txt",
01981             "e/subdir2/subdir/test3.txt",
01982             "e/subdir2/subdir/test4.txt",
01983             "e/subdir2/subdir/test5.txt",
01984             "e/subdir2/subdir/sub/test0.txt",
01985             "e/subdir2/subdir/sub/120-px-file.txt",
01986         );
01987         sort( $expected );
01988 
01989         // Actual listing (no trailing slash) at root
01990         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
01991         $list = $this->listToArray( $iter );
01992         sort( $list );
01993         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
01994 
01995         // Actual listing (no trailing slash) at root with advise
01996         $iter = $this->backend->getFileList( array(
01997             'dir' => "$base/unittest-cont1",
01998             'adviseStat' => 1
01999         ) );
02000         $list = $this->listToArray( $iter );
02001         sort( $list );
02002         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
02003 
02004         // Actual listing (with trailing slash) at root
02005         $list = array();
02006         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
02007         foreach ( $iter as $file ) {
02008             $list[] = $file;
02009         }
02010         sort( $list );
02011         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
02012 
02013         // Expected listing at subdir
02014         $expected = array(
02015             "test1.txt",
02016             "test2.txt",
02017             "test3.txt",
02018             "test4.txt",
02019             "test5.txt",
02020             "sub/test0.txt",
02021             "sub/120-px-file.txt",
02022         );
02023         sort( $expected );
02024 
02025         // Actual listing (no trailing slash) at subdir
02026         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
02027         $list = $this->listToArray( $iter );
02028         sort( $list );
02029         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
02030 
02031         // Actual listing (no trailing slash) at subdir with advise
02032         $iter = $this->backend->getFileList( array(
02033             'dir' => "$base/unittest-cont1/e/subdir2/subdir",
02034             'adviseStat' => 1
02035         ) );
02036         $list = $this->listToArray( $iter );
02037         sort( $list );
02038         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
02039 
02040         // Actual listing (with trailing slash) at subdir
02041         $list = array();
02042         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
02043         foreach ( $iter as $file ) {
02044             $list[] = $file;
02045         }
02046         sort( $list );
02047         $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
02048 
02049         // Actual listing (using iterator second time)
02050         $list = $this->listToArray( $iter );
02051         sort( $list );
02052         $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
02053 
02054         // Actual listing (top files only) at root
02055         $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1" ) );
02056         $list = $this->listToArray( $iter );
02057         sort( $list );
02058         $this->assertEquals( array(), $list, "Correct top file listing ($backendName)." );
02059 
02060         // Expected listing (top files only) at subdir
02061         $expected = array(
02062             "test1.txt",
02063             "test2.txt",
02064             "test3.txt",
02065             "test4.txt",
02066             "test5.txt"
02067         );
02068         sort( $expected );
02069 
02070         // Actual listing (top files only) at subdir
02071         $iter = $this->backend->getTopFileList(
02072             array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" )
02073         );
02074         $list = $this->listToArray( $iter );
02075         sort( $list );
02076         $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
02077 
02078         // Actual listing (top files only) at subdir with advise
02079         $iter = $this->backend->getTopFileList( array(
02080             'dir' => "$base/unittest-cont1/e/subdir2/subdir",
02081             'adviseStat' => 1
02082         ) );
02083         $list = $this->listToArray( $iter );
02084         sort( $list );
02085         $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
02086 
02087         foreach ( $files as $file ) { // clean up
02088             $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
02089         }
02090 
02091         $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
02092         foreach ( $iter as $iter ) {
02093             // no errors
02094         }
02095     }
02096 
02101     public function testGetDirectoryList() {
02102         $this->backend = $this->singleBackend;
02103         $this->tearDownFiles();
02104         $this->doTestGetDirectoryList();
02105         $this->tearDownFiles();
02106 
02107         $this->backend = $this->multiBackend;
02108         $this->tearDownFiles();
02109         $this->doTestGetDirectoryList();
02110         $this->tearDownFiles();
02111     }
02112 
02113     private function doTestGetDirectoryList() {
02114         $backendName = $this->backendClass();
02115 
02116         $base = self::baseStorePath();
02117         $files = array(
02118             "$base/unittest-cont1/e/test1.txt",
02119             "$base/unittest-cont1/e/test2.txt",
02120             "$base/unittest-cont1/e/test3.txt",
02121             "$base/unittest-cont1/e/subdir1/test1.txt",
02122             "$base/unittest-cont1/e/subdir1/test2.txt",
02123             "$base/unittest-cont1/e/subdir2/test3.txt",
02124             "$base/unittest-cont1/e/subdir2/test4.txt",
02125             "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
02126             "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
02127             "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
02128             "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
02129             "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
02130             "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
02131             "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
02132         );
02133 
02134         // Add the files
02135         $ops = array();
02136         foreach ( $files as $file ) {
02137             $this->prepare( array( 'dir' => dirname( $file ) ) );
02138             $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
02139         }
02140         $status = $this->backend->doQuickOperations( $ops );
02141         $this->assertGoodStatus( $status,
02142             "Creation of files succeeded ($backendName)." );
02143         $this->assertEquals( true, $status->isOK(),
02144             "Creation of files succeeded with OK status ($backendName)." );
02145 
02146         $this->assertEquals( true,
02147             $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
02148             "Directory exists in ($backendName)." );
02149         $this->assertEquals( true,
02150             $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
02151             "Directory exists in ($backendName)." );
02152         $this->assertEquals( false,
02153             $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
02154             "Directory does not exists in ($backendName)." );
02155 
02156         // Expected listing
02157         $expected = array(
02158             "e",
02159         );
02160         sort( $expected );
02161 
02162         // Actual listing (no trailing slash)
02163         $list = array();
02164         $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
02165         foreach ( $iter as $file ) {
02166             $list[] = $file;
02167         }
02168         sort( $list );
02169 
02170         $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
02171 
02172         // Expected listing
02173         $expected = array(
02174             "subdir1",
02175             "subdir2",
02176             "subdir3",
02177             "subdir4",
02178         );
02179         sort( $expected );
02180 
02181         // Actual listing (no trailing slash)
02182         $list = array();
02183         $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
02184         foreach ( $iter as $file ) {
02185             $list[] = $file;
02186         }
02187         sort( $list );
02188 
02189         $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
02190 
02191         // Actual listing (with trailing slash)
02192         $list = array();
02193         $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
02194         foreach ( $iter as $file ) {
02195             $list[] = $file;
02196         }
02197         sort( $list );
02198 
02199         $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
02200 
02201         // Expected listing
02202         $expected = array(
02203             "subdir",
02204         );
02205         sort( $expected );
02206 
02207         // Actual listing (no trailing slash)
02208         $list = array();
02209         $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
02210         foreach ( $iter as $file ) {
02211             $list[] = $file;
02212         }
02213         sort( $list );
02214 
02215         $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
02216 
02217         // Actual listing (with trailing slash)
02218         $list = array();
02219         $iter = $this->backend->getTopDirectoryList(
02220             array( 'dir' => "$base/unittest-cont1/e/subdir2/" )
02221         );
02222 
02223         foreach ( $iter as $file ) {
02224             $list[] = $file;
02225         }
02226         sort( $list );
02227 
02228         $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
02229 
02230         // Actual listing (using iterator second time)
02231         $list = array();
02232         foreach ( $iter as $file ) {
02233             $list[] = $file;
02234         }
02235         sort( $list );
02236 
02237         $this->assertEquals(
02238             $expected,
02239             $list,
02240             "Correct top dir listing ($backendName), second iteration."
02241         );
02242 
02243         // Expected listing (recursive)
02244         $expected = array(
02245             "e",
02246             "e/subdir1",
02247             "e/subdir2",
02248             "e/subdir3",
02249             "e/subdir4",
02250             "e/subdir2/subdir",
02251             "e/subdir3/subdir",
02252             "e/subdir4/subdir",
02253             "e/subdir4/subdir/sub",
02254         );
02255         sort( $expected );
02256 
02257         // Actual listing (recursive)
02258         $list = array();
02259         $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
02260         foreach ( $iter as $file ) {
02261             $list[] = $file;
02262         }
02263         sort( $list );
02264 
02265         $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
02266 
02267         // Expected listing (recursive)
02268         $expected = array(
02269             "subdir",
02270             "subdir/sub",
02271         );
02272         sort( $expected );
02273 
02274         // Actual listing (recursive)
02275         $list = array();
02276         $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
02277         foreach ( $iter as $file ) {
02278             $list[] = $file;
02279         }
02280         sort( $list );
02281 
02282         $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
02283 
02284         // Actual listing (recursive, second time)
02285         $list = array();
02286         foreach ( $iter as $file ) {
02287             $list[] = $file;
02288         }
02289         sort( $list );
02290 
02291         $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
02292 
02293         $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) );
02294         $items = $this->listToArray( $iter );
02295         $this->assertEquals( array(), $items, "Directory listing is empty." );
02296 
02297         foreach ( $files as $file ) { // clean up
02298             $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
02299         }
02300 
02301         $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
02302         foreach ( $iter as $file ) {
02303             // no errors
02304         }
02305 
02306         $items = $this->listToArray( $iter );
02307         $this->assertEquals( array(), $items, "Directory listing is empty." );
02308 
02309         $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/not/exists" ) );
02310         $items = $this->listToArray( $iter );
02311         $this->assertEquals( array(), $items, "Directory listing is empty." );
02312     }
02313 
02318     public function testLockCalls() {
02319         $this->backend = $this->singleBackend;
02320         $this->doTestLockCalls();
02321     }
02322 
02323     private function doTestLockCalls() {
02324         $backendName = $this->backendClass();
02325 
02326         $paths = array(
02327             "test1.txt",
02328             "test2.txt",
02329             "test3.txt",
02330             "subdir1",
02331             "subdir1", // duplicate
02332             "subdir1/test1.txt",
02333             "subdir1/test2.txt",
02334             "subdir2",
02335             "subdir2", // duplicate
02336             "subdir2/test3.txt",
02337             "subdir2/test4.txt",
02338             "subdir2/subdir",
02339             "subdir2/subdir/test1.txt",
02340             "subdir2/subdir/test2.txt",
02341             "subdir2/subdir/test3.txt",
02342             "subdir2/subdir/test4.txt",
02343             "subdir2/subdir/test5.txt",
02344             "subdir2/subdir/sub",
02345             "subdir2/subdir/sub/test0.txt",
02346             "subdir2/subdir/sub/120-px-file.txt",
02347         );
02348 
02349         for ( $i = 0; $i < 25; $i++ ) {
02350             $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
02351             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02352                 "Locking of files succeeded ($backendName) ($i)." );
02353             $this->assertEquals( true, $status->isOK(),
02354                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02355 
02356             $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
02357             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02358                 "Locking of files succeeded ($backendName) ($i)." );
02359             $this->assertEquals( true, $status->isOK(),
02360                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02361 
02362             $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
02363             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02364                 "Locking of files succeeded ($backendName) ($i)." );
02365             $this->assertEquals( true, $status->isOK(),
02366                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02367 
02368             $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
02369             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02370                 "Locking of files succeeded ($backendName). ($i)" );
02371             $this->assertEquals( true, $status->isOK(),
02372                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02373 
02374             ## Flip the acquire/release ordering around ##
02375 
02376             $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
02377             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02378                 "Locking of files succeeded ($backendName) ($i)." );
02379             $this->assertEquals( true, $status->isOK(),
02380                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02381 
02382             $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
02383             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02384                 "Locking of files succeeded ($backendName) ($i)." );
02385             $this->assertEquals( true, $status->isOK(),
02386                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02387 
02388             $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
02389             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02390                 "Locking of files succeeded ($backendName). ($i)" );
02391             $this->assertEquals( true, $status->isOK(),
02392                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02393 
02394             $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
02395             $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
02396                 "Locking of files succeeded ($backendName) ($i)." );
02397             $this->assertEquals( true, $status->isOK(),
02398                 "Locking of files succeeded with OK status ($backendName) ($i)." );
02399         }
02400 
02401         $status = Status::newGood();
02402         $sl = $this->backend->getScopedFileLocks( $paths, LockManager::LOCK_EX, $status );
02403         $this->assertType( 'ScopedLock', $sl,
02404             "Scoped locking of files succeeded ($backendName)." );
02405         $this->assertEquals( array(), $status->errors,
02406             "Scoped locking of files succeeded ($backendName)." );
02407         $this->assertEquals( true, $status->isOK(),
02408             "Scoped locking of files succeeded with OK status ($backendName)." );
02409 
02410         ScopedLock::release( $sl );
02411         $this->assertEquals( null, $sl,
02412             "Scoped unlocking of files succeeded ($backendName)." );
02413         $this->assertEquals( array(), $status->errors,
02414             "Scoped unlocking of files succeeded ($backendName)." );
02415         $this->assertEquals( true, $status->isOK(),
02416             "Scoped unlocking of files succeeded with OK status ($backendName)." );
02417     }
02418 
02419     // helper function
02420     private function listToArray( $iter ) {
02421         return is_array( $iter ) ? $iter : iterator_to_array( $iter );
02422     }
02423 
02424     // test helper wrapper for backend prepare() function
02425     private function prepare( array $params ) {
02426         return $this->backend->prepare( $params );
02427     }
02428 
02429     // test helper wrapper for backend prepare() function
02430     private function create( array $params ) {
02431         $params['op'] = 'create';
02432 
02433         return $this->backend->doQuickOperations( array( $params ) );
02434     }
02435 
02436     function tearDownFiles() {
02437         foreach ( $this->filesToPrune as $file ) {
02438             if ( is_file( $file ) ) {
02439                 unlink( $file );
02440             }
02441         }
02442         $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont-bad' );
02443         foreach ( $containers as $container ) {
02444             $this->deleteFiles( $container );
02445         }
02446         $this->filesToPrune = array();
02447     }
02448 
02449     private function deleteFiles( $container ) {
02450         $base = self::baseStorePath();
02451         $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
02452         if ( $iter ) {
02453             foreach ( $iter as $file ) {
02454                 $this->backend->quickDelete( array( 'src' => "$base/$container/$file" ) );
02455             }
02456             // free the directory, to avoid Permission denied under windows on rmdir
02457             unset( $iter );
02458         }
02459         $this->backend->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
02460     }
02461 
02462     function assertBackendPathsConsistent( array $paths ) {
02463         if ( $this->backend instanceof FileBackendMultiWrite ) {
02464             $status = $this->backend->consistencyCheck( $paths );
02465             $this->assertGoodStatus( $status, "Files synced: " . implode( ',', $paths ) );
02466         }
02467     }
02468 
02469     function assertGoodStatus( $status, $msg ) {
02470         $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors, 1 ), $msg );
02471     }
02472 }