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