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