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