MediaWiki
REL1_19
|
00001 <?php 00002 00007 class FileBackendTest extends MediaWikiTestCase { 00008 private $backend, $multiBackend; 00009 private $filesToPrune = array(); 00010 private $dirsToPrune = array(); 00011 private static $backendToUse; 00012 00013 function setUp() { 00014 global $wgFileBackends; 00015 parent::setUp(); 00016 $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand(); 00017 if ( $this->getCliArg( 'use-filebackend=' ) ) { 00018 if ( self::$backendToUse ) { 00019 $this->singleBackend = self::$backendToUse; 00020 } else { 00021 $name = $this->getCliArg( 'use-filebackend=' ); 00022 $useConfig = array(); 00023 foreach ( $wgFileBackends as $conf ) { 00024 if ( $conf['name'] == $name ) { 00025 $useConfig = $conf; 00026 } 00027 } 00028 $useConfig['name'] = 'localtesting'; // swap name 00029 $class = $conf['class']; 00030 self::$backendToUse = new $class( $useConfig ); 00031 $this->singleBackend = self::$backendToUse; 00032 } 00033 } else { 00034 $this->singleBackend = new FSFileBackend( array( 00035 'name' => 'localtesting', 00036 'lockManager' => 'fsLockManager', 00037 'containerPaths' => array( 00038 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1", 00039 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" ) 00040 ) ); 00041 } 00042 $this->multiBackend = new FileBackendMultiWrite( array( 00043 'name' => 'localtesting', 00044 'lockManager' => 'fsLockManager', 00045 'backends' => array( 00046 array( 00047 'name' => 'localmutlitesting1', 00048 'class' => 'FSFileBackend', 00049 'lockManager' => 'nullLockManager', 00050 'containerPaths' => array( 00051 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1", 00052 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ), 00053 'isMultiMaster' => false 00054 ), 00055 array( 00056 'name' => 'localmutlitesting2', 00057 'class' => 'FSFileBackend', 00058 'lockManager' => 'nullLockManager', 00059 'containerPaths' => array( 00060 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1", 00061 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ), 00062 'isMultiMaster' => true 00063 ) 00064 ) 00065 ) ); 00066 $this->filesToPrune = array(); 00067 } 00068 00069 private function baseStorePath() { 00070 return 'mwstore://localtesting'; 00071 } 00072 00073 private function backendClass() { 00074 return get_class( $this->backend ); 00075 } 00076 00080 public function testIsStoragePath( $path, $isStorePath ) { 00081 $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ), 00082 "FileBackend::isStoragePath on path '$path'" ); 00083 } 00084 00085 function provider_testIsStoragePath() { 00086 return array( 00087 array( 'mwstore://', true ), 00088 array( 'mwstore://backend', true ), 00089 array( 'mwstore://backend/container', true ), 00090 array( 'mwstore://backend/container/', true ), 00091 array( 'mwstore://backend/container/path', true ), 00092 array( 'mwstore://backend//container/', true ), 00093 array( 'mwstore://backend//container//', true ), 00094 array( 'mwstore://backend//container//path', true ), 00095 array( 'mwstore:///', true ), 00096 array( 'mwstore:/', false ), 00097 array( 'mwstore:', false ), 00098 ); 00099 } 00100 00104 public function testSplitStoragePath( $path, $res ) { 00105 $this->assertEquals( $res, FileBackend::splitStoragePath( $path ), 00106 "FileBackend::splitStoragePath on path '$path'" ); 00107 } 00108 00109 function provider_testSplitStoragePath() { 00110 return array( 00111 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ), 00112 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ), 00113 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ), 00114 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ), 00115 array( 'mwstore://backend//container/path', array( null, null, null ) ), 00116 array( 'mwstore://backend//container//path', array( null, null, null ) ), 00117 array( 'mwstore://', array( null, null, null ) ), 00118 array( 'mwstore://backend', array( null, null, null ) ), 00119 array( 'mwstore:///', array( null, null, null ) ), 00120 array( 'mwstore:/', array( null, null, null ) ), 00121 array( 'mwstore:', array( null, null, null ) ) 00122 ); 00123 } 00124 00128 public function testNormalizeStoragePath( $path, $res ) { 00129 $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ), 00130 "FileBackend::normalizeStoragePath on path '$path'" ); 00131 } 00132 00133 function provider_normalizeStoragePath() { 00134 return array( 00135 array( 'mwstore://backend/container', 'mwstore://backend/container' ), 00136 array( 'mwstore://backend/container/', 'mwstore://backend/container' ), 00137 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ), 00138 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ), 00139 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ), 00140 array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj', 00141 array( 'mwstore://', null ), 00142 array( 'mwstore://backend', null ), 00143 array( 'mwstore://backend//container/path', null ), 00144 array( 'mwstore://backend//container//path', null ), 00145 array( 'mwstore:///', null ), 00146 array( 'mwstore:/', null ), 00147 array( 'mwstore:', null ), ) 00148 ); 00149 } 00150 00154 public function testParentStoragePath( $path, $res ) { 00155 $this->assertEquals( $res, FileBackend::parentStoragePath( $path ), 00156 "FileBackend::parentStoragePath on path '$path'" ); 00157 } 00158 00159 function provider_testParentStoragePath() { 00160 return array( 00161 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ), 00162 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ), 00163 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ), 00164 array( 'mwstore://backend/container', null ), 00165 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ), 00166 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ), 00167 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ), 00168 array( 'mwstore://backend/container/', null ), 00169 ); 00170 } 00171 00175 public function testExtensionFromPath( $path, $res ) { 00176 $this->assertEquals( $res, FileBackend::extensionFromPath( $path ), 00177 "FileBackend::extensionFromPath on path '$path'" ); 00178 } 00179 00180 function provider_testExtensionFromPath() { 00181 return array( 00182 array( 'mwstore://backend/container/path.txt', 'txt' ), 00183 array( 'mwstore://backend/container/path.svg.png', 'png' ), 00184 array( 'mwstore://backend/container/path', '' ), 00185 array( 'mwstore://backend/container/path.', '' ), 00186 ); 00187 } 00188 00192 public function testStore( $op ) { 00193 $this->filesToPrune[] = $op['src']; 00194 00195 $this->backend = $this->singleBackend; 00196 $this->tearDownFiles(); 00197 $this->doTestStore( $op ); 00198 $this->tearDownFiles(); 00199 00200 $this->backend = $this->multiBackend; 00201 $this->tearDownFiles(); 00202 $this->doTestStore( $op ); 00203 $this->filesToPrune[] = $op['src']; # avoid file leaking 00204 $this->tearDownFiles(); 00205 } 00206 00207 function doTestStore( $op ) { 00208 $backendName = $this->backendClass(); 00209 00210 $source = $op['src']; 00211 $dest = $op['dst']; 00212 $this->prepare( array( 'dir' => dirname( $dest ) ) ); 00213 00214 file_put_contents( $source, "Unit test file" ); 00215 00216 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { 00217 $this->backend->store( $op ); 00218 } 00219 00220 $status = $this->backend->doOperation( $op ); 00221 00222 $this->assertEquals( array(), $status->errors, 00223 "Store from $source to $dest succeeded without warnings ($backendName)." ); 00224 $this->assertEquals( array(), $status->errors, 00225 "Store from $source to $dest succeeded ($backendName)." ); 00226 $this->assertEquals( array( 0 => true ), $status->success, 00227 "Store from $source to $dest has proper 'success' field in Status ($backendName)." ); 00228 $this->assertEquals( true, file_exists( $source ), 00229 "Source file $source still exists ($backendName)." ); 00230 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), 00231 "Destination file $dest exists ($backendName)." ); 00232 00233 $this->assertEquals( filesize( $source ), 00234 $this->backend->getFileSize( array( 'src' => $dest ) ), 00235 "Destination file $dest has correct size ($backendName)." ); 00236 00237 $props1 = FSFile::getPropsFromPath( $source ); 00238 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); 00239 $this->assertEquals( $props1, $props2, 00240 "Source and destination have the same props ($backendName)." ); 00241 } 00242 00243 public function provider_testStore() { 00244 $cases = array(); 00245 00246 $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath(); 00247 $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt'; 00248 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath ); 00249 $cases[] = array( 00250 $op, // operation 00251 $tmpName, // source 00252 $toPath, // dest 00253 ); 00254 00255 $op2 = $op; 00256 $op2['overwrite'] = true; 00257 $cases[] = array( 00258 $op2, // operation 00259 $tmpName, // source 00260 $toPath, // dest 00261 ); 00262 00263 $op2 = $op; 00264 $op2['overwriteSame'] = true; 00265 $cases[] = array( 00266 $op2, // operation 00267 $tmpName, // source 00268 $toPath, // dest 00269 ); 00270 00271 return $cases; 00272 } 00273 00277 public function testCopy( $op ) { 00278 $this->backend = $this->singleBackend; 00279 $this->tearDownFiles(); 00280 $this->doTestCopy( $op ); 00281 $this->tearDownFiles(); 00282 00283 $this->backend = $this->multiBackend; 00284 $this->tearDownFiles(); 00285 $this->doTestCopy( $op ); 00286 $this->tearDownFiles(); 00287 } 00288 00289 function doTestCopy( $op ) { 00290 $backendName = $this->backendClass(); 00291 00292 $source = $op['src']; 00293 $dest = $op['dst']; 00294 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00295 $this->prepare( array( 'dir' => dirname( $dest ) ) ); 00296 00297 $status = $this->backend->doOperation( 00298 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); 00299 $this->assertEquals( array(), $status->errors, 00300 "Creation of file at $source succeeded ($backendName)." ); 00301 00302 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { 00303 $this->backend->copy( $op ); 00304 } 00305 00306 $status = $this->backend->doOperation( $op ); 00307 00308 $this->assertEquals( array(), $status->errors, 00309 "Copy from $source to $dest succeeded without warnings ($backendName)." ); 00310 $this->assertEquals( true, $status->isOK(), 00311 "Copy from $source to $dest succeeded ($backendName)." ); 00312 $this->assertEquals( array( 0 => true ), $status->success, 00313 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." ); 00314 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ), 00315 "Source file $source still exists ($backendName)." ); 00316 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), 00317 "Destination file $dest exists after copy ($backendName)." ); 00318 00319 $this->assertEquals( 00320 $this->backend->getFileSize( array( 'src' => $source ) ), 00321 $this->backend->getFileSize( array( 'src' => $dest ) ), 00322 "Destination file $dest has correct size ($backendName)." ); 00323 00324 $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); 00325 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); 00326 $this->assertEquals( $props1, $props2, 00327 "Source and destination have the same props ($backendName)." ); 00328 } 00329 00330 public function provider_testCopy() { 00331 $cases = array(); 00332 00333 $source = $this->baseStorePath() . '/unittest-cont1/file.txt'; 00334 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt'; 00335 00336 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest ); 00337 $cases[] = array( 00338 $op, // operation 00339 $source, // source 00340 $dest, // dest 00341 ); 00342 00343 $op2 = $op; 00344 $op2['overwrite'] = true; 00345 $cases[] = array( 00346 $op2, // operation 00347 $source, // source 00348 $dest, // dest 00349 ); 00350 00351 $op2 = $op; 00352 $op2['overwriteSame'] = true; 00353 $cases[] = array( 00354 $op2, // operation 00355 $source, // source 00356 $dest, // dest 00357 ); 00358 00359 return $cases; 00360 } 00361 00365 public function testMove( $op ) { 00366 $this->backend = $this->singleBackend; 00367 $this->tearDownFiles(); 00368 $this->doTestMove( $op ); 00369 $this->tearDownFiles(); 00370 00371 $this->backend = $this->multiBackend; 00372 $this->tearDownFiles(); 00373 $this->doTestMove( $op ); 00374 $this->tearDownFiles(); 00375 } 00376 00377 private function doTestMove( $op ) { 00378 $backendName = $this->backendClass(); 00379 00380 $source = $op['src']; 00381 $dest = $op['dst']; 00382 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00383 $this->prepare( array( 'dir' => dirname( $dest ) ) ); 00384 00385 $status = $this->backend->doOperation( 00386 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); 00387 $this->assertEquals( array(), $status->errors, 00388 "Creation of file at $source succeeded ($backendName)." ); 00389 00390 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) { 00391 $this->backend->copy( $op ); 00392 } 00393 00394 $status = $this->backend->doOperation( $op ); 00395 $this->assertEquals( array(), $status->errors, 00396 "Move from $source to $dest succeeded without warnings ($backendName)." ); 00397 $this->assertEquals( true, $status->isOK(), 00398 "Move from $source to $dest succeeded ($backendName)." ); 00399 $this->assertEquals( array( 0 => true ), $status->success, 00400 "Move from $source to $dest has proper 'success' field in Status ($backendName)." ); 00401 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ), 00402 "Source file $source does not still exists ($backendName)." ); 00403 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), 00404 "Destination file $dest exists after move ($backendName)." ); 00405 00406 $this->assertNotEquals( 00407 $this->backend->getFileSize( array( 'src' => $source ) ), 00408 $this->backend->getFileSize( array( 'src' => $dest ) ), 00409 "Destination file $dest has correct size ($backendName)." ); 00410 00411 $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); 00412 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) ); 00413 $this->assertEquals( false, $props1['fileExists'], 00414 "Source file does not exist accourding to props ($backendName)." ); 00415 $this->assertEquals( true, $props2['fileExists'], 00416 "Destination file exists accourding to props ($backendName)." ); 00417 } 00418 00419 public function provider_testMove() { 00420 $cases = array(); 00421 00422 $source = $this->baseStorePath() . '/unittest-cont1/file.txt'; 00423 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt'; 00424 00425 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest ); 00426 $cases[] = array( 00427 $op, // operation 00428 $source, // source 00429 $dest, // dest 00430 ); 00431 00432 $op2 = $op; 00433 $op2['overwrite'] = true; 00434 $cases[] = array( 00435 $op2, // operation 00436 $source, // source 00437 $dest, // dest 00438 ); 00439 00440 $op2 = $op; 00441 $op2['overwriteSame'] = true; 00442 $cases[] = array( 00443 $op2, // operation 00444 $source, // source 00445 $dest, // dest 00446 ); 00447 00448 return $cases; 00449 } 00450 00454 public function testDelete( $op, $withSource, $okStatus ) { 00455 $this->backend = $this->singleBackend; 00456 $this->tearDownFiles(); 00457 $this->doTestDelete( $op, $withSource, $okStatus ); 00458 $this->tearDownFiles(); 00459 00460 $this->backend = $this->multiBackend; 00461 $this->tearDownFiles(); 00462 $this->doTestDelete( $op, $withSource, $okStatus ); 00463 $this->tearDownFiles(); 00464 } 00465 00466 private function doTestDelete( $op, $withSource, $okStatus ) { 00467 $backendName = $this->backendClass(); 00468 00469 $source = $op['src']; 00470 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00471 00472 if ( $withSource ) { 00473 $status = $this->backend->doOperation( 00474 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); 00475 $this->assertEquals( array(), $status->errors, 00476 "Creation of file at $source succeeded ($backendName)." ); 00477 } 00478 00479 $status = $this->backend->doOperation( $op ); 00480 if ( $okStatus ) { 00481 $this->assertEquals( array(), $status->errors, 00482 "Deletion of file at $source succeeded without warnings ($backendName)." ); 00483 $this->assertEquals( true, $status->isOK(), 00484 "Deletion of file at $source succeeded ($backendName)." ); 00485 $this->assertEquals( array( 0 => true ), $status->success, 00486 "Deletion of file at $source has proper 'success' field in Status ($backendName)." ); 00487 } else { 00488 $this->assertEquals( false, $status->isOK(), 00489 "Deletion of file at $source failed ($backendName)." ); 00490 } 00491 00492 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ), 00493 "Source file $source does not exist after move ($backendName)." ); 00494 00495 $this->assertFalse( 00496 $this->backend->getFileSize( array( 'src' => $source ) ), 00497 "Source file $source has correct size (false) ($backendName)." ); 00498 00499 $props1 = $this->backend->getFileProps( array( 'src' => $source ) ); 00500 $this->assertFalse( $props1['fileExists'], 00501 "Source file $source does not exist according to props ($backendName)." ); 00502 } 00503 00504 public function provider_testDelete() { 00505 $cases = array(); 00506 00507 $source = $this->baseStorePath() . '/unittest-cont1/myfacefile.txt'; 00508 00509 $op = array( 'op' => 'delete', 'src' => $source ); 00510 $cases[] = array( 00511 $op, // operation 00512 true, // with source 00513 true // succeeds 00514 ); 00515 00516 $cases[] = array( 00517 $op, // operation 00518 false, // without source 00519 false // fails 00520 ); 00521 00522 $op['ignoreMissingSource'] = true; 00523 $cases[] = array( 00524 $op, // operation 00525 false, // without source 00526 true // succeeds 00527 ); 00528 00529 return $cases; 00530 } 00531 00535 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) { 00536 $this->backend = $this->singleBackend; 00537 $this->tearDownFiles(); 00538 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize ); 00539 $this->tearDownFiles(); 00540 00541 $this->backend = $this->multiBackend; 00542 $this->tearDownFiles(); 00543 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize ); 00544 $this->tearDownFiles(); 00545 } 00546 00547 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) { 00548 $backendName = $this->backendClass(); 00549 00550 $dest = $op['dst']; 00551 $this->prepare( array( 'dir' => dirname( $dest ) ) ); 00552 00553 $oldText = 'blah...blah...waahwaah'; 00554 if ( $alreadyExists ) { 00555 $status = $this->backend->doOperation( 00556 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) ); 00557 $this->assertEquals( array(), $status->errors, 00558 "Creation of file at $dest succeeded ($backendName)." ); 00559 } 00560 00561 $status = $this->backend->doOperation( $op ); 00562 if ( $okStatus ) { 00563 $this->assertEquals( array(), $status->errors, 00564 "Creation of file at $dest succeeded without warnings ($backendName)." ); 00565 $this->assertEquals( true, $status->isOK(), 00566 "Creation of file at $dest succeeded ($backendName)." ); 00567 $this->assertEquals( array( 0 => true ), $status->success, 00568 "Creation of file at $dest has proper 'success' field in Status ($backendName)." ); 00569 } else { 00570 $this->assertEquals( false, $status->isOK(), 00571 "Creation of file at $dest failed ($backendName)." ); 00572 } 00573 00574 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ), 00575 "Destination file $dest exists after creation ($backendName)." ); 00576 00577 $props1 = $this->backend->getFileProps( array( 'src' => $dest ) ); 00578 $this->assertEquals( true, $props1['fileExists'], 00579 "Destination file $dest exists according to props ($backendName)." ); 00580 if ( $okStatus ) { // file content is what we saved 00581 $this->assertEquals( $newSize, $props1['size'], 00582 "Destination file $dest has expected size according to props ($backendName)." ); 00583 $this->assertEquals( $newSize, 00584 $this->backend->getFileSize( array( 'src' => $dest ) ), 00585 "Destination file $dest has correct size ($backendName)." ); 00586 } else { // file content is some other previous text 00587 $this->assertEquals( strlen( $oldText ), $props1['size'], 00588 "Destination file $dest has original size according to props ($backendName)." ); 00589 $this->assertEquals( strlen( $oldText ), 00590 $this->backend->getFileSize( array( 'src' => $dest ) ), 00591 "Destination file $dest has original size according to props ($backendName)." ); 00592 } 00593 } 00594 00598 public function provider_testCreate() { 00599 $cases = array(); 00600 00601 $dest = $this->baseStorePath() . '/unittest-cont2/myspacefile.txt'; 00602 00603 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest ); 00604 $cases[] = array( 00605 $op, // operation 00606 false, // no dest already exists 00607 true, // succeeds 00608 strlen( $op['content'] ) 00609 ); 00610 00611 $op2 = $op; 00612 $op2['content'] = "\n"; 00613 $cases[] = array( 00614 $op2, // operation 00615 false, // no dest already exists 00616 true, // succeeds 00617 strlen( $op2['content'] ) 00618 ); 00619 00620 $op2 = $op; 00621 $op2['content'] = "fsf\n waf 3kt"; 00622 $cases[] = array( 00623 $op2, // operation 00624 true, // dest already exists 00625 false, // fails 00626 strlen( $op2['content'] ) 00627 ); 00628 00629 $op2 = $op; 00630 $op2['content'] = "egm'g gkpe gpqg eqwgwqg"; 00631 $op2['overwrite'] = true; 00632 $cases[] = array( 00633 $op2, // operation 00634 true, // dest already exists 00635 true, // succeeds 00636 strlen( $op2['content'] ) 00637 ); 00638 00639 $op2 = $op; 00640 $op2['content'] = "39qjmg3-qg"; 00641 $op2['overwriteSame'] = true; 00642 $cases[] = array( 00643 $op2, // operation 00644 true, // dest already exists 00645 false, // succeeds 00646 strlen( $op2['content'] ) 00647 ); 00648 00649 return $cases; 00650 } 00651 00655 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) { 00656 $this->filesToPrune[] = $op['dst']; 00657 00658 $this->backend = $this->singleBackend; 00659 $this->tearDownFiles(); 00660 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); 00661 $this->tearDownFiles(); 00662 00663 $this->backend = $this->multiBackend; 00664 $this->tearDownFiles(); 00665 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ); 00666 $this->filesToPrune[] = $op['dst']; # avoid file leaking 00667 $this->tearDownFiles(); 00668 } 00669 00670 public function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) { 00671 $backendName = $this->backendClass(); 00672 00673 $expContent = ''; 00674 // Create sources 00675 $ops = array(); 00676 foreach ( $srcs as $i => $source ) { 00677 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00678 $ops[] = array( 00679 'op' => 'create', // operation 00680 'dst' => $source, // source 00681 'content' => $srcsContent[$i] 00682 ); 00683 $expContent .= $srcsContent[$i]; 00684 } 00685 $status = $this->backend->doOperations( $ops ); 00686 00687 $this->assertEquals( array(), $status->errors, 00688 "Creation of source files succeeded ($backendName)." ); 00689 00690 $dest = $params['dst']; 00691 if ( $alreadyExists ) { 00692 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false; 00693 $this->assertEquals( true, $ok, 00694 "Creation of file at $dest succeeded ($backendName)." ); 00695 } else { 00696 $ok = file_put_contents( $dest, '' ) !== false; 00697 $this->assertEquals( true, $ok, 00698 "Creation of 0-byte file at $dest succeeded ($backendName)." ); 00699 } 00700 00701 // Combine the files into one 00702 $status = $this->backend->concatenate( $params ); 00703 if ( $okStatus ) { 00704 $this->assertEquals( array(), $status->errors, 00705 "Creation of concat file at $dest succeeded without warnings ($backendName)." ); 00706 $this->assertEquals( true, $status->isOK(), 00707 "Creation of concat file at $dest succeeded ($backendName)." ); 00708 } else { 00709 $this->assertEquals( false, $status->isOK(), 00710 "Creation of concat file at $dest failed ($backendName)." ); 00711 } 00712 00713 if ( $okStatus ) { 00714 $this->assertEquals( true, is_file( $dest ), 00715 "Dest concat file $dest exists after creation ($backendName)." ); 00716 } else { 00717 $this->assertEquals( true, is_file( $dest ), 00718 "Dest concat file $dest exists after failed creation ($backendName)." ); 00719 } 00720 00721 $contents = file_get_contents( $dest ); 00722 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." ); 00723 00724 if ( $okStatus ) { 00725 $this->assertEquals( $expContent, $contents, 00726 "Concat file at $dest has correct contents ($backendName)." ); 00727 } else { 00728 $this->assertNotEquals( $expContent, $contents, 00729 "Concat file at $dest has correct contents ($backendName)." ); 00730 } 00731 } 00732 00733 function provider_testConcatenate() { 00734 $cases = array(); 00735 00736 $rand = mt_rand( 0, 2000000000 ) . time(); 00737 $dest = wfTempDir() . "/randomfile!$rand.txt"; 00738 $srcs = array( 00739 $this->baseStorePath() . '/unittest-cont1/file1.txt', 00740 $this->baseStorePath() . '/unittest-cont1/file2.txt', 00741 $this->baseStorePath() . '/unittest-cont1/file3.txt', 00742 $this->baseStorePath() . '/unittest-cont1/file4.txt', 00743 $this->baseStorePath() . '/unittest-cont1/file5.txt', 00744 $this->baseStorePath() . '/unittest-cont1/file6.txt', 00745 $this->baseStorePath() . '/unittest-cont1/file7.txt', 00746 $this->baseStorePath() . '/unittest-cont1/file8.txt', 00747 $this->baseStorePath() . '/unittest-cont1/file9.txt', 00748 $this->baseStorePath() . '/unittest-cont1/file10.txt' 00749 ); 00750 $content = array( 00751 'egfage', 00752 'ageageag', 00753 'rhokohlr', 00754 'shgmslkg', 00755 'kenga', 00756 'owagmal', 00757 'kgmae', 00758 'g eak;g', 00759 'lkaem;a', 00760 'legma' 00761 ); 00762 $params = array( 'srcs' => $srcs, 'dst' => $dest ); 00763 00764 $cases[] = array( 00765 $params, // operation 00766 $srcs, // sources 00767 $content, // content for each source 00768 false, // no dest already exists 00769 true, // succeeds 00770 ); 00771 00772 $cases[] = array( 00773 $params, // operation 00774 $srcs, // sources 00775 $content, // content for each source 00776 true, // dest already exists 00777 false, // succeeds 00778 ); 00779 00780 return $cases; 00781 } 00782 00786 public function testGetFileStat( $path, $content, $alreadyExists ) { 00787 $this->backend = $this->singleBackend; 00788 $this->tearDownFiles(); 00789 $this->doTestGetFileStat( $path, $content, $alreadyExists ); 00790 $this->tearDownFiles(); 00791 00792 $this->backend = $this->multiBackend; 00793 $this->tearDownFiles(); 00794 $this->doTestGetFileStat( $path, $content, $alreadyExists ); 00795 $this->tearDownFiles(); 00796 } 00797 00798 private function doTestGetFileStat( $path, $content, $alreadyExists ) { 00799 $backendName = $this->backendClass(); 00800 00801 if ( $alreadyExists ) { 00802 $this->prepare( array( 'dir' => dirname( $path ) ) ); 00803 $status = $this->backend->create( array( 'dst' => $path, 'content' => $content ) ); 00804 $this->assertEquals( array(), $status->errors, 00805 "Creation of file at $path succeeded ($backendName)." ); 00806 00807 $size = $this->backend->getFileSize( array( 'src' => $path ) ); 00808 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) ); 00809 $stat = $this->backend->getFileStat( array( 'src' => $path ) ); 00810 00811 $this->assertEquals( strlen( $content ), $size, 00812 "Correct file size of '$path'" ); 00813 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5, 00814 "Correct file timestamp of '$path'" ); 00815 00816 $size = $stat['size']; 00817 $time = $stat['mtime']; 00818 $this->assertEquals( strlen( $content ), $size, 00819 "Correct file size of '$path'" ); 00820 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 5, 00821 "Correct file timestamp of '$path'" ); 00822 } else { 00823 $size = $this->backend->getFileSize( array( 'src' => $path ) ); 00824 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) ); 00825 $stat = $this->backend->getFileStat( array( 'src' => $path ) ); 00826 00827 $this->assertFalse( $size, "Correct file size of '$path'" ); 00828 $this->assertFalse( $time, "Correct file timestamp of '$path'" ); 00829 $this->assertFalse( $stat, "Correct file stat of '$path'" ); 00830 } 00831 } 00832 00833 function provider_testGetFileStat() { 00834 $cases = array(); 00835 00836 $base = $this->baseStorePath(); 00837 $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents", true ); 00838 $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "", true ); 00839 $cases[] = array( "$base/unittest-cont1/b/some-diff_file.txt", null, false ); 00840 00841 return $cases; 00842 } 00843 00847 public function testGetFileContents( $source, $content ) { 00848 $this->backend = $this->singleBackend; 00849 $this->tearDownFiles(); 00850 $this->doTestGetFileContents( $source, $content ); 00851 $this->tearDownFiles(); 00852 00853 $this->backend = $this->multiBackend; 00854 $this->tearDownFiles(); 00855 $this->doTestGetFileContents( $source, $content ); 00856 $this->tearDownFiles(); 00857 } 00858 00859 public function doTestGetFileContents( $source, $content ) { 00860 $backendName = $this->backendClass(); 00861 00862 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00863 00864 $status = $this->backend->doOperation( 00865 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); 00866 $this->assertEquals( array(), $status->errors, 00867 "Creation of file at $source succeeded ($backendName)." ); 00868 $this->assertEquals( true, $status->isOK(), 00869 "Creation of file at $source succeeded with OK status ($backendName)." ); 00870 00871 $newContents = $this->backend->getFileContents( array( 'src' => $source, 'latest' => 1 ) ); 00872 $this->assertNotEquals( false, $newContents, 00873 "Read of file at $source succeeded ($backendName)." ); 00874 00875 $this->assertEquals( $content, $newContents, 00876 "Contents read match data at $source ($backendName)." ); 00877 } 00878 00879 function provider_testGetFileContents() { 00880 $cases = array(); 00881 00882 $base = $this->baseStorePath(); 00883 $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents" ); 00884 $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "more file contents" ); 00885 00886 return $cases; 00887 } 00888 00892 public function testGetLocalCopy( $source, $content ) { 00893 $this->backend = $this->singleBackend; 00894 $this->tearDownFiles(); 00895 $this->doTestGetLocalCopy( $source, $content ); 00896 $this->tearDownFiles(); 00897 00898 $this->backend = $this->multiBackend; 00899 $this->tearDownFiles(); 00900 $this->doTestGetLocalCopy( $source, $content ); 00901 $this->tearDownFiles(); 00902 } 00903 00904 public function doTestGetLocalCopy( $source, $content ) { 00905 $backendName = $this->backendClass(); 00906 00907 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00908 00909 $status = $this->backend->doOperation( 00910 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); 00911 $this->assertEquals( array(), $status->errors, 00912 "Creation of file at $source succeeded ($backendName)." ); 00913 00914 $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) ); 00915 $this->assertNotNull( $tmpFile, 00916 "Creation of local copy of $source succeeded ($backendName)." ); 00917 00918 $contents = file_get_contents( $tmpFile->getPath() ); 00919 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); 00920 } 00921 00922 function provider_testGetLocalCopy() { 00923 $cases = array(); 00924 00925 $base = $this->baseStorePath(); 00926 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" ); 00927 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" ); 00928 00929 return $cases; 00930 } 00931 00935 public function testGetLocalReference( $source, $content ) { 00936 $this->backend = $this->singleBackend; 00937 $this->tearDownFiles(); 00938 $this->doTestGetLocalReference( $source, $content ); 00939 $this->tearDownFiles(); 00940 00941 $this->backend = $this->multiBackend; 00942 $this->tearDownFiles(); 00943 $this->doTestGetLocalReference( $source, $content ); 00944 $this->tearDownFiles(); 00945 } 00946 00947 private function doTestGetLocalReference( $source, $content ) { 00948 $backendName = $this->backendClass(); 00949 00950 $this->prepare( array( 'dir' => dirname( $source ) ) ); 00951 00952 $status = $this->backend->doOperation( 00953 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); 00954 $this->assertEquals( array(), $status->errors, 00955 "Creation of file at $source succeeded ($backendName)." ); 00956 00957 $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) ); 00958 $this->assertNotNull( $tmpFile, 00959 "Creation of local copy of $source succeeded ($backendName)." ); 00960 00961 $contents = file_get_contents( $tmpFile->getPath() ); 00962 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); 00963 } 00964 00965 function provider_testGetLocalReference() { 00966 $cases = array(); 00967 00968 $base = $this->baseStorePath(); 00969 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" ); 00970 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" ); 00971 00972 return $cases; 00973 } 00974 00978 public function testPrepareAndClean( $path, $isOK ) { 00979 $this->backend = $this->singleBackend; 00980 $this->doTestPrepareAndClean( $path, $isOK ); 00981 $this->tearDownFiles(); 00982 00983 $this->backend = $this->multiBackend; 00984 $this->doTestPrepareAndClean( $path, $isOK ); 00985 $this->tearDownFiles(); 00986 } 00987 00988 function provider_testPrepareAndClean() { 00989 $base = $this->baseStorePath(); 00990 return array( 00991 array( "$base/unittest-cont1/a/z/some_file1.txt", true ), 00992 array( "$base/unittest-cont2/a/z/some_file2.txt", true ), 00993 # Specific to FS backend with no basePath field set 00994 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ), 00995 ); 00996 } 00997 00998 function doTestPrepareAndClean( $path, $isOK ) { 00999 $backendName = $this->backendClass(); 01000 01001 $status = $this->prepare( array( 'dir' => dirname( $path ) ) ); 01002 if ( $isOK ) { 01003 $this->assertEquals( array(), $status->errors, 01004 "Preparing dir $path succeeded without warnings ($backendName)." ); 01005 $this->assertEquals( true, $status->isOK(), 01006 "Preparing dir $path succeeded ($backendName)." ); 01007 } else { 01008 $this->assertEquals( false, $status->isOK(), 01009 "Preparing dir $path failed ($backendName)." ); 01010 } 01011 01012 $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) ); 01013 if ( $isOK ) { 01014 $this->assertEquals( array(), $status->errors, 01015 "Cleaning dir $path succeeded without warnings ($backendName)." ); 01016 $this->assertEquals( true, $status->isOK(), 01017 "Cleaning dir $path succeeded ($backendName)." ); 01018 } else { 01019 $this->assertEquals( false, $status->isOK(), 01020 "Cleaning dir $path failed ($backendName)." ); 01021 } 01022 } 01023 01024 // @TODO: testSecure 01025 01026 public function testDoOperations() { 01027 $this->backend = $this->singleBackend; 01028 $this->tearDownFiles(); 01029 $this->doTestDoOperations(); 01030 $this->tearDownFiles(); 01031 01032 $this->backend = $this->multiBackend; 01033 $this->tearDownFiles(); 01034 $this->doTestDoOperations(); 01035 $this->tearDownFiles(); 01036 01037 $this->backend = $this->singleBackend; 01038 $this->tearDownFiles(); 01039 $this->doTestDoOperationsFailing(); 01040 $this->tearDownFiles(); 01041 01042 $this->backend = $this->multiBackend; 01043 $this->tearDownFiles(); 01044 $this->doTestDoOperationsFailing(); 01045 $this->tearDownFiles(); 01046 01047 // @TODO: test some cases where the ops should fail 01048 } 01049 01050 function doTestDoOperations() { 01051 $base = $this->baseStorePath(); 01052 01053 $fileA = "$base/unittest-cont1/a/b/fileA.txt"; 01054 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq'; 01055 $fileB = "$base/unittest-cont1/a/b/fileB.txt"; 01056 $fileBContents = 'g-jmq3gpqgt3qtg q3GT '; 01057 $fileC = "$base/unittest-cont1/a/b/fileC.txt"; 01058 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag'; 01059 $fileD = "$base/unittest-cont1/a/b/fileD.txt"; 01060 01061 $this->prepare( array( 'dir' => dirname( $fileA ) ) ); 01062 $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) ); 01063 $this->prepare( array( 'dir' => dirname( $fileB ) ) ); 01064 $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) ); 01065 $this->prepare( array( 'dir' => dirname( $fileC ) ) ); 01066 $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) ); 01067 01068 $status = $this->backend->doOperations( array( 01069 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ), 01070 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>) 01071 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ), 01072 // Now: A:<A>, B:<B>, C:<A>, D:<empty> 01073 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ), 01074 // Now: A:<A>, B:<B>, C:<empty>, D:<A> 01075 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ), 01076 // Now: A:<A>, B:<empty>, C:<B>, D:<A> 01077 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ), 01078 // Now: A:<A>, B:<empty>, C:<B>, D:<empty> 01079 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ), 01080 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty> 01081 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ), 01082 // Now: A:<B>, B:<empty>, C:<B>, D:<empty> 01083 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ), 01084 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty> 01085 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ), 01086 // Does nothing 01087 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ), 01088 // Does nothing 01089 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ), 01090 // Does nothing 01091 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ), 01092 // Does nothing 01093 array( 'op' => 'null' ), 01094 // Does nothing 01095 ) ); 01096 01097 $this->assertEquals( array(), $status->errors, "Operation batch succeeded" ); 01098 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" ); 01099 $this->assertEquals( 13, count( $status->success ), 01100 "Operation batch has correct success array" ); 01101 01102 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ), 01103 "File does not exist at $fileA" ); 01104 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ), 01105 "File does not exist at $fileB" ); 01106 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ), 01107 "File does not exist at $fileD" ); 01108 01109 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ), 01110 "File exists at $fileC" ); 01111 $this->assertEquals( $fileBContents, 01112 $this->backend->getFileContents( array( 'src' => $fileC ) ), 01113 "Correct file contents of $fileC" ); 01114 $this->assertEquals( strlen( $fileBContents ), 01115 $this->backend->getFileSize( array( 'src' => $fileC ) ), 01116 "Correct file size of $fileC" ); 01117 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ), 01118 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ), 01119 "Correct file SHA-1 of $fileC" ); 01120 } 01121 01122 function doTestDoOperationsFailing() { 01123 $base = $this->baseStorePath(); 01124 01125 $fileA = "$base/unittest-cont2/a/b/fileA.txt"; 01126 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq'; 01127 $fileB = "$base/unittest-cont2/a/b/fileB.txt"; 01128 $fileBContents = 'g-jmq3gpqgt3qtg q3GT '; 01129 $fileC = "$base/unittest-cont2/a/b/fileC.txt"; 01130 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag'; 01131 $fileD = "$base/unittest-cont2/a/b/fileD.txt"; 01132 01133 $this->prepare( array( 'dir' => dirname( $fileA ) ) ); 01134 $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) ); 01135 $this->prepare( array( 'dir' => dirname( $fileB ) ) ); 01136 $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) ); 01137 $this->prepare( array( 'dir' => dirname( $fileC ) ) ); 01138 $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) ); 01139 01140 $status = $this->backend->doOperations( array( 01141 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ), 01142 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>) 01143 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ), 01144 // Now: A:<A>, B:<B>, C:<A>, D:<empty> 01145 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ), 01146 // Now: A:<A>, B:<B>, C:<A>, D:<B> 01147 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ), 01148 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed) 01149 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ), 01150 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed) 01151 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ), 01152 // Now: A:<B>, B:<empty>, C:<A>, D:<empty> 01153 array( 'op' => 'delete', 'src' => $fileD ), 01154 // Now: A:<B>, B:<empty>, C:<A>, D:<empty> 01155 array( 'op' => 'null' ), 01156 // Does nothing 01157 ), array( 'force' => 1 ) ); 01158 01159 $this->assertNotEquals( array(), $status->errors, "Operation had warnings" ); 01160 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" ); 01161 $this->assertEquals( 8, count( $status->success ), 01162 "Operation batch has correct success array" ); 01163 01164 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ), 01165 "File does not exist at $fileB" ); 01166 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ), 01167 "File does not exist at $fileD" ); 01168 01169 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ), 01170 "File does not exist at $fileA" ); 01171 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ), 01172 "File exists at $fileC" ); 01173 $this->assertEquals( $fileBContents, 01174 $this->backend->getFileContents( array( 'src' => $fileA ) ), 01175 "Correct file contents of $fileA" ); 01176 $this->assertEquals( strlen( $fileBContents ), 01177 $this->backend->getFileSize( array( 'src' => $fileA ) ), 01178 "Correct file size of $fileA" ); 01179 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ), 01180 $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ), 01181 "Correct file SHA-1 of $fileA" ); 01182 } 01183 01184 public function testGetFileList() { 01185 $this->backend = $this->singleBackend; 01186 $this->tearDownFiles(); 01187 $this->doTestGetFileList(); 01188 $this->tearDownFiles(); 01189 01190 $this->backend = $this->multiBackend; 01191 $this->tearDownFiles(); 01192 $this->doTestGetFileList(); 01193 $this->tearDownFiles(); 01194 } 01195 01196 private function doTestGetFileList() { 01197 $backendName = $this->backendClass(); 01198 01199 $base = $this->baseStorePath(); 01200 $files = array( 01201 "$base/unittest-cont1/test1.txt", 01202 "$base/unittest-cont1/test2.txt", 01203 "$base/unittest-cont1/test3.txt", 01204 "$base/unittest-cont1/subdir1/test1.txt", 01205 "$base/unittest-cont1/subdir1/test2.txt", 01206 "$base/unittest-cont1/subdir2/test3.txt", 01207 "$base/unittest-cont1/subdir2/test4.txt", 01208 "$base/unittest-cont1/subdir2/subdir/test1.txt", 01209 "$base/unittest-cont1/subdir2/subdir/test2.txt", 01210 "$base/unittest-cont1/subdir2/subdir/test3.txt", 01211 "$base/unittest-cont1/subdir2/subdir/test4.txt", 01212 "$base/unittest-cont1/subdir2/subdir/test5.txt", 01213 "$base/unittest-cont1/subdir2/subdir/sub/test0.txt", 01214 "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt", 01215 ); 01216 01217 // Add the files 01218 $ops = array(); 01219 foreach ( $files as $file ) { 01220 $this->prepare( array( 'dir' => dirname( $file ) ) ); 01221 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file ); 01222 } 01223 $status = $this->backend->doOperations( $ops ); 01224 $this->assertEquals( array(), $status->errors, 01225 "Creation of files succeeded ($backendName)." ); 01226 $this->assertEquals( true, $status->isOK(), 01227 "Creation of files succeeded with OK status ($backendName)." ); 01228 01229 // Expected listing 01230 $expected = array( 01231 "test1.txt", 01232 "test2.txt", 01233 "test3.txt", 01234 "subdir1/test1.txt", 01235 "subdir1/test2.txt", 01236 "subdir2/test3.txt", 01237 "subdir2/test4.txt", 01238 "subdir2/subdir/test1.txt", 01239 "subdir2/subdir/test2.txt", 01240 "subdir2/subdir/test3.txt", 01241 "subdir2/subdir/test4.txt", 01242 "subdir2/subdir/test5.txt", 01243 "subdir2/subdir/sub/test0.txt", 01244 "subdir2/subdir/sub/120-px-file.txt", 01245 ); 01246 sort( $expected ); 01247 01248 // Actual listing (no trailing slash) 01249 $list = array(); 01250 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) ); 01251 foreach ( $iter as $file ) { 01252 $list[] = $file; 01253 } 01254 sort( $list ); 01255 01256 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); 01257 01258 // Actual listing (with trailing slash) 01259 $list = array(); 01260 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) ); 01261 foreach ( $iter as $file ) { 01262 $list[] = $file; 01263 } 01264 sort( $list ); 01265 01266 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); 01267 01268 // Expected listing 01269 $expected = array( 01270 "test1.txt", 01271 "test2.txt", 01272 "test3.txt", 01273 "test4.txt", 01274 "test5.txt", 01275 "sub/test0.txt", 01276 "sub/120-px-file.txt", 01277 ); 01278 sort( $expected ); 01279 01280 // Actual listing (no trailing slash) 01281 $list = array(); 01282 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) ); 01283 foreach ( $iter as $file ) { 01284 $list[] = $file; 01285 } 01286 sort( $list ); 01287 01288 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); 01289 01290 // Actual listing (with trailing slash) 01291 $list = array(); 01292 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) ); 01293 foreach ( $iter as $file ) { 01294 $list[] = $file; 01295 } 01296 sort( $list ); 01297 01298 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." ); 01299 01300 // Actual listing (using iterator second time) 01301 $list = array(); 01302 foreach ( $iter as $file ) { 01303 $list[] = $file; 01304 } 01305 sort( $list ); 01306 01307 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." ); 01308 01309 foreach ( $files as $file ) { // clean up 01310 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) ); 01311 } 01312 01313 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) ); 01314 foreach ( $iter as $iter ) {} // no errors 01315 } 01316 01317 // test helper wrapper for backend prepare() function 01318 private function prepare( array $params ) { 01319 $this->dirsToPrune[] = $params['dir']; 01320 return $this->backend->prepare( $params ); 01321 } 01322 01323 function tearDownFiles() { 01324 foreach ( $this->filesToPrune as $file ) { 01325 @unlink( $file ); 01326 } 01327 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' ); 01328 foreach ( $containers as $container ) { 01329 $this->deleteFiles( $container ); 01330 } 01331 foreach ( $this->dirsToPrune as $dir ) { 01332 $this->recursiveClean( $dir ); 01333 } 01334 $this->filesToPrune = $this->dirsToPrune = array(); 01335 } 01336 01337 private function deleteFiles( $container ) { 01338 $base = $this->baseStorePath(); 01339 $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) ); 01340 if ( $iter ) { 01341 foreach ( $iter as $file ) { 01342 $this->backend->delete( array( 'src' => "$base/$container/$file" ), array( 'force' => 1 ) ); 01343 } 01344 } 01345 } 01346 01347 private function recursiveClean( $dir ) { 01348 do { 01349 if ( !$this->backend->clean( array( 'dir' => $dir ) )->isOK() ) { 01350 break; 01351 } 01352 } while ( $dir = FileBackend::parentStoragePath( $dir ) ); 01353 } 01354 01355 function tearDown() { 01356 parent::tearDown(); 01357 } 01358 }