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