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