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