MediaWiki  master
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                 return $cases;
00391         }
00392 
00396         public function testMove( $op ) {
00397                 $this->backend = $this->singleBackend;
00398                 $this->tearDownFiles();
00399                 $this->doTestMove( $op );
00400                 $this->tearDownFiles();
00401 
00402                 $this->backend = $this->multiBackend;
00403                 $this->tearDownFiles();
00404                 $this->doTestMove( $op );
00405                 $this->tearDownFiles();
00406         }
00407 
00408         private function doTestMove( $op ) {
00409                 $backendName = $this->backendClass();
00410 
00411                 $source = $op['src'];
00412                 $dest = $op['dst'];
00413                 $this->prepare( array( 'dir' => dirname( $source ) ) );
00414                 $this->prepare( array( 'dir' => dirname( $dest ) ) );
00415 
00416                 if ( isset( $op['ignoreMissingSource'] ) ) {
00417                         $status = $this->backend->doOperation( $op );
00418                         $this->assertGoodStatus( $status,
00419                                 "Move from $source to $dest succeeded without warnings ($backendName)." );
00420                         $this->assertEquals( array( 0 => true ), $status->success,
00421                                 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
00422                         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00423                                 "Source file $source does not exist ($backendName)." );
00424                         $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $dest ) ),
00425                                 "Destination file $dest does not exist ($backendName)." );
00426                         return; // done
00427                 }
00428 
00429                 $status = $this->backend->doOperation(
00430                         array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
00431                 $this->assertGoodStatus( $status,
00432                         "Creation of file at $source succeeded ($backendName)." );
00433 
00434                 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
00435                         $this->backend->copy( $op );
00436                 }
00437 
00438                 $status = $this->backend->doOperation( $op );
00439                 $this->assertGoodStatus( $status,
00440                         "Move from $source to $dest succeeded without warnings ($backendName)." );
00441                 $this->assertEquals( true, $status->isOK(),
00442                         "Move from $source to $dest succeeded ($backendName)." );
00443                 $this->assertEquals( array( 0 => true ), $status->success,
00444                         "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
00445                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00446                         "Source file $source does not still exists ($backendName)." );
00447                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00448                         "Destination file $dest exists after move ($backendName)." );
00449 
00450                 $this->assertNotEquals(
00451                         $this->backend->getFileSize( array( 'src' => $source ) ),
00452                         $this->backend->getFileSize( array( 'src' => $dest ) ),
00453                         "Destination file $dest has correct size ($backendName)." );
00454 
00455                 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
00456                 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
00457                 $this->assertEquals( false, $props1['fileExists'],
00458                         "Source file does not exist accourding to props ($backendName)." );
00459                 $this->assertEquals( true, $props2['fileExists'],
00460                         "Destination file exists accourding to props ($backendName)." );
00461 
00462                 $this->assertBackendPathsConsistent( array( $source, $dest ) );
00463         }
00464 
00465         public static function provider_testMove() {
00466                 $cases = array();
00467 
00468                 $source = self::baseStorePath() . '/unittest-cont1/e/file.txt';
00469                 $dest = self::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
00470 
00471                 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
00472                 $cases[] = array(
00473                         $op, // operation
00474                         $source, // source
00475                         $dest, // dest
00476                 );
00477 
00478                 $op2 = $op;
00479                 $op2['overwrite'] = true;
00480                 $cases[] = array(
00481                         $op2, // operation
00482                         $source, // source
00483                         $dest, // dest
00484                 );
00485 
00486                 $op2 = $op;
00487                 $op2['overwriteSame'] = true;
00488                 $cases[] = array(
00489                         $op2, // operation
00490                         $source, // source
00491                         $dest, // dest
00492                 );
00493 
00494                 $op2 = $op;
00495                 $op2['ignoreMissingSource'] = true;
00496                 $cases[] = array(
00497                         $op2, // operation
00498                         $source, // source
00499                         $dest, // dest
00500                 );
00501 
00502                 return $cases;
00503         }
00504 
00508         public function testDelete( $op, $withSource, $okStatus ) {
00509                 $this->backend = $this->singleBackend;
00510                 $this->tearDownFiles();
00511                 $this->doTestDelete( $op, $withSource, $okStatus );
00512                 $this->tearDownFiles();
00513 
00514                 $this->backend = $this->multiBackend;
00515                 $this->tearDownFiles();
00516                 $this->doTestDelete( $op, $withSource, $okStatus );
00517                 $this->tearDownFiles();
00518         }
00519 
00520         private function doTestDelete( $op, $withSource, $okStatus ) {
00521                 $backendName = $this->backendClass();
00522 
00523                 $source = $op['src'];
00524                 $this->prepare( array( 'dir' => dirname( $source ) ) );
00525 
00526                 if ( $withSource ) {
00527                         $status = $this->backend->doOperation(
00528                                 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
00529                         $this->assertGoodStatus( $status,
00530                                 "Creation of file at $source succeeded ($backendName)." );
00531                 }
00532 
00533                 $status = $this->backend->doOperation( $op );
00534                 if ( $okStatus ) {
00535                         $this->assertGoodStatus( $status,
00536                                 "Deletion of file at $source succeeded without warnings ($backendName)." );
00537                         $this->assertEquals( true, $status->isOK(),
00538                                 "Deletion of file at $source succeeded ($backendName)." );
00539                         $this->assertEquals( array( 0 => true ), $status->success,
00540                                 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
00541                 } else {
00542                         $this->assertEquals( false, $status->isOK(),
00543                                 "Deletion of file at $source failed ($backendName)." );
00544                 }
00545 
00546                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
00547                         "Source file $source does not exist after move ($backendName)." );
00548 
00549                 $this->assertFalse(
00550                         $this->backend->getFileSize( array( 'src' => $source ) ),
00551                         "Source file $source has correct size (false) ($backendName)." );
00552 
00553                 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
00554                 $this->assertFalse( $props1['fileExists'],
00555                         "Source file $source does not exist according to props ($backendName)." );
00556 
00557                 $this->assertBackendPathsConsistent( array( $source ) );
00558         }
00559 
00560         public static function provider_testDelete() {
00561                 $cases = array();
00562 
00563                 $source = self::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
00564 
00565                 $op = array( 'op' => 'delete', 'src' => $source );
00566                 $cases[] = array(
00567                         $op, // operation
00568                         true, // with source
00569                         true // succeeds
00570                 );
00571 
00572                 $cases[] = array(
00573                         $op, // operation
00574                         false, // without source
00575                         false // fails
00576                 );
00577 
00578                 $op['ignoreMissingSource'] = true;
00579                 $cases[] = array(
00580                         $op, // operation
00581                         false, // without source
00582                         true // succeeds
00583                 );
00584 
00585                 return $cases;
00586         }
00587 
00591         public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
00592                 $this->backend = $this->singleBackend;
00593                 $this->tearDownFiles();
00594                 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
00595                 $this->tearDownFiles();
00596 
00597                 $this->backend = $this->multiBackend;
00598                 $this->tearDownFiles();
00599                 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
00600                 $this->tearDownFiles();
00601         }
00602 
00603         private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
00604                 $backendName = $this->backendClass();
00605 
00606                 $dest = $op['dst'];
00607                 $this->prepare( array( 'dir' => dirname( $dest ) ) );
00608 
00609                 $oldText = 'blah...blah...waahwaah';
00610                 if ( $alreadyExists ) {
00611                         $status = $this->backend->doOperation(
00612                                 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
00613                         $this->assertGoodStatus( $status,
00614                                 "Creation of file at $dest succeeded ($backendName)." );
00615                 }
00616 
00617                 $status = $this->backend->doOperation( $op );
00618                 if ( $okStatus ) {
00619                         $this->assertGoodStatus( $status,
00620                                 "Creation of file at $dest succeeded without warnings ($backendName)." );
00621                         $this->assertEquals( true, $status->isOK(),
00622                                 "Creation of file at $dest succeeded ($backendName)." );
00623                         $this->assertEquals( array( 0 => true ), $status->success,
00624                                 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
00625                 } else {
00626                         $this->assertEquals( false, $status->isOK(),
00627                                 "Creation of file at $dest failed ($backendName)." );
00628                 }
00629 
00630                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
00631                         "Destination file $dest exists after creation ($backendName)." );
00632 
00633                 $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
00634                 $this->assertEquals( true, $props1['fileExists'],
00635                         "Destination file $dest exists according to props ($backendName)." );
00636                 if ( $okStatus ) { // file content is what we saved
00637                         $this->assertEquals( $newSize, $props1['size'],
00638                                 "Destination file $dest has expected size according to props ($backendName)." );
00639                         $this->assertEquals( $newSize,
00640                                 $this->backend->getFileSize( array( 'src' => $dest ) ),
00641                                 "Destination file $dest has correct size ($backendName)." );
00642                 } else { // file content is some other previous text
00643                         $this->assertEquals( strlen( $oldText ), $props1['size'],
00644                                 "Destination file $dest has original size according to props ($backendName)." );
00645                         $this->assertEquals( strlen( $oldText ),
00646                                 $this->backend->getFileSize( array( 'src' => $dest ) ),
00647                                 "Destination file $dest has original size according to props ($backendName)." );
00648                 }
00649 
00650                 $this->assertBackendPathsConsistent( array( $dest ) );
00651         }
00652 
00656         public static function provider_testCreate() {
00657                 $cases = array();
00658 
00659                 $dest = self::baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
00660 
00661                 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
00662                 $cases[] = array(
00663                         $op, // operation
00664                         false, // no dest already exists
00665                         true, // succeeds
00666                         strlen( $op['content'] )
00667                 );
00668 
00669                 $op2 = $op;
00670                 $op2['content'] = "\n";
00671                 $cases[] = array(
00672                         $op2, // operation
00673                         false, // no dest already exists
00674                         true, // succeeds
00675                         strlen( $op2['content'] )
00676                 );
00677 
00678                 $op2 = $op;
00679                 $op2['content'] = "fsf\n waf 3kt";
00680                 $cases[] = array(
00681                         $op2, // operation
00682                         true, // dest already exists
00683                         false, // fails
00684                         strlen( $op2['content'] )
00685                 );
00686 
00687                 $op2 = $op;
00688                 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
00689                 $op2['overwrite'] = true;
00690                 $cases[] = array(
00691                         $op2, // operation
00692                         true, // dest already exists
00693                         true, // succeeds
00694                         strlen( $op2['content'] )
00695                 );
00696 
00697                 $op2 = $op;
00698                 $op2['content'] = "39qjmg3-qg";
00699                 $op2['overwriteSame'] = true;
00700                 $cases[] = array(
00701                         $op2, // operation
00702                         true, // dest already exists
00703                         false, // succeeds
00704                         strlen( $op2['content'] )
00705                 );
00706 
00707                 return $cases;
00708         }
00709 
00710         public function testDoQuickOperations() {
00711                 $this->backend = $this->singleBackend;
00712                 $this->doTestDoQuickOperations();
00713                 $this->tearDownFiles();
00714 
00715                 $this->backend = $this->multiBackend;
00716                 $this->doTestDoQuickOperations();
00717                 $this->tearDownFiles();
00718         }
00719 
00720         private function doTestDoQuickOperations() {
00721                 $backendName = $this->backendClass();
00722 
00723                 $base = self::baseStorePath();
00724                 $files = array(
00725                         "$base/unittest-cont1/e/fileA.a",
00726                         "$base/unittest-cont1/e/fileB.a",
00727                         "$base/unittest-cont1/e/fileC.a"
00728                 );
00729                 $ops = array();
00730                 $purgeOps = array();
00731                 foreach ( $files as $path ) {
00732                         $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
00733                         $this->assertGoodStatus( $status,
00734                                 "Preparing $path succeeded without warnings ($backendName)." );
00735                         $ops[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand(0,50000) );
00736                         $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
00737                 }
00738                 $purgeOps[] = array( 'op' => 'null' );
00739                 $status = $this->backend->doQuickOperations( $ops );
00740                 $this->assertGoodStatus( $status,
00741                         "Creation of source files succeeded ($backendName)." );
00742 
00743                 foreach ( $files as $file ) {
00744                         $this->assertTrue( $this->backend->fileExists( array( 'src' => $file ) ),
00745                                 "File $file exists." );
00746                 }
00747 
00748                 $status = $this->backend->doQuickOperations( $purgeOps );
00749                 $this->assertGoodStatus( $status,
00750                         "Quick deletion of source files succeeded ($backendName)." );
00751 
00752                 foreach ( $files as $file ) {
00753                         $this->assertFalse( $this->backend->fileExists( array( 'src' => $file ) ),
00754                                 "File $file purged." );
00755                 }
00756         }
00757 
00761         public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
00762                 $this->filesToPrune[] = $op['dst'];
00763 
00764                 $this->backend = $this->singleBackend;
00765                 $this->tearDownFiles();
00766                 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
00767                 $this->tearDownFiles();
00768 
00769                 $this->backend = $this->multiBackend;
00770                 $this->tearDownFiles();
00771                 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
00772                 $this->filesToPrune[] = $op['dst']; # avoid file leaking
00773                 $this->tearDownFiles();
00774         }
00775 
00776         private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
00777                 $backendName = $this->backendClass();
00778 
00779                 $expContent = '';
00780                 // Create sources
00781                 $ops = array();
00782                 foreach ( $srcs as $i => $source ) {
00783                         $this->prepare( array( 'dir' => dirname( $source ) ) );
00784                         $ops[] = array(
00785                                 'op'      => 'create', // operation
00786                                 'dst'     => $source, // source
00787                                 'content' => $srcsContent[$i]
00788                         );
00789                         $expContent .= $srcsContent[$i];
00790                 }
00791                 $status = $this->backend->doOperations( $ops );
00792 
00793                 $this->assertGoodStatus( $status,
00794                         "Creation of source files succeeded ($backendName)." );
00795 
00796                 $dest = $params['dst'];
00797                 if ( $alreadyExists ) {
00798                         $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
00799                         $this->assertEquals( true, $ok,
00800                                 "Creation of file at $dest succeeded ($backendName)." );
00801                 } else {
00802                         $ok = file_put_contents( $dest, '' ) !== false;
00803                         $this->assertEquals( true, $ok,
00804                                 "Creation of 0-byte file at $dest succeeded ($backendName)." );
00805                 }
00806 
00807                 // Combine the files into one
00808                 $status = $this->backend->concatenate( $params );
00809                 if ( $okStatus ) {
00810                         $this->assertGoodStatus( $status,
00811                                 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
00812                         $this->assertEquals( true, $status->isOK(),
00813                                 "Creation of concat file at $dest succeeded ($backendName)." );
00814                 } else {
00815                         $this->assertEquals( false, $status->isOK(),
00816                                 "Creation of concat file at $dest failed ($backendName)." );
00817                 }
00818 
00819                 if ( $okStatus ) {
00820                         $this->assertEquals( true, is_file( $dest ),
00821                                 "Dest concat file $dest exists after creation ($backendName)." );
00822                 } else {
00823                         $this->assertEquals( true, is_file( $dest ),
00824                                 "Dest concat file $dest exists after failed creation ($backendName)." );
00825                 }
00826 
00827                 $contents = file_get_contents( $dest );
00828                 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
00829 
00830                 if ( $okStatus ) {
00831                         $this->assertEquals( $expContent, $contents,
00832                                 "Concat file at $dest has correct contents ($backendName)." );
00833                 } else {
00834                         $this->assertNotEquals( $expContent, $contents,
00835                                 "Concat file at $dest has correct contents ($backendName)." );
00836                 }
00837         }
00838 
00839         function provider_testConcatenate() {
00840                 $cases = array();
00841 
00842                 $rand = mt_rand( 0, 2000000000 ) . time();
00843                 $dest = wfTempDir() . "/randomfile!$rand.txt";
00844                 $srcs = array(
00845                         self::baseStorePath() . '/unittest-cont1/e/file1.txt',
00846                         self::baseStorePath() . '/unittest-cont1/e/file2.txt',
00847                         self::baseStorePath() . '/unittest-cont1/e/file3.txt',
00848                         self::baseStorePath() . '/unittest-cont1/e/file4.txt',
00849                         self::baseStorePath() . '/unittest-cont1/e/file5.txt',
00850                         self::baseStorePath() . '/unittest-cont1/e/file6.txt',
00851                         self::baseStorePath() . '/unittest-cont1/e/file7.txt',
00852                         self::baseStorePath() . '/unittest-cont1/e/file8.txt',
00853                         self::baseStorePath() . '/unittest-cont1/e/file9.txt',
00854                         self::baseStorePath() . '/unittest-cont1/e/file10.txt'
00855                 );
00856                 $content = array(
00857                         'egfage',
00858                         'ageageag',
00859                         'rhokohlr',
00860                         'shgmslkg',
00861                         'kenga',
00862                         'owagmal',
00863                         'kgmae',
00864                         'g eak;g',
00865                         'lkaem;a',
00866                         'legma'
00867                 );
00868                 $params = array( 'srcs' => $srcs, 'dst' => $dest );
00869 
00870                 $cases[] = array(
00871                         $params, // operation
00872                         $srcs, // sources
00873                         $content, // content for each source
00874                         false, // no dest already exists
00875                         true, // succeeds
00876                 );
00877 
00878                 $cases[] = array(
00879                         $params, // operation
00880                         $srcs, // sources
00881                         $content, // content for each source
00882                         true, // dest already exists
00883                         false, // succeeds
00884                 );
00885 
00886                 return $cases;
00887         }
00888 
00892         public function testGetFileStat( $path, $content, $alreadyExists ) {
00893                 $this->backend = $this->singleBackend;
00894                 $this->tearDownFiles();
00895                 $this->doTestGetFileStat( $path, $content, $alreadyExists );
00896                 $this->tearDownFiles();
00897 
00898                 $this->backend = $this->multiBackend;
00899                 $this->tearDownFiles();
00900                 $this->doTestGetFileStat( $path, $content, $alreadyExists );
00901                 $this->tearDownFiles();
00902         }
00903 
00904         private function doTestGetFileStat( $path, $content, $alreadyExists ) {
00905                 $backendName = $this->backendClass();
00906 
00907                 if ( $alreadyExists ) {
00908                         $this->prepare( array( 'dir' => dirname( $path ) ) );
00909                         $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
00910                         $this->assertGoodStatus( $status,
00911                                 "Creation of file at $path succeeded ($backendName)." );
00912 
00913                         $size = $this->backend->getFileSize( array( 'src' => $path ) );
00914                         $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
00915                         $stat = $this->backend->getFileStat( array( 'src' => $path ) );
00916 
00917                         $this->assertEquals( strlen( $content ), $size,
00918                                 "Correct file size of '$path'" );
00919                         $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
00920                                 "Correct file timestamp of '$path'" );
00921 
00922                         $size = $stat['size'];
00923                         $time = $stat['mtime'];
00924                         $this->assertEquals( strlen( $content ), $size,
00925                                 "Correct file size of '$path'" );
00926                         $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
00927                                 "Correct file timestamp of '$path'" );
00928 
00929                         $this->backend->clearCache( array( $path ) );
00930 
00931                         $size = $this->backend->getFileSize( array( 'src' => $path ) );
00932 
00933                         $this->assertEquals( strlen( $content ), $size,
00934                                 "Correct file size of '$path'" );
00935 
00936                         $this->backend->preloadCache( array( $path ) );
00937 
00938                         $size = $this->backend->getFileSize( array( 'src' => $path ) );
00939 
00940                         $this->assertEquals( strlen( $content ), $size,
00941                                 "Correct file size of '$path'" );
00942                 } else {
00943                         $size = $this->backend->getFileSize( array( 'src' => $path ) );
00944                         $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
00945                         $stat = $this->backend->getFileStat( array( 'src' => $path ) );
00946 
00947                         $this->assertFalse( $size, "Correct file size of '$path'" );
00948                         $this->assertFalse( $time, "Correct file timestamp of '$path'" );
00949                         $this->assertFalse( $stat, "Correct file stat of '$path'" );
00950                 }
00951         }
00952 
00953         function provider_testGetFileStat() {
00954                 $cases = array();
00955 
00956                 $base = self::baseStorePath();
00957                 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
00958                 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
00959                 $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
00960 
00961                 return $cases;
00962         }
00963 
00967         public function testGetFileContents( $source, $content ) {
00968                 $this->backend = $this->singleBackend;
00969                 $this->tearDownFiles();
00970                 $this->doTestGetFileContents( $source, $content );
00971                 $this->tearDownFiles();
00972 
00973                 $this->backend = $this->multiBackend;
00974                 $this->tearDownFiles();
00975                 $this->doTestGetFileContents( $source, $content );
00976                 $this->tearDownFiles();
00977         }
00978 
00979         private function doTestGetFileContents( $source, $content ) {
00980                 $backendName = $this->backendClass();
00981 
00982                 $srcs = (array)$source;
00983                 $content = (array)$content;
00984                 foreach ( $srcs as $i => $src ) {
00985                         $this->prepare( array( 'dir' => dirname( $src ) ) );
00986                         $status = $this->backend->doOperation(
00987                                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
00988                         $this->assertGoodStatus( $status,
00989                                 "Creation of file at $src succeeded ($backendName)." );
00990                 }
00991 
00992                 if ( is_array( $source ) ) {
00993                         $contents = $this->backend->getFileContentsMulti( array( 'srcs' => $source ) );
00994                         foreach ( $contents as $path => $data ) {
00995                                 $this->assertNotEquals( false, $data, "Contents of $path exists ($backendName)." );
00996                                 $this->assertEquals( current( $content ), $data, "Contents of $path is correct ($backendName)." );
00997                                 next( $content );
00998                         }
00999                         $this->assertEquals( $source, array_keys( $contents ), "Contents in right order ($backendName)." );
01000                         $this->assertEquals( count( $source ), count( $contents ), "Contents array size correct ($backendName)." );
01001                 } else {
01002                         $data = $this->backend->getFileContents( array( 'src' => $source ) );
01003                         $this->assertNotEquals( false, $data, "Contents of $source exists ($backendName)." );
01004                         $this->assertEquals( $content[0], $data, "Contents of $source is correct ($backendName)." );
01005                 }
01006         }
01007 
01008         function provider_testGetFileContents() {
01009                 $cases = array();
01010 
01011                 $base = self::baseStorePath();
01012                 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
01013                 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
01014                 $cases[] = array(
01015                         array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01016                                  "$base/unittest-cont1/e/a/z.txt" ),
01017                         array( "contents xx", "contents xy", "contents xz" )
01018                 );
01019 
01020                 return $cases;
01021         }
01022 
01026         public function testGetLocalCopy( $source, $content ) {
01027                 $this->backend = $this->singleBackend;
01028                 $this->tearDownFiles();
01029                 $this->doTestGetLocalCopy( $source, $content );
01030                 $this->tearDownFiles();
01031 
01032                 $this->backend = $this->multiBackend;
01033                 $this->tearDownFiles();
01034                 $this->doTestGetLocalCopy( $source, $content );
01035                 $this->tearDownFiles();
01036         }
01037 
01038         private function doTestGetLocalCopy( $source, $content ) {
01039                 $backendName = $this->backendClass();
01040 
01041                 $srcs = (array)$source;
01042                 $content = (array)$content;
01043                 foreach ( $srcs as $i => $src ) {
01044                         $this->prepare( array( 'dir' => dirname( $src ) ) );
01045                         $status = $this->backend->doOperation(
01046                                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
01047                         $this->assertGoodStatus( $status,
01048                                 "Creation of file at $src succeeded ($backendName)." );
01049                 }
01050 
01051                 if ( is_array( $source ) ) {
01052                         $tmpFiles = $this->backend->getLocalCopyMulti( array( 'srcs' => $source ) );
01053                         foreach ( $tmpFiles as $path => $tmpFile ) {
01054                                 $this->assertNotNull( $tmpFile,
01055                                         "Creation of local copy of $path succeeded ($backendName)." );
01056                                 $contents = file_get_contents( $tmpFile->getPath() );
01057                                 $this->assertNotEquals( false, $contents, "Local copy of $path exists ($backendName)." );
01058                                 $this->assertEquals( current( $content ), $contents, "Local copy of $path is correct ($backendName)." );
01059                                 next( $content );
01060                         }
01061                         $this->assertEquals( $source, array_keys( $tmpFiles ), "Local copies in right order ($backendName)." );
01062                         $this->assertEquals( count( $source ), count( $tmpFiles ), "Local copies array size correct ($backendName)." );
01063                 } else {
01064                         $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
01065                         $this->assertNotNull( $tmpFile,
01066                                 "Creation of local copy of $source succeeded ($backendName)." );
01067                         $contents = file_get_contents( $tmpFile->getPath() );
01068                         $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
01069                         $this->assertEquals( $content[0], $contents, "Local copy of $source is correct ($backendName)." );
01070                 }
01071 
01072                 $obj = new stdClass();
01073                 $tmpFile->bind( $obj );
01074         }
01075 
01076         function provider_testGetLocalCopy() {
01077                 $cases = array();
01078 
01079                 $base = self::baseStorePath();
01080                 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01081                 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01082                 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01083                 $cases[] = array(
01084                         array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01085                                  "$base/unittest-cont1/e/a/z.txt" ),
01086                         array( "contents xx", "contents xy", "contents xz" )
01087                 );
01088 
01089                 return $cases;
01090         }
01091 
01095         public function testGetLocalReference( $source, $content ) {
01096                 $this->backend = $this->singleBackend;
01097                 $this->tearDownFiles();
01098                 $this->doTestGetLocalReference( $source, $content );
01099                 $this->tearDownFiles();
01100 
01101                 $this->backend = $this->multiBackend;
01102                 $this->tearDownFiles();
01103                 $this->doTestGetLocalReference( $source, $content );
01104                 $this->tearDownFiles();
01105         }
01106 
01107         private function doTestGetLocalReference( $source, $content ) {
01108                 $backendName = $this->backendClass();
01109 
01110                 $srcs = (array)$source;
01111                 $content = (array)$content;
01112                 foreach ( $srcs as $i => $src ) {
01113                         $this->prepare( array( 'dir' => dirname( $src ) ) );
01114                         $status = $this->backend->doOperation(
01115                                 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
01116                         $this->assertGoodStatus( $status,
01117                                 "Creation of file at $src succeeded ($backendName)." );
01118                 }
01119 
01120                 if ( is_array( $source ) ) {
01121                         $tmpFiles = $this->backend->getLocalReferenceMulti( array( 'srcs' => $source ) );
01122                         foreach ( $tmpFiles as $path => $tmpFile ) {
01123                                 $this->assertNotNull( $tmpFile,
01124                                         "Creation of local copy of $path succeeded ($backendName)." );
01125                                 $contents = file_get_contents( $tmpFile->getPath() );
01126                                 $this->assertNotEquals( false, $contents, "Local ref of $path exists ($backendName)." );
01127                                 $this->assertEquals( current( $content ), $contents, "Local ref of $path is correct ($backendName)." );
01128                                 next( $content );
01129                         }
01130                         $this->assertEquals( $source, array_keys( $tmpFiles ), "Local refs in right order ($backendName)." );
01131                         $this->assertEquals( count( $source ), count( $tmpFiles ), "Local refs array size correct ($backendName)." );
01132                 } else {
01133                         $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
01134                         $this->assertNotNull( $tmpFile,
01135                                 "Creation of local copy of $source succeeded ($backendName)." );
01136                         $contents = file_get_contents( $tmpFile->getPath() );
01137                         $this->assertNotEquals( false, $contents, "Local ref of $source exists ($backendName)." );
01138                         $this->assertEquals( $content[0], $contents, "Local ref of $source is correct ($backendName)." );
01139                 }
01140         }
01141 
01142         function provider_testGetLocalReference() {
01143                 $cases = array();
01144 
01145                 $base = self::baseStorePath();
01146                 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01147                 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01148                 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01149                 $cases[] = array(
01150                         array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
01151                                  "$base/unittest-cont1/e/a/z.txt" ),
01152                         array( "contents xx", "contents xy", "contents xz" )
01153                 );
01154 
01155                 return $cases;
01156         }
01157 
01158         public function testGetLocalCopyAndReference404() {
01159                 $this->backend = $this->singleBackend;
01160                 $this->tearDownFiles();
01161                 $this->doTestGetLocalCopyAndReference404();
01162                 $this->tearDownFiles();
01163 
01164                 $this->backend = $this->multiBackend;
01165                 $this->tearDownFiles();
01166                 $this->doTestGetLocalCopyAndReference404();
01167                 $this->tearDownFiles();
01168         }
01169 
01170         public function doTestGetLocalCopyAndReference404() {
01171                 $backendName = $this->backendClass();
01172 
01173                 $base = self::baseStorePath();
01174 
01175                 $tmpFile = $this->backend->getLocalCopy( array(
01176                         'src' => "$base/unittest-cont1/not-there" ) );
01177                 $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
01178 
01179                 $tmpFile = $this->backend->getLocalReference( array(
01180                         'src' => "$base/unittest-cont1/not-there" ) );
01181                 $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
01182         }
01183 
01187         public function testGetFileHttpUrl( $source, $content ) {
01188                 $this->backend = $this->singleBackend;
01189                 $this->tearDownFiles();
01190                 $this->doTestGetFileHttpUrl( $source, $content );
01191                 $this->tearDownFiles();
01192 
01193                 $this->backend = $this->multiBackend;
01194                 $this->tearDownFiles();
01195                 $this->doTestGetFileHttpUrl( $source, $content );
01196                 $this->tearDownFiles();
01197         }
01198 
01199         private function doTestGetFileHttpUrl( $source, $content ) {
01200                 $backendName = $this->backendClass();
01201 
01202                 $this->prepare( array( 'dir' => dirname( $source ) ) );
01203                 $status = $this->backend->doOperation(
01204                         array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
01205                 $this->assertGoodStatus( $status,
01206                         "Creation of file at $source succeeded ($backendName)." );
01207 
01208                 $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) );
01209 
01210                 if ( $url !== null ) { // supported
01211                         $data = Http::request( "GET", $url );
01212                         $this->assertEquals( $content, $data,
01213                                 "HTTP GET of URL has right contents ($backendName)." );
01214                 }
01215         }
01216 
01217         function provider_testGetFileHttpUrl() {
01218                 $cases = array();
01219 
01220                 $base = self::baseStorePath();
01221                 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
01222                 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
01223                 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
01224 
01225                 return $cases;
01226         }
01227 
01231         public function testPrepareAndClean( $path, $isOK ) {
01232                 $this->backend = $this->singleBackend;
01233                 $this->doTestPrepareAndClean( $path, $isOK );
01234                 $this->tearDownFiles();
01235 
01236                 $this->backend = $this->multiBackend;
01237                 $this->doTestPrepareAndClean( $path, $isOK );
01238                 $this->tearDownFiles();
01239         }
01240 
01241         function provider_testPrepareAndClean() {
01242                 $base = self::baseStorePath();
01243                 return array(
01244                         array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
01245                         array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
01246                         # Specific to FS backend with no basePath field set
01247                         #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
01248                 );
01249         }
01250 
01251         private function doTestPrepareAndClean( $path, $isOK ) {
01252                 $backendName = $this->backendClass();
01253 
01254                 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
01255                 if ( $isOK ) {
01256                         $this->assertGoodStatus( $status,
01257                                 "Preparing dir $path succeeded without warnings ($backendName)." );
01258                         $this->assertEquals( true, $status->isOK(),
01259                                 "Preparing dir $path succeeded ($backendName)." );
01260                 } else {
01261                         $this->assertEquals( false, $status->isOK(),
01262                                 "Preparing dir $path failed ($backendName)." );
01263                 }
01264 
01265                 $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
01266                 if ( $isOK ) {
01267                         $this->assertGoodStatus( $status,
01268                                 "Cleaning dir $path succeeded without warnings ($backendName)." );
01269                         $this->assertEquals( true, $status->isOK(),
01270                                 "Cleaning dir $path succeeded ($backendName)." );
01271                 } else {
01272                         $this->assertEquals( false, $status->isOK(),
01273                                 "Cleaning dir $path failed ($backendName)." );
01274                 }
01275         }
01276 
01277         public function testRecursiveClean() {
01278                 $this->backend = $this->singleBackend;
01279                 $this->doTestRecursiveClean();
01280                 $this->tearDownFiles();
01281 
01282                 $this->backend = $this->multiBackend;
01283                 $this->doTestRecursiveClean();
01284                 $this->tearDownFiles();
01285         }
01286 
01287         private function doTestRecursiveClean() {
01288                 $backendName = $this->backendClass();
01289 
01290                 $base = self::baseStorePath();
01291                 $dirs = array(
01292                         "$base/unittest-cont1/e/a",
01293                         "$base/unittest-cont1/e/a/b",
01294                         "$base/unittest-cont1/e/a/b/c",
01295                         "$base/unittest-cont1/e/a/b/c/d0",
01296                         "$base/unittest-cont1/e/a/b/c/d1",
01297                         "$base/unittest-cont1/e/a/b/c/d2",
01298                         "$base/unittest-cont1/e/a/b/c/d0/1",
01299                         "$base/unittest-cont1/e/a/b/c/d0/2",
01300                         "$base/unittest-cont1/e/a/b/c/d1/3",
01301                         "$base/unittest-cont1/e/a/b/c/d1/4",
01302                         "$base/unittest-cont1/e/a/b/c/d2/5",
01303                         "$base/unittest-cont1/e/a/b/c/d2/6"
01304                 );
01305                 foreach ( $dirs as $dir ) {
01306                         $status = $this->prepare( array( 'dir' => $dir ) );
01307                         $this->assertGoodStatus( $status,
01308                                 "Preparing dir $dir succeeded without warnings ($backendName)." );
01309                 }
01310 
01311                 if ( $this->backend instanceof FSFileBackend ) {
01312                         foreach ( $dirs as $dir ) {
01313                                 $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ),
01314                                         "Dir $dir exists ($backendName)." );
01315                         }
01316                 }
01317 
01318                 $status = $this->backend->clean(
01319                         array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
01320                 $this->assertGoodStatus( $status,
01321                         "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
01322 
01323                 foreach ( $dirs as $dir ) {
01324                         $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ),
01325                                 "Dir $dir no longer exists ($backendName)." );
01326                 }
01327         }
01328 
01329         // @TODO: testSecure
01330 
01331         public function testDoOperations() {
01332                 $this->backend = $this->singleBackend;
01333                 $this->tearDownFiles();
01334                 $this->doTestDoOperations();
01335                 $this->tearDownFiles();
01336 
01337                 $this->backend = $this->multiBackend;
01338                 $this->tearDownFiles();
01339                 $this->doTestDoOperations();
01340                 $this->tearDownFiles();
01341         }
01342 
01343         private function doTestDoOperations() {
01344                 $base = self::baseStorePath();
01345 
01346                 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
01347                 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01348                 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
01349                 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01350                 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
01351                 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01352                 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
01353 
01354                 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01355                 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01356                 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01357                 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
01358                 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01359                 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
01360                 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
01361 
01362                 $status = $this->backend->doOperations( array(
01363                         array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01364                         // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01365                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01366                         // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01367                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
01368                         // Now: A:<A>, B:<B>, C:<empty>, D:<A>
01369                         array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
01370                         // Now: A:<A>, B:<empty>, C:<B>, D:<A>
01371                         array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
01372                         // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
01373                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
01374                         // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
01375                         array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
01376                         // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
01377                         array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
01378                         // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
01379                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01380                         // Does nothing
01381                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01382                         // Does nothing
01383                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01384                         // Does nothing
01385                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01386                         // Does nothing
01387                         array( 'op' => 'null' ),
01388                         // Does nothing
01389                 ) );
01390 
01391                 $this->assertGoodStatus( $status, "Operation batch succeeded" );
01392                 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01393                 $this->assertEquals( 13, count( $status->success ),
01394                         "Operation batch has correct success array" );
01395 
01396                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
01397                         "File does not exist at $fileA" );
01398                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01399                         "File does not exist at $fileB" );
01400                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01401                         "File does not exist at $fileD" );
01402 
01403                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01404                         "File exists at $fileC" );
01405                 $this->assertEquals( $fileBContents,
01406                         $this->backend->getFileContents( array( 'src' => $fileC ) ),
01407                         "Correct file contents of $fileC" );
01408                 $this->assertEquals( strlen( $fileBContents ),
01409                         $this->backend->getFileSize( array( 'src' => $fileC ) ),
01410                         "Correct file size of $fileC" );
01411                 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01412                         $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
01413                         "Correct file SHA-1 of $fileC" );
01414         }
01415 
01416         public function testDoOperationsPipeline() {
01417                 $this->backend = $this->singleBackend;
01418                 $this->tearDownFiles();
01419                 $this->doTestDoOperationsPipeline();
01420                 $this->tearDownFiles();
01421 
01422                 $this->backend = $this->multiBackend;
01423                 $this->tearDownFiles();
01424                 $this->doTestDoOperationsPipeline();
01425                 $this->tearDownFiles();
01426         }
01427 
01428         // concurrency orientated
01429         private function doTestDoOperationsPipeline() {
01430                 $base = self::baseStorePath();
01431 
01432                 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01433                 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01434                 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01435 
01436                 $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01437                 file_put_contents( $tmpNameA, $fileAContents );
01438                 $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01439                 file_put_contents( $tmpNameB, $fileBContents );
01440                 $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
01441                 file_put_contents( $tmpNameC, $fileCContents );
01442 
01443                 $this->filesToPrune[] = $tmpNameA; # avoid file leaking
01444                 $this->filesToPrune[] = $tmpNameB; # avoid file leaking
01445                 $this->filesToPrune[] = $tmpNameC; # avoid file leaking
01446 
01447                 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
01448                 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
01449                 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
01450                 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
01451 
01452                 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01453                 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01454                 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01455                 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01456                 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
01457 
01458                 $status = $this->backend->doOperations( array(
01459                         array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
01460                         array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
01461                         array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
01462                         array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01463                         // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01464                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01465                         // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01466                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
01467                         // Now: A:<A>, B:<B>, C:<empty>, D:<A>
01468                         array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
01469                         // Now: A:<A>, B:<empty>, C:<B>, D:<A>
01470                         array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
01471                         // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
01472                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
01473                         // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
01474                         array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
01475                         // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
01476                         array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
01477                         // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
01478                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01479                         // Does nothing
01480                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01481                         // Does nothing
01482                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
01483                         // Does nothing
01484                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
01485                         // Does nothing
01486                         array( 'op' => 'null' ),
01487                         // Does nothing
01488                 ) );
01489 
01490                 $this->assertGoodStatus( $status, "Operation batch succeeded" );
01491                 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01492                 $this->assertEquals( 16, count( $status->success ),
01493                         "Operation batch has correct success array" );
01494 
01495                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
01496                         "File does not exist at $fileA" );
01497                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01498                         "File does not exist at $fileB" );
01499                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01500                         "File does not exist at $fileD" );
01501 
01502                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01503                         "File exists at $fileC" );
01504                 $this->assertEquals( $fileBContents,
01505                         $this->backend->getFileContents( array( 'src' => $fileC ) ),
01506                         "Correct file contents of $fileC" );
01507                 $this->assertEquals( strlen( $fileBContents ),
01508                         $this->backend->getFileSize( array( 'src' => $fileC ) ),
01509                         "Correct file size of $fileC" );
01510                 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01511                         $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
01512                         "Correct file SHA-1 of $fileC" );
01513         }
01514 
01515         public function testDoOperationsFailing() {
01516                 $this->backend = $this->singleBackend;
01517                 $this->tearDownFiles();
01518                 $this->doTestDoOperationsFailing();
01519                 $this->tearDownFiles();
01520 
01521                 $this->backend = $this->multiBackend;
01522                 $this->tearDownFiles();
01523                 $this->doTestDoOperationsFailing();
01524                 $this->tearDownFiles();
01525         }
01526 
01527         private function doTestDoOperationsFailing() {
01528                 $base = self::baseStorePath();
01529 
01530                 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
01531                 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
01532                 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
01533                 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
01534                 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
01535                 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
01536                 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
01537 
01538                 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
01539                 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
01540                 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
01541                 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
01542                 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
01543                 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
01544 
01545                 $status = $this->backend->doOperations( array(
01546                         array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
01547                         // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
01548                         array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
01549                         // Now: A:<A>, B:<B>, C:<A>, D:<empty>
01550                         array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
01551                         // Now: A:<A>, B:<B>, C:<A>, D:<B>
01552                         array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
01553                         // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
01554                         array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
01555                         // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
01556                         array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
01557                         // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
01558                         array( 'op' => 'delete', 'src' => $fileD ),
01559                         // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
01560                         array( 'op' => 'null' ),
01561                         // Does nothing
01562                 ), array( 'force' => 1 ) );
01563 
01564                 $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
01565                 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
01566                 $this->assertEquals( 8, count( $status->success ),
01567                         "Operation batch has correct success array" );
01568 
01569                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
01570                         "File does not exist at $fileB" );
01571                 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
01572                         "File does not exist at $fileD" );
01573 
01574                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
01575                         "File does not exist at $fileA" );
01576                 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
01577                         "File exists at $fileC" );
01578                 $this->assertEquals( $fileBContents,
01579                         $this->backend->getFileContents( array( 'src' => $fileA ) ),
01580                         "Correct file contents of $fileA" );
01581                 $this->assertEquals( strlen( $fileBContents ),
01582                         $this->backend->getFileSize( array( 'src' => $fileA ) ),
01583                         "Correct file size of $fileA" );
01584                 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
01585                         $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
01586                         "Correct file SHA-1 of $fileA" );
01587         }
01588 
01589         public function testGetFileList() {
01590                 $this->backend = $this->singleBackend;
01591                 $this->tearDownFiles();
01592                 $this->doTestGetFileList();
01593                 $this->tearDownFiles();
01594 
01595                 $this->backend = $this->multiBackend;
01596                 $this->tearDownFiles();
01597                 $this->doTestGetFileList();
01598                 $this->tearDownFiles();
01599         }
01600 
01601         private function doTestGetFileList() {
01602                 $backendName = $this->backendClass();
01603                 $base = self::baseStorePath();
01604 
01605                 // Should have no errors
01606                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
01607 
01608                 $files = array(
01609                         "$base/unittest-cont1/e/test1.txt",
01610                         "$base/unittest-cont1/e/test2.txt",
01611                         "$base/unittest-cont1/e/test3.txt",
01612                         "$base/unittest-cont1/e/subdir1/test1.txt",
01613                         "$base/unittest-cont1/e/subdir1/test2.txt",
01614                         "$base/unittest-cont1/e/subdir2/test3.txt",
01615                         "$base/unittest-cont1/e/subdir2/test4.txt",
01616                         "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
01617                         "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
01618                         "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
01619                         "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
01620                         "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
01621                         "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
01622                         "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
01623                 );
01624 
01625                 // Add the files
01626                 $ops = array();
01627                 foreach ( $files as $file ) {
01628                         $this->prepare( array( 'dir' => dirname( $file ) ) );
01629                         $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
01630                 }
01631                 $status = $this->backend->doQuickOperations( $ops );
01632                 $this->assertGoodStatus( $status,
01633                         "Creation of files succeeded ($backendName)." );
01634                 $this->assertEquals( true, $status->isOK(),
01635                         "Creation of files succeeded with OK status ($backendName)." );
01636 
01637                 // Expected listing
01638                 $expected = array(
01639                         "e/test1.txt",
01640                         "e/test2.txt",
01641                         "e/test3.txt",
01642                         "e/subdir1/test1.txt",
01643                         "e/subdir1/test2.txt",
01644                         "e/subdir2/test3.txt",
01645                         "e/subdir2/test4.txt",
01646                         "e/subdir2/subdir/test1.txt",
01647                         "e/subdir2/subdir/test2.txt",
01648                         "e/subdir2/subdir/test3.txt",
01649                         "e/subdir2/subdir/test4.txt",
01650                         "e/subdir2/subdir/test5.txt",
01651                         "e/subdir2/subdir/sub/test0.txt",
01652                         "e/subdir2/subdir/sub/120-px-file.txt",
01653                 );
01654                 sort( $expected );
01655 
01656                 // Actual listing (no trailing slash)
01657                 $list = array();
01658                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
01659                 foreach ( $iter as $file ) {
01660                         $list[] = $file;
01661                 }
01662                 sort( $list );
01663 
01664                 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
01665 
01666                 // Actual listing (with trailing slash)
01667                 $list = array();
01668                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
01669                 foreach ( $iter as $file ) {
01670                         $list[] = $file;
01671                 }
01672                 sort( $list );
01673 
01674                 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
01675 
01676                 // Expected listing
01677                 $expected = array(
01678                         "test1.txt",
01679                         "test2.txt",
01680                         "test3.txt",
01681                         "test4.txt",
01682                         "test5.txt",
01683                         "sub/test0.txt",
01684                         "sub/120-px-file.txt",
01685                 );
01686                 sort( $expected );
01687 
01688                 // Actual listing (no trailing slash)
01689                 $list = array();
01690                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
01691                 foreach ( $iter as $file ) {
01692                         $list[] = $file;
01693                 }
01694                 sort( $list );
01695 
01696                 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
01697 
01698                 // Actual listing (with trailing slash)
01699                 $list = array();
01700                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
01701                 foreach ( $iter as $file ) {
01702                         $list[] = $file;
01703                 }
01704                 sort( $list );
01705 
01706                 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
01707 
01708                 // Actual listing (using iterator second time)
01709                 $list = array();
01710                 foreach ( $iter as $file ) {
01711                         $list[] = $file;
01712                 }
01713                 sort( $list );
01714 
01715                 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
01716 
01717                 // Expected listing (top files only)
01718                 $expected = array(
01719                         "test1.txt",
01720                         "test2.txt",
01721                         "test3.txt",
01722                         "test4.txt",
01723                         "test5.txt"
01724                 );
01725                 sort( $expected );
01726 
01727                 // Actual listing (top files only)
01728                 $list = array();
01729                 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
01730                 foreach ( $iter as $file ) {
01731                         $list[] = $file;
01732                 }
01733                 sort( $list );
01734 
01735                 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
01736 
01737                 foreach ( $files as $file ) { // clean up
01738                         $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
01739                 }
01740 
01741                 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
01742                 foreach ( $iter as $iter ) {} // no errors
01743         }
01744 
01745         public function testGetDirectoryList() {
01746                 $this->backend = $this->singleBackend;
01747                 $this->tearDownFiles();
01748                 $this->doTestGetDirectoryList();
01749                 $this->tearDownFiles();
01750 
01751                 $this->backend = $this->multiBackend;
01752                 $this->tearDownFiles();
01753                 $this->doTestGetDirectoryList();
01754                 $this->tearDownFiles();
01755         }
01756 
01757         private function doTestGetDirectoryList() {
01758                 $backendName = $this->backendClass();
01759 
01760                 $base = self::baseStorePath();
01761                 $files = array(
01762                         "$base/unittest-cont1/e/test1.txt",
01763                         "$base/unittest-cont1/e/test2.txt",
01764                         "$base/unittest-cont1/e/test3.txt",
01765                         "$base/unittest-cont1/e/subdir1/test1.txt",
01766                         "$base/unittest-cont1/e/subdir1/test2.txt",
01767                         "$base/unittest-cont1/e/subdir2/test3.txt",
01768                         "$base/unittest-cont1/e/subdir2/test4.txt",
01769                         "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
01770                         "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
01771                         "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
01772                         "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
01773                         "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
01774                         "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
01775                         "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
01776                 );
01777 
01778                 // Add the files
01779                 $ops = array();
01780                 foreach ( $files as $file ) {
01781                         $this->prepare( array( 'dir' => dirname( $file ) ) );
01782                         $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
01783                 }
01784                 $status = $this->backend->doQuickOperations( $ops );
01785                 $this->assertGoodStatus( $status,
01786                         "Creation of files succeeded ($backendName)." );
01787                 $this->assertEquals( true, $status->isOK(),
01788                         "Creation of files succeeded with OK status ($backendName)." );
01789 
01790                 $this->assertEquals( true,
01791                         $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
01792                         "Directory exists in ($backendName)." );
01793                 $this->assertEquals( true,
01794                         $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
01795                         "Directory exists in ($backendName)." );
01796                 $this->assertEquals( false,
01797                         $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
01798                         "Directory does not exists in ($backendName)." );
01799 
01800                 // Expected listing
01801                 $expected = array(
01802                         "e",
01803                 );
01804                 sort( $expected );
01805 
01806                 // Actual listing (no trailing slash)
01807                 $list = array();
01808                 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
01809                 foreach ( $iter as $file ) {
01810                         $list[] = $file;
01811                 }
01812                 sort( $list );
01813 
01814                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
01815 
01816                 // Expected listing
01817                 $expected = array(
01818                         "subdir1",
01819                         "subdir2",
01820                         "subdir3",
01821                         "subdir4",
01822                 );
01823                 sort( $expected );
01824 
01825                 // Actual listing (no trailing slash)
01826                 $list = array();
01827                 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
01828                 foreach ( $iter as $file ) {
01829                         $list[] = $file;
01830                 }
01831                 sort( $list );
01832 
01833                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
01834 
01835                 // Actual listing (with trailing slash)
01836                 $list = array();
01837                 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
01838                 foreach ( $iter as $file ) {
01839                         $list[] = $file;
01840                 }
01841                 sort( $list );
01842 
01843                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
01844 
01845                 // Expected listing
01846                 $expected = array(
01847                         "subdir",
01848                 );
01849                 sort( $expected );
01850 
01851                 // Actual listing (no trailing slash)
01852                 $list = array();
01853                 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
01854                 foreach ( $iter as $file ) {
01855                         $list[] = $file;
01856                 }
01857                 sort( $list );
01858 
01859                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
01860 
01861                 // Actual listing (with trailing slash)
01862                 $list = array();
01863                 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2/" ) );
01864                 foreach ( $iter as $file ) {
01865                         $list[] = $file;
01866                 }
01867                 sort( $list );
01868 
01869                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
01870 
01871                 // Actual listing (using iterator second time)
01872                 $list = array();
01873                 foreach ( $iter as $file ) {
01874                         $list[] = $file;
01875                 }
01876                 sort( $list );
01877 
01878                 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
01879 
01880                 // Expected listing (recursive)
01881                 $expected = array(
01882                         "e",
01883                         "e/subdir1",
01884                         "e/subdir2",
01885                         "e/subdir3",
01886                         "e/subdir4",
01887                         "e/subdir2/subdir",
01888                         "e/subdir3/subdir",
01889                         "e/subdir4/subdir",
01890                         "e/subdir4/subdir/sub",
01891                 );
01892                 sort( $expected );
01893 
01894                 // Actual listing (recursive)
01895                 $list = array();
01896                 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
01897                 foreach ( $iter as $file ) {
01898                         $list[] = $file;
01899                 }
01900                 sort( $list );
01901 
01902                 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
01903 
01904                 // Expected listing (recursive)
01905                 $expected = array(
01906                         "subdir",
01907                         "subdir/sub",
01908                 );
01909                 sort( $expected );
01910 
01911                 // Actual listing (recursive)
01912                 $list = array();
01913                 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
01914                 foreach ( $iter as $file ) {
01915                         $list[] = $file;
01916                 }
01917                 sort( $list );
01918 
01919                 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
01920 
01921                 // Actual listing (recursive, second time)
01922                 $list = array();
01923                 foreach ( $iter as $file ) {
01924                         $list[] = $file;
01925                 }
01926                 sort( $list );
01927 
01928                 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
01929 
01930                 foreach ( $files as $file ) { // clean up
01931                         $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
01932                 }
01933 
01934                 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
01935                 foreach ( $iter as $iter ) {} // no errors
01936         }
01937 
01938         public function testLockCalls() {
01939                 $this->backend = $this->singleBackend;
01940                 $this->doTestLockCalls();
01941         }
01942 
01943         private function doTestLockCalls() {
01944                 $backendName = $this->backendClass();
01945 
01946                 for ( $i=0; $i<50; $i++ ) {
01947                         $paths = array(
01948                                 "test1.txt",
01949                                 "test2.txt",
01950                                 "test3.txt",
01951                                 "subdir1",
01952                                 "subdir1", // duplicate
01953                                 "subdir1/test1.txt",
01954                                 "subdir1/test2.txt",
01955                                 "subdir2",
01956                                 "subdir2", // duplicate
01957                                 "subdir2/test3.txt",
01958                                 "subdir2/test4.txt",
01959                                 "subdir2/subdir",
01960                                 "subdir2/subdir/test1.txt",
01961                                 "subdir2/subdir/test2.txt",
01962                                 "subdir2/subdir/test3.txt",
01963                                 "subdir2/subdir/test4.txt",
01964                                 "subdir2/subdir/test5.txt",
01965                                 "subdir2/subdir/sub",
01966                                 "subdir2/subdir/sub/test0.txt",
01967                                 "subdir2/subdir/sub/120-px-file.txt",
01968                         );
01969 
01970                         $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
01971                         $this->assertEquals( array(), $status->errors,
01972                                 "Locking of files succeeded ($backendName)." );
01973                         $this->assertEquals( true, $status->isOK(),
01974                                 "Locking of files succeeded with OK status ($backendName)." );
01975 
01976                         $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
01977                         $this->assertEquals( array(), $status->errors,
01978                                 "Locking of files succeeded ($backendName)." );
01979                         $this->assertEquals( true, $status->isOK(),
01980                                 "Locking of files succeeded with OK status ($backendName)." );
01981 
01982                         $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
01983                         $this->assertEquals( array(), $status->errors,
01984                                 "Locking of files succeeded ($backendName)." );
01985                         $this->assertEquals( true, $status->isOK(),
01986                                 "Locking of files succeeded with OK status ($backendName)." );
01987 
01988                         $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
01989                         $this->assertEquals( array(), $status->errors,
01990                                 "Locking of files succeeded ($backendName)." );
01991                         $this->assertEquals( true, $status->isOK(),
01992                                 "Locking of files succeeded with OK status ($backendName)." );
01993                 }
01994         }
01995 
01996         // test helper wrapper for backend prepare() function
01997         private function prepare( array $params ) {
01998                 return $this->backend->prepare( $params );
01999         }
02000 
02001         // test helper wrapper for backend prepare() function
02002         private function create( array $params ) {
02003                 $params['op'] = 'create';
02004                 return $this->backend->doQuickOperations( array( $params ) );
02005         }
02006 
02007         function tearDownFiles() {
02008                 foreach ( $this->filesToPrune as $file ) {
02009                         @unlink( $file );
02010                 }
02011                 $containers = array( 'unittest-cont1', 'unittest-cont2' );
02012                 foreach ( $containers as $container ) {
02013                         $this->deleteFiles( $container );
02014                 }
02015                 $this->filesToPrune = array();
02016         }
02017 
02018         private function deleteFiles( $container ) {
02019                 $base = self::baseStorePath();
02020                 $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
02021                 if ( $iter ) {
02022                         foreach ( $iter as $file ) {
02023                                 $this->backend->quickDelete( array( 'src' => "$base/$container/$file" ) );
02024                         }
02025                 }
02026                 $this->backend->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
02027         }
02028 
02029         function assertBackendPathsConsistent( array $paths ) {
02030                 if ( $this->backend instanceof FileBackendMultiWrite ) {
02031                         $status = $this->backend->consistencyCheck( $paths );
02032                         $this->assertGoodStatus( $status, "Files synced: " . implode( ',', $paths ) );
02033                 }
02034         }
02035 
02036         function assertGoodStatus( $status, $msg ) {
02037                 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors, 1 ), $msg );
02038         }
02039 }