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