Merge "Migrate redirectToFragment() from wikibits.js to own module"
[lhc/web/wiklou.git] / tests / phpunit / includes / filebackend / FileBackendTest.php
1 <?php
2
3 /**
4 * @group FileRepo
5 * @group FileBackend
6 * @group medium
7 */
8 class FileBackendTest extends MediaWikiTestCase {
9
10 /** @var FileBackend */
11 private $backend;
12 /** @var FileBackendMultiWrite */
13 private $multiBackend;
14 /** @var FSFileBackend */
15 public $singleBackend;
16 private $filesToPrune = array();
17 private static $backendToUse;
18
19 protected function setUp() {
20 global $wgFileBackends;
21 parent::setUp();
22 $uniqueId = time() . '-' . mt_rand();
23 $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . $uniqueId;
24 if ( $this->getCliArg( 'use-filebackend=' ) ) {
25 if ( self::$backendToUse ) {
26 $this->singleBackend = self::$backendToUse;
27 } else {
28 $name = $this->getCliArg( 'use-filebackend=' );
29 $useConfig = array();
30 foreach ( $wgFileBackends as $conf ) {
31 if ( $conf['name'] == $name ) {
32 $useConfig = $conf;
33 break;
34 }
35 }
36 $useConfig['name'] = 'localtesting'; // swap name
37 $useConfig['shardViaHashLevels'] = array( // test sharding
38 'unittest-cont1' => array( 'levels' => 1, 'base' => 16, 'repeat' => 1 )
39 );
40 if ( isset( $useConfig['fileJournal'] ) ) {
41 $useConfig['fileJournal'] = FileJournal::factory( $useConfig['fileJournal'], $name );
42 }
43 $useConfig['lockManager'] = LockManagerGroup::singleton()->get( $useConfig['lockManager'] );
44 $class = $useConfig['class'];
45 self::$backendToUse = new $class( $useConfig );
46 $this->singleBackend = self::$backendToUse;
47 }
48 } else {
49 $this->singleBackend = new FSFileBackend( array(
50 'name' => 'localtesting',
51 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
52 'wikiId' => wfWikiID(),
53 'containerPaths' => array(
54 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
55 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
56 ) );
57 }
58 $this->multiBackend = new FileBackendMultiWrite( array(
59 'name' => 'localtesting',
60 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
61 'parallelize' => 'implicit',
62 'wikiId' => wfWikiId() . $uniqueId,
63 'backends' => array(
64 array(
65 'name' => 'localmultitesting1',
66 'class' => 'FSFileBackend',
67 'containerPaths' => array(
68 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
69 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
70 'isMultiMaster' => false
71 ),
72 array(
73 'name' => 'localmultitesting2',
74 'class' => 'FSFileBackend',
75 'containerPaths' => array(
76 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
77 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
78 'isMultiMaster' => true
79 )
80 )
81 ) );
82 $this->filesToPrune = array();
83 }
84
85 private static function baseStorePath() {
86 return 'mwstore://localtesting';
87 }
88
89 private function backendClass() {
90 return get_class( $this->backend );
91 }
92
93 /**
94 * @dataProvider provider_testIsStoragePath
95 * @covers FileBackend::isStoragePath
96 */
97 public function testIsStoragePath( $path, $isStorePath ) {
98 $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ),
99 "FileBackend::isStoragePath on path '$path'" );
100 }
101
102 public static function provider_testIsStoragePath() {
103 return array(
104 array( 'mwstore://', true ),
105 array( 'mwstore://backend', true ),
106 array( 'mwstore://backend/container', true ),
107 array( 'mwstore://backend/container/', true ),
108 array( 'mwstore://backend/container/path', true ),
109 array( 'mwstore://backend//container/', true ),
110 array( 'mwstore://backend//container//', true ),
111 array( 'mwstore://backend//container//path', true ),
112 array( 'mwstore:///', true ),
113 array( 'mwstore:/', false ),
114 array( 'mwstore:', false ),
115 );
116 }
117
118 /**
119 * @dataProvider provider_testSplitStoragePath
120 * @covers FileBackend::splitStoragePath
121 */
122 public function testSplitStoragePath( $path, $res ) {
123 $this->assertEquals( $res, FileBackend::splitStoragePath( $path ),
124 "FileBackend::splitStoragePath on path '$path'" );
125 }
126
127 public static function provider_testSplitStoragePath() {
128 return array(
129 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
130 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
131 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
132 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
133 array( 'mwstore://backend//container/path', array( null, null, null ) ),
134 array( 'mwstore://backend//container//path', array( null, null, null ) ),
135 array( 'mwstore://', array( null, null, null ) ),
136 array( 'mwstore://backend', array( null, null, null ) ),
137 array( 'mwstore:///', array( null, null, null ) ),
138 array( 'mwstore:/', array( null, null, null ) ),
139 array( 'mwstore:', array( null, null, null ) )
140 );
141 }
142
143 /**
144 * @dataProvider provider_normalizeStoragePath
145 * @covers FileBackend::normalizeStoragePath
146 */
147 public function testNormalizeStoragePath( $path, $res ) {
148 $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ),
149 "FileBackend::normalizeStoragePath on path '$path'" );
150 }
151
152 public static function provider_normalizeStoragePath() {
153 return array(
154 array( 'mwstore://backend/container', 'mwstore://backend/container' ),
155 array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
156 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
157 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
158 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
159 array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj' ),
160 array( 'mwstore://', null ),
161 array( 'mwstore://backend', null ),
162 array( 'mwstore://backend//container/path', null ),
163 array( 'mwstore://backend//container//path', null ),
164 array( 'mwstore:///', null ),
165 array( 'mwstore:/', null ),
166 array( 'mwstore:', null ),
167 );
168 }
169
170 /**
171 * @dataProvider provider_testParentStoragePath
172 * @covers FileBackend::parentStoragePath
173 */
174 public function testParentStoragePath( $path, $res ) {
175 $this->assertEquals( $res, FileBackend::parentStoragePath( $path ),
176 "FileBackend::parentStoragePath on path '$path'" );
177 }
178
179 public static function provider_testParentStoragePath() {
180 return array(
181 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
182 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
183 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
184 array( 'mwstore://backend/container', null ),
185 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
186 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
187 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
188 array( 'mwstore://backend/container/', null ),
189 );
190 }
191
192 /**
193 * @dataProvider provider_testExtensionFromPath
194 * @covers FileBackend::extensionFromPath
195 */
196 public function testExtensionFromPath( $path, $res ) {
197 $this->assertEquals( $res, FileBackend::extensionFromPath( $path ),
198 "FileBackend::extensionFromPath on path '$path'" );
199 }
200
201 public static function provider_testExtensionFromPath() {
202 return array(
203 array( 'mwstore://backend/container/path.txt', 'txt' ),
204 array( 'mwstore://backend/container/path.svg.png', 'png' ),
205 array( 'mwstore://backend/container/path', '' ),
206 array( 'mwstore://backend/container/path.', '' ),
207 );
208 }
209
210 /**
211 * @dataProvider provider_testStore
212 */
213 public function testStore( $op ) {
214 $this->filesToPrune[] = $op['src'];
215
216 $this->backend = $this->singleBackend;
217 $this->tearDownFiles();
218 $this->doTestStore( $op );
219 $this->tearDownFiles();
220
221 $this->backend = $this->multiBackend;
222 $this->tearDownFiles();
223 $this->doTestStore( $op );
224 $this->filesToPrune[] = $op['src']; # avoid file leaking
225 $this->tearDownFiles();
226 }
227
228 /**
229 * @covers FileBackend::doOperation
230 */
231 private function doTestStore( $op ) {
232 $backendName = $this->backendClass();
233
234 $source = $op['src'];
235 $dest = $op['dst'];
236 $this->prepare( array( 'dir' => dirname( $dest ) ) );
237
238 file_put_contents( $source, "Unit test file" );
239
240 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
241 $this->backend->store( $op );
242 }
243
244 $status = $this->backend->doOperation( $op );
245
246 $this->assertGoodStatus( $status,
247 "Store from $source to $dest succeeded without warnings ($backendName)." );
248 $this->assertEquals( true, $status->isOK(),
249 "Store from $source to $dest succeeded ($backendName)." );
250 $this->assertEquals( array( 0 => true ), $status->success,
251 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
252 $this->assertEquals( true, file_exists( $source ),
253 "Source file $source still exists ($backendName)." );
254 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
255 "Destination file $dest exists ($backendName)." );
256
257 $this->assertEquals( filesize( $source ),
258 $this->backend->getFileSize( array( 'src' => $dest ) ),
259 "Destination file $dest has correct size ($backendName)." );
260
261 $props1 = FSFile::getPropsFromPath( $source );
262 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
263 $this->assertEquals( $props1, $props2,
264 "Source and destination have the same props ($backendName)." );
265
266 $this->assertBackendPathsConsistent( array( $dest ) );
267 }
268
269 public static function provider_testStore() {
270 $cases = array();
271
272 $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
273 $toPath = self::baseStorePath() . '/unittest-cont1/e/fun/obj1.txt';
274 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
275 $cases[] = array(
276 $op, // operation
277 $tmpName, // source
278 $toPath, // dest
279 );
280
281 $op2 = $op;
282 $op2['overwrite'] = true;
283 $cases[] = array(
284 $op2, // operation
285 $tmpName, // source
286 $toPath, // dest
287 );
288
289 $op2 = $op;
290 $op2['overwriteSame'] = true;
291 $cases[] = array(
292 $op2, // operation
293 $tmpName, // source
294 $toPath, // dest
295 );
296
297 return $cases;
298 }
299
300 /**
301 * @dataProvider provider_testCopy
302 * @covers FileBackend::doOperation
303 */
304 public function testCopy( $op ) {
305 $this->backend = $this->singleBackend;
306 $this->tearDownFiles();
307 $this->doTestCopy( $op );
308 $this->tearDownFiles();
309
310 $this->backend = $this->multiBackend;
311 $this->tearDownFiles();
312 $this->doTestCopy( $op );
313 $this->tearDownFiles();
314 }
315
316 private function doTestCopy( $op ) {
317 $backendName = $this->backendClass();
318
319 $source = $op['src'];
320 $dest = $op['dst'];
321 $this->prepare( array( 'dir' => dirname( $source ) ) );
322 $this->prepare( array( 'dir' => dirname( $dest ) ) );
323
324 if ( isset( $op['ignoreMissingSource'] ) ) {
325 $status = $this->backend->doOperation( $op );
326 $this->assertGoodStatus( $status,
327 "Move from $source to $dest succeeded without warnings ($backendName)." );
328 $this->assertEquals( array( 0 => true ), $status->success,
329 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
330 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
331 "Source file $source does not exist ($backendName)." );
332 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $dest ) ),
333 "Destination file $dest does not exist ($backendName)." );
334
335 return; // done
336 }
337
338 $status = $this->backend->doOperation(
339 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
340 $this->assertGoodStatus( $status,
341 "Creation of file at $source succeeded ($backendName)." );
342
343 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
344 $this->backend->copy( $op );
345 }
346
347 $status = $this->backend->doOperation( $op );
348
349 $this->assertGoodStatus( $status,
350 "Copy from $source to $dest succeeded without warnings ($backendName)." );
351 $this->assertEquals( true, $status->isOK(),
352 "Copy from $source to $dest succeeded ($backendName)." );
353 $this->assertEquals( array( 0 => true ), $status->success,
354 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
355 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
356 "Source file $source still exists ($backendName)." );
357 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
358 "Destination file $dest exists after copy ($backendName)." );
359
360 $this->assertEquals(
361 $this->backend->getFileSize( array( 'src' => $source ) ),
362 $this->backend->getFileSize( array( 'src' => $dest ) ),
363 "Destination file $dest has correct size ($backendName)." );
364
365 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
366 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
367 $this->assertEquals( $props1, $props2,
368 "Source and destination have the same props ($backendName)." );
369
370 $this->assertBackendPathsConsistent( array( $source, $dest ) );
371 }
372
373 public static function provider_testCopy() {
374 $cases = array();
375
376 $source = self::baseStorePath() . '/unittest-cont1/e/file.txt';
377 $dest = self::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
378
379 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
380 $cases[] = array(
381 $op, // operation
382 $source, // source
383 $dest, // dest
384 );
385
386 $op2 = $op;
387 $op2['overwrite'] = true;
388 $cases[] = array(
389 $op2, // operation
390 $source, // source
391 $dest, // dest
392 );
393
394 $op2 = $op;
395 $op2['overwriteSame'] = true;
396 $cases[] = array(
397 $op2, // operation
398 $source, // source
399 $dest, // dest
400 );
401
402 $op2 = $op;
403 $op2['ignoreMissingSource'] = true;
404 $cases[] = array(
405 $op2, // operation
406 $source, // source
407 $dest, // dest
408 );
409
410 $op2 = $op;
411 $op2['ignoreMissingSource'] = true;
412 $cases[] = array(
413 $op2, // operation
414 self::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
415 $dest, // dest
416 );
417
418 return $cases;
419 }
420
421 /**
422 * @dataProvider provider_testMove
423 * @covers FileBackend::doOperation
424 */
425 public function testMove( $op ) {
426 $this->backend = $this->singleBackend;
427 $this->tearDownFiles();
428 $this->doTestMove( $op );
429 $this->tearDownFiles();
430
431 $this->backend = $this->multiBackend;
432 $this->tearDownFiles();
433 $this->doTestMove( $op );
434 $this->tearDownFiles();
435 }
436
437 private function doTestMove( $op ) {
438 $backendName = $this->backendClass();
439
440 $source = $op['src'];
441 $dest = $op['dst'];
442 $this->prepare( array( 'dir' => dirname( $source ) ) );
443 $this->prepare( array( 'dir' => dirname( $dest ) ) );
444
445 if ( isset( $op['ignoreMissingSource'] ) ) {
446 $status = $this->backend->doOperation( $op );
447 $this->assertGoodStatus( $status,
448 "Move from $source to $dest succeeded without warnings ($backendName)." );
449 $this->assertEquals( array( 0 => true ), $status->success,
450 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
451 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
452 "Source file $source does not exist ($backendName)." );
453 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $dest ) ),
454 "Destination file $dest does not exist ($backendName)." );
455
456 return; // done
457 }
458
459 $status = $this->backend->doOperation(
460 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
461 $this->assertGoodStatus( $status,
462 "Creation of file at $source succeeded ($backendName)." );
463
464 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
465 $this->backend->copy( $op );
466 }
467
468 $status = $this->backend->doOperation( $op );
469 $this->assertGoodStatus( $status,
470 "Move from $source to $dest succeeded without warnings ($backendName)." );
471 $this->assertEquals( true, $status->isOK(),
472 "Move from $source to $dest succeeded ($backendName)." );
473 $this->assertEquals( array( 0 => true ), $status->success,
474 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
475 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
476 "Source file $source does not still exists ($backendName)." );
477 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
478 "Destination file $dest exists after move ($backendName)." );
479
480 $this->assertNotEquals(
481 $this->backend->getFileSize( array( 'src' => $source ) ),
482 $this->backend->getFileSize( array( 'src' => $dest ) ),
483 "Destination file $dest has correct size ($backendName)." );
484
485 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
486 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
487 $this->assertEquals( false, $props1['fileExists'],
488 "Source file does not exist accourding to props ($backendName)." );
489 $this->assertEquals( true, $props2['fileExists'],
490 "Destination file exists accourding to props ($backendName)." );
491
492 $this->assertBackendPathsConsistent( array( $source, $dest ) );
493 }
494
495 public static function provider_testMove() {
496 $cases = array();
497
498 $source = self::baseStorePath() . '/unittest-cont1/e/file.txt';
499 $dest = self::baseStorePath() . '/unittest-cont2/a/fileMoved.txt';
500
501 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
502 $cases[] = array(
503 $op, // operation
504 $source, // source
505 $dest, // dest
506 );
507
508 $op2 = $op;
509 $op2['overwrite'] = true;
510 $cases[] = array(
511 $op2, // operation
512 $source, // source
513 $dest, // dest
514 );
515
516 $op2 = $op;
517 $op2['overwriteSame'] = true;
518 $cases[] = array(
519 $op2, // operation
520 $source, // source
521 $dest, // dest
522 );
523
524 $op2 = $op;
525 $op2['ignoreMissingSource'] = true;
526 $cases[] = array(
527 $op2, // operation
528 $source, // source
529 $dest, // dest
530 );
531
532 $op2 = $op;
533 $op2['ignoreMissingSource'] = true;
534 $cases[] = array(
535 $op2, // operation
536 self::baseStorePath() . '/unittest-cont-bad/e/file.txt', // source
537 $dest, // dest
538 );
539
540 return $cases;
541 }
542
543 /**
544 * @dataProvider provider_testDelete
545 * @covers FileBackend::doOperation
546 */
547 public function testDelete( $op, $withSource, $okStatus ) {
548 $this->backend = $this->singleBackend;
549 $this->tearDownFiles();
550 $this->doTestDelete( $op, $withSource, $okStatus );
551 $this->tearDownFiles();
552
553 $this->backend = $this->multiBackend;
554 $this->tearDownFiles();
555 $this->doTestDelete( $op, $withSource, $okStatus );
556 $this->tearDownFiles();
557 }
558
559 private function doTestDelete( $op, $withSource, $okStatus ) {
560 $backendName = $this->backendClass();
561
562 $source = $op['src'];
563 $this->prepare( array( 'dir' => dirname( $source ) ) );
564
565 if ( $withSource ) {
566 $status = $this->backend->doOperation(
567 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
568 $this->assertGoodStatus( $status,
569 "Creation of file at $source succeeded ($backendName)." );
570 }
571
572 $status = $this->backend->doOperation( $op );
573 if ( $okStatus ) {
574 $this->assertGoodStatus( $status,
575 "Deletion of file at $source succeeded without warnings ($backendName)." );
576 $this->assertEquals( true, $status->isOK(),
577 "Deletion of file at $source succeeded ($backendName)." );
578 $this->assertEquals( array( 0 => true ), $status->success,
579 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
580 } else {
581 $this->assertEquals( false, $status->isOK(),
582 "Deletion of file at $source failed ($backendName)." );
583 }
584
585 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
586 "Source file $source does not exist after move ($backendName)." );
587
588 $this->assertFalse(
589 $this->backend->getFileSize( array( 'src' => $source ) ),
590 "Source file $source has correct size (false) ($backendName)." );
591
592 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
593 $this->assertFalse( $props1['fileExists'],
594 "Source file $source does not exist according to props ($backendName)." );
595
596 $this->assertBackendPathsConsistent( array( $source ) );
597 }
598
599 public static function provider_testDelete() {
600 $cases = array();
601
602 $source = self::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
603
604 $op = array( 'op' => 'delete', 'src' => $source );
605 $cases[] = array(
606 $op, // operation
607 true, // with source
608 true // succeeds
609 );
610
611 $cases[] = array(
612 $op, // operation
613 false, // without source
614 false // fails
615 );
616
617 $op['ignoreMissingSource'] = true;
618 $cases[] = array(
619 $op, // operation
620 false, // without source
621 true // succeeds
622 );
623
624 $op['ignoreMissingSource'] = true;
625 $op['src'] = self::baseStorePath() . '/unittest-cont-bad/e/file.txt';
626 $cases[] = array(
627 $op, // operation
628 false, // without source
629 true // succeeds
630 );
631
632 return $cases;
633 }
634
635 /**
636 * @dataProvider provider_testDescribe
637 * @covers FileBackend::doOperation
638 */
639 public function testDescribe( $op, $withSource, $okStatus ) {
640 $this->backend = $this->singleBackend;
641 $this->tearDownFiles();
642 $this->doTestDescribe( $op, $withSource, $okStatus );
643 $this->tearDownFiles();
644
645 $this->backend = $this->multiBackend;
646 $this->tearDownFiles();
647 $this->doTestDescribe( $op, $withSource, $okStatus );
648 $this->tearDownFiles();
649 }
650
651 private function doTestDescribe( $op, $withSource, $okStatus ) {
652 $backendName = $this->backendClass();
653
654 $source = $op['src'];
655 $this->prepare( array( 'dir' => dirname( $source ) ) );
656
657 if ( $withSource ) {
658 $status = $this->backend->doOperation(
659 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
660 $this->assertGoodStatus( $status,
661 "Creation of file at $source succeeded ($backendName)." );
662 }
663
664 $status = $this->backend->doOperation( $op );
665 if ( $okStatus ) {
666 $this->assertGoodStatus( $status,
667 "Describe of file at $source succeeded without warnings ($backendName)." );
668 $this->assertEquals( true, $status->isOK(),
669 "Describe of file at $source succeeded ($backendName)." );
670 $this->assertEquals( array( 0 => true ), $status->success,
671 "Describe of file at $source has proper 'success' field in Status ($backendName)." );
672 } else {
673 $this->assertEquals( false, $status->isOK(),
674 "Describe of file at $source failed ($backendName)." );
675 }
676
677 $this->assertBackendPathsConsistent( array( $source ) );
678 }
679
680 public static function provider_testDescribe() {
681 $cases = array();
682
683 $source = self::baseStorePath() . '/unittest-cont1/e/myfacefile.txt';
684
685 $op = array( 'op' => 'describe', 'src' => $source,
686 'headers' => array( 'X-Content-Length' => '91.3', 'Content-Old-Header' => '' ),
687 'disposition' => 'inline' );
688 $cases[] = array(
689 $op, // operation
690 true, // with source
691 true // succeeds
692 );
693
694 $cases[] = array(
695 $op, // operation
696 false, // without source
697 false // fails
698 );
699
700 return $cases;
701 }
702
703 /**
704 * @dataProvider provider_testCreate
705 * @covers FileBackend::doOperation
706 */
707 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
708 $this->backend = $this->singleBackend;
709 $this->tearDownFiles();
710 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
711 $this->tearDownFiles();
712
713 $this->backend = $this->multiBackend;
714 $this->tearDownFiles();
715 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
716 $this->tearDownFiles();
717 }
718
719 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
720 $backendName = $this->backendClass();
721
722 $dest = $op['dst'];
723 $this->prepare( array( 'dir' => dirname( $dest ) ) );
724
725 $oldText = 'blah...blah...waahwaah';
726 if ( $alreadyExists ) {
727 $status = $this->backend->doOperation(
728 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
729 $this->assertGoodStatus( $status,
730 "Creation of file at $dest succeeded ($backendName)." );
731 }
732
733 $status = $this->backend->doOperation( $op );
734 if ( $okStatus ) {
735 $this->assertGoodStatus( $status,
736 "Creation of file at $dest succeeded without warnings ($backendName)." );
737 $this->assertEquals( true, $status->isOK(),
738 "Creation of file at $dest succeeded ($backendName)." );
739 $this->assertEquals( array( 0 => true ), $status->success,
740 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
741 } else {
742 $this->assertEquals( false, $status->isOK(),
743 "Creation of file at $dest failed ($backendName)." );
744 }
745
746 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
747 "Destination file $dest exists after creation ($backendName)." );
748
749 $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
750 $this->assertEquals( true, $props1['fileExists'],
751 "Destination file $dest exists according to props ($backendName)." );
752 if ( $okStatus ) { // file content is what we saved
753 $this->assertEquals( $newSize, $props1['size'],
754 "Destination file $dest has expected size according to props ($backendName)." );
755 $this->assertEquals( $newSize,
756 $this->backend->getFileSize( array( 'src' => $dest ) ),
757 "Destination file $dest has correct size ($backendName)." );
758 } else { // file content is some other previous text
759 $this->assertEquals( strlen( $oldText ), $props1['size'],
760 "Destination file $dest has original size according to props ($backendName)." );
761 $this->assertEquals( strlen( $oldText ),
762 $this->backend->getFileSize( array( 'src' => $dest ) ),
763 "Destination file $dest has original size according to props ($backendName)." );
764 }
765
766 $this->assertBackendPathsConsistent( array( $dest ) );
767 }
768
769 /**
770 * @dataProvider provider_testCreate
771 */
772 public static function provider_testCreate() {
773 $cases = array();
774
775 $dest = self::baseStorePath() . '/unittest-cont2/a/myspacefile.txt';
776
777 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
778 $cases[] = array(
779 $op, // operation
780 false, // no dest already exists
781 true, // succeeds
782 strlen( $op['content'] )
783 );
784
785 $op2 = $op;
786 $op2['content'] = "\n";
787 $cases[] = array(
788 $op2, // operation
789 false, // no dest already exists
790 true, // succeeds
791 strlen( $op2['content'] )
792 );
793
794 $op2 = $op;
795 $op2['content'] = "fsf\n waf 3kt";
796 $cases[] = array(
797 $op2, // operation
798 true, // dest already exists
799 false, // fails
800 strlen( $op2['content'] )
801 );
802
803 $op2 = $op;
804 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
805 $op2['overwrite'] = true;
806 $cases[] = array(
807 $op2, // operation
808 true, // dest already exists
809 true, // succeeds
810 strlen( $op2['content'] )
811 );
812
813 $op2 = $op;
814 $op2['content'] = "39qjmg3-qg";
815 $op2['overwriteSame'] = true;
816 $cases[] = array(
817 $op2, // operation
818 true, // dest already exists
819 false, // succeeds
820 strlen( $op2['content'] )
821 );
822
823 return $cases;
824 }
825
826 /**
827 * @covers FileBackend::doQuickOperations
828 */
829 public function testDoQuickOperations() {
830 $this->backend = $this->singleBackend;
831 $this->doTestDoQuickOperations();
832 $this->tearDownFiles();
833
834 $this->backend = $this->multiBackend;
835 $this->doTestDoQuickOperations();
836 $this->tearDownFiles();
837 }
838
839 private function doTestDoQuickOperations() {
840 $backendName = $this->backendClass();
841
842 $base = self::baseStorePath();
843 $files = array(
844 "$base/unittest-cont1/e/fileA.a",
845 "$base/unittest-cont1/e/fileB.a",
846 "$base/unittest-cont1/e/fileC.a"
847 );
848 $createOps = array();
849 $purgeOps = array();
850 foreach ( $files as $path ) {
851 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
852 $this->assertGoodStatus( $status,
853 "Preparing $path succeeded without warnings ($backendName)." );
854 $createOps[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand( 0, 50000 ) );
855 $copyOps[] = array( 'op' => 'copy', 'src' => $path, 'dst' => "$path-2" );
856 $moveOps[] = array( 'op' => 'move', 'src' => "$path-2", 'dst' => "$path-3" );
857 $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
858 $purgeOps[] = array( 'op' => 'delete', 'src' => "$path-3" );
859 }
860 $purgeOps[] = array( 'op' => 'null' );
861
862 $this->assertGoodStatus(
863 $this->backend->doQuickOperations( $createOps ),
864 "Creation of source files succeeded ($backendName)." );
865 foreach ( $files as $file ) {
866 $this->assertTrue( $this->backend->fileExists( array( 'src' => $file ) ),
867 "File $file exists." );
868 }
869
870 $this->assertGoodStatus(
871 $this->backend->doQuickOperations( $copyOps ),
872 "Quick copy of source files succeeded ($backendName)." );
873 foreach ( $files as $file ) {
874 $this->assertTrue( $this->backend->fileExists( array( 'src' => "$file-2" ) ),
875 "File $file-2 exists." );
876 }
877
878 $this->assertGoodStatus(
879 $this->backend->doQuickOperations( $moveOps ),
880 "Quick move of source files succeeded ($backendName)." );
881 foreach ( $files as $file ) {
882 $this->assertTrue( $this->backend->fileExists( array( 'src' => "$file-3" ) ),
883 "File $file-3 move in." );
884 $this->assertFalse( $this->backend->fileExists( array( 'src' => "$file-2" ) ),
885 "File $file-2 moved away." );
886 }
887
888 $this->assertGoodStatus(
889 $this->backend->quickCopy( array( 'src' => $files[0], 'dst' => $files[0] ) ),
890 "Copy of file {$files[0]} over itself succeeded ($backendName)." );
891 $this->assertTrue( $this->backend->fileExists( array( 'src' => $files[0] ) ),
892 "File {$files[0]} still exists." );
893
894 $this->assertGoodStatus(
895 $this->backend->quickMove( array( 'src' => $files[0], 'dst' => $files[0] ) ),
896 "Move of file {$files[0]} over itself succeeded ($backendName)." );
897 $this->assertTrue( $this->backend->fileExists( array( 'src' => $files[0] ) ),
898 "File {$files[0]} still exists." );
899
900 $this->assertGoodStatus(
901 $this->backend->doQuickOperations( $purgeOps ),
902 "Quick deletion of source files succeeded ($backendName)." );
903 foreach ( $files as $file ) {
904 $this->assertFalse( $this->backend->fileExists( array( 'src' => $file ) ),
905 "File $file purged." );
906 $this->assertFalse( $this->backend->fileExists( array( 'src' => "$file-3" ) ),
907 "File $file-3 purged." );
908 }
909 }
910
911 /**
912 * @dataProvider provider_testConcatenate
913 */
914 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
915 $this->filesToPrune[] = $op['dst'];
916
917 $this->backend = $this->singleBackend;
918 $this->tearDownFiles();
919 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
920 $this->filesToPrune[] = $op['dst']; # avoid file leaking
921 $this->tearDownFiles();
922
923 $this->backend = $this->multiBackend;
924 $this->tearDownFiles();
925 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
926 $this->filesToPrune[] = $op['dst']; # avoid file leaking
927 $this->tearDownFiles();
928 }
929
930 private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
931 $backendName = $this->backendClass();
932
933 $expContent = '';
934 // Create sources
935 $ops = array();
936 foreach ( $srcs as $i => $source ) {
937 $this->prepare( array( 'dir' => dirname( $source ) ) );
938 $ops[] = array(
939 'op' => 'create', // operation
940 'dst' => $source, // source
941 'content' => $srcsContent[$i]
942 );
943 $expContent .= $srcsContent[$i];
944 }
945 $status = $this->backend->doOperations( $ops );
946
947 $this->assertGoodStatus( $status,
948 "Creation of source files succeeded ($backendName)." );
949
950 $dest = $params['dst'];
951 if ( $alreadyExists ) {
952 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
953 $this->assertEquals( true, $ok,
954 "Creation of file at $dest succeeded ($backendName)." );
955 } else {
956 $ok = file_put_contents( $dest, '' ) !== false;
957 $this->assertEquals( true, $ok,
958 "Creation of 0-byte file at $dest succeeded ($backendName)." );
959 }
960
961 // Combine the files into one
962 $status = $this->backend->concatenate( $params );
963 if ( $okStatus ) {
964 $this->assertGoodStatus( $status,
965 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
966 $this->assertEquals( true, $status->isOK(),
967 "Creation of concat file at $dest succeeded ($backendName)." );
968 } else {
969 $this->assertEquals( false, $status->isOK(),
970 "Creation of concat file at $dest failed ($backendName)." );
971 }
972
973 if ( $okStatus ) {
974 $this->assertEquals( true, is_file( $dest ),
975 "Dest concat file $dest exists after creation ($backendName)." );
976 } else {
977 $this->assertEquals( true, is_file( $dest ),
978 "Dest concat file $dest exists after failed creation ($backendName)." );
979 }
980
981 $contents = file_get_contents( $dest );
982 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
983
984 if ( $okStatus ) {
985 $this->assertEquals( $expContent, $contents,
986 "Concat file at $dest has correct contents ($backendName)." );
987 } else {
988 $this->assertNotEquals( $expContent, $contents,
989 "Concat file at $dest has correct contents ($backendName)." );
990 }
991 }
992
993 public static function provider_testConcatenate() {
994 $cases = array();
995
996 $rand = mt_rand( 0, 2000000000 ) . time();
997 $dest = wfTempDir() . "/randomfile!$rand.txt";
998 $srcs = array(
999 self::baseStorePath() . '/unittest-cont1/e/file1.txt',
1000 self::baseStorePath() . '/unittest-cont1/e/file2.txt',
1001 self::baseStorePath() . '/unittest-cont1/e/file3.txt',
1002 self::baseStorePath() . '/unittest-cont1/e/file4.txt',
1003 self::baseStorePath() . '/unittest-cont1/e/file5.txt',
1004 self::baseStorePath() . '/unittest-cont1/e/file6.txt',
1005 self::baseStorePath() . '/unittest-cont1/e/file7.txt',
1006 self::baseStorePath() . '/unittest-cont1/e/file8.txt',
1007 self::baseStorePath() . '/unittest-cont1/e/file9.txt',
1008 self::baseStorePath() . '/unittest-cont1/e/file10.txt'
1009 );
1010 $content = array(
1011 'egfage',
1012 'ageageag',
1013 'rhokohlr',
1014 'shgmslkg',
1015 'kenga',
1016 'owagmal',
1017 'kgmae',
1018 'g eak;g',
1019 'lkaem;a',
1020 'legma'
1021 );
1022 $params = array( 'srcs' => $srcs, 'dst' => $dest );
1023
1024 $cases[] = array(
1025 $params, // operation
1026 $srcs, // sources
1027 $content, // content for each source
1028 false, // no dest already exists
1029 true, // succeeds
1030 );
1031
1032 $cases[] = array(
1033 $params, // operation
1034 $srcs, // sources
1035 $content, // content for each source
1036 true, // dest already exists
1037 false, // succeeds
1038 );
1039
1040 return $cases;
1041 }
1042
1043 /**
1044 * @dataProvider provider_testGetFileStat
1045 * @covers FileBackend::getFileStat
1046 */
1047 public function testGetFileStat( $path, $content, $alreadyExists ) {
1048 $this->backend = $this->singleBackend;
1049 $this->tearDownFiles();
1050 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1051 $this->tearDownFiles();
1052
1053 $this->backend = $this->multiBackend;
1054 $this->tearDownFiles();
1055 $this->doTestGetFileStat( $path, $content, $alreadyExists );
1056 $this->tearDownFiles();
1057 }
1058
1059 private function doTestGetFileStat( $path, $content, $alreadyExists ) {
1060 $backendName = $this->backendClass();
1061
1062 if ( $alreadyExists ) {
1063 $this->prepare( array( 'dir' => dirname( $path ) ) );
1064 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1065 $this->assertGoodStatus( $status,
1066 "Creation of file at $path succeeded ($backendName)." );
1067
1068 $size = $this->backend->getFileSize( array( 'src' => $path ) );
1069 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
1070 $stat = $this->backend->getFileStat( array( 'src' => $path ) );
1071
1072 $this->assertEquals( strlen( $content ), $size,
1073 "Correct file size of '$path'" );
1074 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
1075 "Correct file timestamp of '$path'" );
1076
1077 $size = $stat['size'];
1078 $time = $stat['mtime'];
1079 $this->assertEquals( strlen( $content ), $size,
1080 "Correct file size of '$path'" );
1081 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
1082 "Correct file timestamp of '$path'" );
1083
1084 $this->backend->clearCache( array( $path ) );
1085
1086 $size = $this->backend->getFileSize( array( 'src' => $path ) );
1087
1088 $this->assertEquals( strlen( $content ), $size,
1089 "Correct file size of '$path'" );
1090
1091 $this->backend->preloadCache( array( $path ) );
1092
1093 $size = $this->backend->getFileSize( array( 'src' => $path ) );
1094
1095 $this->assertEquals( strlen( $content ), $size,
1096 "Correct file size of '$path'" );
1097 } else {
1098 $size = $this->backend->getFileSize( array( 'src' => $path ) );
1099 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
1100 $stat = $this->backend->getFileStat( array( 'src' => $path ) );
1101
1102 $this->assertFalse( $size, "Correct file size of '$path'" );
1103 $this->assertFalse( $time, "Correct file timestamp of '$path'" );
1104 $this->assertFalse( $stat, "Correct file stat of '$path'" );
1105 }
1106 }
1107
1108 public static function provider_testGetFileStat() {
1109 $cases = array();
1110
1111 $base = self::baseStorePath();
1112 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents", true );
1113 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "", true );
1114 $cases[] = array( "$base/unittest-cont1/e/b/some-diff_file.txt", null, false );
1115
1116 return $cases;
1117 }
1118
1119 /**
1120 * @dataProvider provider_testGetFileStat
1121 * @covers FileBackend::streamFile
1122 */
1123 public function testStreamFile( $path, $content, $alreadyExists ) {
1124 $this->backend = $this->singleBackend;
1125 $this->tearDownFiles();
1126 $this->doTestStreamFile( $path, $content, $alreadyExists );
1127 $this->tearDownFiles();
1128 }
1129
1130 private function doTestStreamFile( $path, $content ) {
1131 $backendName = $this->backendClass();
1132
1133 // Test doStreamFile() directly to avoid header madness
1134 $class = new ReflectionClass( $this->backend );
1135 $method = $class->getMethod( 'doStreamFile' );
1136 $method->setAccessible( true );
1137
1138 if ( $content !== null ) {
1139 $this->prepare( array( 'dir' => dirname( $path ) ) );
1140 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
1141 $this->assertGoodStatus( $status,
1142 "Creation of file at $path succeeded ($backendName)." );
1143
1144 ob_start();
1145 $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
1146 $data = ob_get_contents();
1147 ob_end_clean();
1148
1149 $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
1150 } else { // 404 case
1151 ob_start();
1152 $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
1153 $data = ob_get_contents();
1154 ob_end_clean();
1155
1156 $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
1157 }
1158 }
1159
1160 public static function provider_testStreamFile() {
1161 $cases = array();
1162
1163 $base = self::baseStorePath();
1164 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
1165 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
1166
1167 return $cases;
1168 }
1169
1170 /**
1171 * @dataProvider provider_testGetFileContents
1172 * @covers FileBackend::getFileContents
1173 * @covers FileBackend::getFileContentsMulti
1174 */
1175 public function testGetFileContents( $source, $content ) {
1176 $this->backend = $this->singleBackend;
1177 $this->tearDownFiles();
1178 $this->doTestGetFileContents( $source, $content );
1179 $this->tearDownFiles();
1180
1181 $this->backend = $this->multiBackend;
1182 $this->tearDownFiles();
1183 $this->doTestGetFileContents( $source, $content );
1184 $this->tearDownFiles();
1185 }
1186
1187 private function doTestGetFileContents( $source, $content ) {
1188 $backendName = $this->backendClass();
1189
1190 $srcs = (array)$source;
1191 $content = (array)$content;
1192 foreach ( $srcs as $i => $src ) {
1193 $this->prepare( array( 'dir' => dirname( $src ) ) );
1194 $status = $this->backend->doOperation(
1195 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1196 $this->assertGoodStatus( $status,
1197 "Creation of file at $src succeeded ($backendName)." );
1198 }
1199
1200 if ( is_array( $source ) ) {
1201 $contents = $this->backend->getFileContentsMulti( array( 'srcs' => $source ) );
1202 foreach ( $contents as $path => $data ) {
1203 $this->assertNotEquals( false, $data, "Contents of $path exists ($backendName)." );
1204 $this->assertEquals( current( $content ), $data, "Contents of $path is correct ($backendName)." );
1205 next( $content );
1206 }
1207 $this->assertEquals( $source, array_keys( $contents ), "Contents in right order ($backendName)." );
1208 $this->assertEquals( count( $source ), count( $contents ), "Contents array size correct ($backendName)." );
1209 } else {
1210 $data = $this->backend->getFileContents( array( 'src' => $source ) );
1211 $this->assertNotEquals( false, $data, "Contents of $source exists ($backendName)." );
1212 $this->assertEquals( $content[0], $data, "Contents of $source is correct ($backendName)." );
1213 }
1214 }
1215
1216 public static function provider_testGetFileContents() {
1217 $cases = array();
1218
1219 $base = self::baseStorePath();
1220 $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
1221 $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", "more file contents" );
1222 $cases[] = array(
1223 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1224 "$base/unittest-cont1/e/a/z.txt" ),
1225 array( "contents xx", "contents xy", "contents xz" )
1226 );
1227
1228 return $cases;
1229 }
1230
1231 /**
1232 * @dataProvider provider_testGetLocalCopy
1233 * @covers FileBackend::getLocalCopy
1234 */
1235 public function testGetLocalCopy( $source, $content ) {
1236 $this->backend = $this->singleBackend;
1237 $this->tearDownFiles();
1238 $this->doTestGetLocalCopy( $source, $content );
1239 $this->tearDownFiles();
1240
1241 $this->backend = $this->multiBackend;
1242 $this->tearDownFiles();
1243 $this->doTestGetLocalCopy( $source, $content );
1244 $this->tearDownFiles();
1245 }
1246
1247 private function doTestGetLocalCopy( $source, $content ) {
1248 $backendName = $this->backendClass();
1249
1250 $srcs = (array)$source;
1251 $content = (array)$content;
1252 foreach ( $srcs as $i => $src ) {
1253 $this->prepare( array( 'dir' => dirname( $src ) ) );
1254 $status = $this->backend->doOperation(
1255 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1256 $this->assertGoodStatus( $status,
1257 "Creation of file at $src succeeded ($backendName)." );
1258 }
1259
1260 if ( is_array( $source ) ) {
1261 $tmpFiles = $this->backend->getLocalCopyMulti( array( 'srcs' => $source ) );
1262 foreach ( $tmpFiles as $path => $tmpFile ) {
1263 $this->assertNotNull( $tmpFile,
1264 "Creation of local copy of $path succeeded ($backendName)." );
1265 $contents = file_get_contents( $tmpFile->getPath() );
1266 $this->assertNotEquals( false, $contents, "Local copy of $path exists ($backendName)." );
1267 $this->assertEquals( current( $content ), $contents, "Local copy of $path is correct ($backendName)." );
1268 next( $content );
1269 }
1270 $this->assertEquals( $source, array_keys( $tmpFiles ), "Local copies in right order ($backendName)." );
1271 $this->assertEquals( count( $source ), count( $tmpFiles ), "Local copies array size correct ($backendName)." );
1272 } else {
1273 $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
1274 $this->assertNotNull( $tmpFile,
1275 "Creation of local copy of $source succeeded ($backendName)." );
1276 $contents = file_get_contents( $tmpFile->getPath() );
1277 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
1278 $this->assertEquals( $content[0], $contents, "Local copy of $source is correct ($backendName)." );
1279 }
1280
1281 $obj = new stdClass();
1282 $tmpFile->bind( $obj );
1283 }
1284
1285 public static function provider_testGetLocalCopy() {
1286 $cases = array();
1287
1288 $base = self::baseStorePath();
1289 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1290 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1291 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1292 $cases[] = array(
1293 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1294 "$base/unittest-cont1/e/a/z.txt" ),
1295 array( "contents xx", "contents xy", "contents xz" )
1296 );
1297
1298 return $cases;
1299 }
1300
1301 /**
1302 * @dataProvider provider_testGetLocalReference
1303 * @covers FileBackend::getLocalReference
1304 */
1305 public function testGetLocalReference( $source, $content ) {
1306 $this->backend = $this->singleBackend;
1307 $this->tearDownFiles();
1308 $this->doTestGetLocalReference( $source, $content );
1309 $this->tearDownFiles();
1310
1311 $this->backend = $this->multiBackend;
1312 $this->tearDownFiles();
1313 $this->doTestGetLocalReference( $source, $content );
1314 $this->tearDownFiles();
1315 }
1316
1317 private function doTestGetLocalReference( $source, $content ) {
1318 $backendName = $this->backendClass();
1319
1320 $srcs = (array)$source;
1321 $content = (array)$content;
1322 foreach ( $srcs as $i => $src ) {
1323 $this->prepare( array( 'dir' => dirname( $src ) ) );
1324 $status = $this->backend->doOperation(
1325 array( 'op' => 'create', 'content' => $content[$i], 'dst' => $src ) );
1326 $this->assertGoodStatus( $status,
1327 "Creation of file at $src succeeded ($backendName)." );
1328 }
1329
1330 if ( is_array( $source ) ) {
1331 $tmpFiles = $this->backend->getLocalReferenceMulti( array( 'srcs' => $source ) );
1332 foreach ( $tmpFiles as $path => $tmpFile ) {
1333 $this->assertNotNull( $tmpFile,
1334 "Creation of local copy of $path succeeded ($backendName)." );
1335 $contents = file_get_contents( $tmpFile->getPath() );
1336 $this->assertNotEquals( false, $contents, "Local ref of $path exists ($backendName)." );
1337 $this->assertEquals( current( $content ), $contents, "Local ref of $path is correct ($backendName)." );
1338 next( $content );
1339 }
1340 $this->assertEquals( $source, array_keys( $tmpFiles ), "Local refs in right order ($backendName)." );
1341 $this->assertEquals( count( $source ), count( $tmpFiles ), "Local refs array size correct ($backendName)." );
1342 } else {
1343 $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
1344 $this->assertNotNull( $tmpFile,
1345 "Creation of local copy of $source succeeded ($backendName)." );
1346 $contents = file_get_contents( $tmpFile->getPath() );
1347 $this->assertNotEquals( false, $contents, "Local ref of $source exists ($backendName)." );
1348 $this->assertEquals( $content[0], $contents, "Local ref of $source is correct ($backendName)." );
1349 }
1350 }
1351
1352 public static function provider_testGetLocalReference() {
1353 $cases = array();
1354
1355 $base = self::baseStorePath();
1356 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1357 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1358 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1359 $cases[] = array(
1360 array( "$base/unittest-cont1/e/a/x.txt", "$base/unittest-cont1/e/a/y.txt",
1361 "$base/unittest-cont1/e/a/z.txt" ),
1362 array( "contents xx", "contents xy", "contents xz" )
1363 );
1364
1365 return $cases;
1366 }
1367
1368 /**
1369 * @covers FileBackend::getLocalCopy
1370 * @covers FileBackend::getLocalReference
1371 */
1372 public function testGetLocalCopyAndReference404() {
1373 $this->backend = $this->singleBackend;
1374 $this->tearDownFiles();
1375 $this->doTestGetLocalCopyAndReference404();
1376 $this->tearDownFiles();
1377
1378 $this->backend = $this->multiBackend;
1379 $this->tearDownFiles();
1380 $this->doTestGetLocalCopyAndReference404();
1381 $this->tearDownFiles();
1382 }
1383
1384 public function doTestGetLocalCopyAndReference404() {
1385 $backendName = $this->backendClass();
1386
1387 $base = self::baseStorePath();
1388
1389 $tmpFile = $this->backend->getLocalCopy( array(
1390 'src' => "$base/unittest-cont1/not-there" ) );
1391 $this->assertEquals( null, $tmpFile, "Local copy of not existing file is null ($backendName)." );
1392
1393 $tmpFile = $this->backend->getLocalReference( array(
1394 'src' => "$base/unittest-cont1/not-there" ) );
1395 $this->assertEquals( null, $tmpFile, "Local ref of not existing file is null ($backendName)." );
1396 }
1397
1398 /**
1399 * @dataProvider provider_testGetFileHttpUrl
1400 * @covers FileBackend::getFileHttpUrl
1401 */
1402 public function testGetFileHttpUrl( $source, $content ) {
1403 $this->backend = $this->singleBackend;
1404 $this->tearDownFiles();
1405 $this->doTestGetFileHttpUrl( $source, $content );
1406 $this->tearDownFiles();
1407
1408 $this->backend = $this->multiBackend;
1409 $this->tearDownFiles();
1410 $this->doTestGetFileHttpUrl( $source, $content );
1411 $this->tearDownFiles();
1412 }
1413
1414 private function doTestGetFileHttpUrl( $source, $content ) {
1415 $backendName = $this->backendClass();
1416
1417 $this->prepare( array( 'dir' => dirname( $source ) ) );
1418 $status = $this->backend->doOperation(
1419 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
1420 $this->assertGoodStatus( $status,
1421 "Creation of file at $source succeeded ($backendName)." );
1422
1423 $url = $this->backend->getFileHttpUrl( array( 'src' => $source ) );
1424
1425 if ( $url !== null ) { // supported
1426 $data = Http::request( "GET", $url );
1427 $this->assertEquals( $content, $data,
1428 "HTTP GET of URL has right contents ($backendName)." );
1429 }
1430 }
1431
1432 public static function provider_testGetFileHttpUrl() {
1433 $cases = array();
1434
1435 $base = self::baseStorePath();
1436 $cases[] = array( "$base/unittest-cont1/e/a/z/some_file.txt", "some file contents" );
1437 $cases[] = array( "$base/unittest-cont1/e/a/some-other_file.txt", "more file contents" );
1438 $cases[] = array( "$base/unittest-cont1/e/a/\$odd&.txt", "test file contents" );
1439
1440 return $cases;
1441 }
1442
1443 /**
1444 * @dataProvider provider_testPrepareAndClean
1445 * @covers FileBackend::prepare
1446 * @covers FileBackend::clean
1447 */
1448 public function testPrepareAndClean( $path, $isOK ) {
1449 $this->backend = $this->singleBackend;
1450 $this->doTestPrepareAndClean( $path, $isOK );
1451 $this->tearDownFiles();
1452
1453 $this->backend = $this->multiBackend;
1454 $this->doTestPrepareAndClean( $path, $isOK );
1455 $this->tearDownFiles();
1456 }
1457
1458 public static function provider_testPrepareAndClean() {
1459 $base = self::baseStorePath();
1460
1461 return array(
1462 array( "$base/unittest-cont1/e/a/z/some_file1.txt", true ),
1463 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
1464 # Specific to FS backend with no basePath field set
1465 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
1466 );
1467 }
1468
1469 private function doTestPrepareAndClean( $path, $isOK ) {
1470 $backendName = $this->backendClass();
1471
1472 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
1473 if ( $isOK ) {
1474 $this->assertGoodStatus( $status,
1475 "Preparing dir $path succeeded without warnings ($backendName)." );
1476 $this->assertEquals( true, $status->isOK(),
1477 "Preparing dir $path succeeded ($backendName)." );
1478 } else {
1479 $this->assertEquals( false, $status->isOK(),
1480 "Preparing dir $path failed ($backendName)." );
1481 }
1482
1483 $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
1484 if ( $isOK ) {
1485 $this->assertGoodStatus( $status,
1486 "Cleaning dir $path succeeded without warnings ($backendName)." );
1487 $this->assertEquals( true, $status->isOK(),
1488 "Cleaning dir $path succeeded ($backendName)." );
1489 } else {
1490 $this->assertEquals( false, $status->isOK(),
1491 "Cleaning dir $path failed ($backendName)." );
1492 }
1493 }
1494
1495 public function testRecursiveClean() {
1496 $this->backend = $this->singleBackend;
1497 $this->doTestRecursiveClean();
1498 $this->tearDownFiles();
1499
1500 $this->backend = $this->multiBackend;
1501 $this->doTestRecursiveClean();
1502 $this->tearDownFiles();
1503 }
1504
1505 /**
1506 * @covers FileBackend::clean
1507 */
1508 private function doTestRecursiveClean() {
1509 $backendName = $this->backendClass();
1510
1511 $base = self::baseStorePath();
1512 $dirs = array(
1513 "$base/unittest-cont1",
1514 "$base/unittest-cont1/e",
1515 "$base/unittest-cont1/e/a",
1516 "$base/unittest-cont1/e/a/b",
1517 "$base/unittest-cont1/e/a/b/c",
1518 "$base/unittest-cont1/e/a/b/c/d0",
1519 "$base/unittest-cont1/e/a/b/c/d1",
1520 "$base/unittest-cont1/e/a/b/c/d2",
1521 "$base/unittest-cont1/e/a/b/c/d0/1",
1522 "$base/unittest-cont1/e/a/b/c/d0/2",
1523 "$base/unittest-cont1/e/a/b/c/d1/3",
1524 "$base/unittest-cont1/e/a/b/c/d1/4",
1525 "$base/unittest-cont1/e/a/b/c/d2/5",
1526 "$base/unittest-cont1/e/a/b/c/d2/6"
1527 );
1528 foreach ( $dirs as $dir ) {
1529 $status = $this->prepare( array( 'dir' => $dir ) );
1530 $this->assertGoodStatus( $status,
1531 "Preparing dir $dir succeeded without warnings ($backendName)." );
1532 }
1533
1534 if ( $this->backend instanceof FSFileBackend ) {
1535 foreach ( $dirs as $dir ) {
1536 $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ),
1537 "Dir $dir exists ($backendName)." );
1538 }
1539 }
1540
1541 $status = $this->backend->clean(
1542 array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
1543 $this->assertGoodStatus( $status,
1544 "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
1545
1546 foreach ( $dirs as $dir ) {
1547 $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ),
1548 "Dir $dir no longer exists ($backendName)." );
1549 }
1550 }
1551
1552 // @todo testSecure
1553
1554 /**
1555 * @covers FileBackend::doOperations
1556 */
1557 public function testDoOperations() {
1558 $this->backend = $this->singleBackend;
1559 $this->tearDownFiles();
1560 $this->doTestDoOperations();
1561 $this->tearDownFiles();
1562
1563 $this->backend = $this->multiBackend;
1564 $this->tearDownFiles();
1565 $this->doTestDoOperations();
1566 $this->tearDownFiles();
1567 }
1568
1569 private function doTestDoOperations() {
1570 $base = self::baseStorePath();
1571
1572 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1573 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1574 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1575 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1576 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1577 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1578 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1579
1580 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1581 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1582 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1583 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1584 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1585 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1586 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1587
1588 $status = $this->backend->doOperations( array(
1589 array( 'op' => 'describe', 'src' => $fileA,
1590 'headers' => array( 'X-Content-Length' => '91.3' ), 'disposition' => 'inline' ),
1591 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1592 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1593 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1594 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1595 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1596 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1597 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1598 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1599 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1600 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1601 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1602 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1603 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1604 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1605 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1606 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1607 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1608 // Does nothing
1609 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1610 // Does nothing
1611 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1612 // Does nothing
1613 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1614 // Does nothing
1615 array( 'op' => 'null' ),
1616 // Does nothing
1617 ) );
1618
1619 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1620 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1621 $this->assertEquals( 14, count( $status->success ),
1622 "Operation batch has correct success array" );
1623
1624 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
1625 "File does not exist at $fileA" );
1626 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1627 "File does not exist at $fileB" );
1628 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1629 "File does not exist at $fileD" );
1630
1631 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1632 "File exists at $fileC" );
1633 $this->assertEquals( $fileBContents,
1634 $this->backend->getFileContents( array( 'src' => $fileC ) ),
1635 "Correct file contents of $fileC" );
1636 $this->assertEquals( strlen( $fileBContents ),
1637 $this->backend->getFileSize( array( 'src' => $fileC ) ),
1638 "Correct file size of $fileC" );
1639 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1640 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
1641 "Correct file SHA-1 of $fileC" );
1642 }
1643
1644 /**
1645 * @covers FileBackend::doOperations
1646 */
1647 public function testDoOperationsPipeline() {
1648 $this->backend = $this->singleBackend;
1649 $this->tearDownFiles();
1650 $this->doTestDoOperationsPipeline();
1651 $this->tearDownFiles();
1652
1653 $this->backend = $this->multiBackend;
1654 $this->tearDownFiles();
1655 $this->doTestDoOperationsPipeline();
1656 $this->tearDownFiles();
1657 }
1658
1659 // concurrency orientated
1660 private function doTestDoOperationsPipeline() {
1661 $base = self::baseStorePath();
1662
1663 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1664 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1665 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1666
1667 $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1668 file_put_contents( $tmpNameA, $fileAContents );
1669 $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1670 file_put_contents( $tmpNameB, $fileBContents );
1671 $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1672 file_put_contents( $tmpNameC, $fileCContents );
1673
1674 $this->filesToPrune[] = $tmpNameA; # avoid file leaking
1675 $this->filesToPrune[] = $tmpNameB; # avoid file leaking
1676 $this->filesToPrune[] = $tmpNameC; # avoid file leaking
1677
1678 $fileA = "$base/unittest-cont1/e/a/b/fileA.txt";
1679 $fileB = "$base/unittest-cont1/e/a/b/fileB.txt";
1680 $fileC = "$base/unittest-cont1/e/a/b/fileC.txt";
1681 $fileD = "$base/unittest-cont1/e/a/b/fileD.txt";
1682
1683 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1684 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1685 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1686 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1687 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1688
1689 $status = $this->backend->doOperations( array(
1690 array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
1691 array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
1692 array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
1693 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1694 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1695 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1696 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1697 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1698 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1699 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1700 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1701 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1702 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1703 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1704 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1705 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1706 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1707 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1708 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1709 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1710 // Does nothing
1711 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1712 // Does nothing
1713 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1714 // Does nothing
1715 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1716 // Does nothing
1717 array( 'op' => 'null' ),
1718 // Does nothing
1719 ) );
1720
1721 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1722 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1723 $this->assertEquals( 16, count( $status->success ),
1724 "Operation batch has correct success array" );
1725
1726 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
1727 "File does not exist at $fileA" );
1728 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1729 "File does not exist at $fileB" );
1730 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1731 "File does not exist at $fileD" );
1732
1733 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1734 "File exists at $fileC" );
1735 $this->assertEquals( $fileBContents,
1736 $this->backend->getFileContents( array( 'src' => $fileC ) ),
1737 "Correct file contents of $fileC" );
1738 $this->assertEquals( strlen( $fileBContents ),
1739 $this->backend->getFileSize( array( 'src' => $fileC ) ),
1740 "Correct file size of $fileC" );
1741 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1742 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
1743 "Correct file SHA-1 of $fileC" );
1744 }
1745
1746 /**
1747 * @covers FileBackend::doOperations
1748 */
1749 public function testDoOperationsFailing() {
1750 $this->backend = $this->singleBackend;
1751 $this->tearDownFiles();
1752 $this->doTestDoOperationsFailing();
1753 $this->tearDownFiles();
1754
1755 $this->backend = $this->multiBackend;
1756 $this->tearDownFiles();
1757 $this->doTestDoOperationsFailing();
1758 $this->tearDownFiles();
1759 }
1760
1761 private function doTestDoOperationsFailing() {
1762 $base = self::baseStorePath();
1763
1764 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
1765 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1766 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
1767 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1768 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
1769 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1770 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
1771
1772 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1773 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1774 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1775 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1776 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1777 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1778
1779 $status = $this->backend->doOperations( array(
1780 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1781 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1782 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1783 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1784 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
1785 // Now: A:<A>, B:<B>, C:<A>, D:<B>
1786 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
1787 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1788 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
1789 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1790 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
1791 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1792 array( 'op' => 'delete', 'src' => $fileD ),
1793 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1794 array( 'op' => 'null' ),
1795 // Does nothing
1796 ), array( 'force' => 1 ) );
1797
1798 $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
1799 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1800 $this->assertEquals( 8, count( $status->success ),
1801 "Operation batch has correct success array" );
1802
1803 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1804 "File does not exist at $fileB" );
1805 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1806 "File does not exist at $fileD" );
1807
1808 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
1809 "File does not exist at $fileA" );
1810 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1811 "File exists at $fileC" );
1812 $this->assertEquals( $fileBContents,
1813 $this->backend->getFileContents( array( 'src' => $fileA ) ),
1814 "Correct file contents of $fileA" );
1815 $this->assertEquals( strlen( $fileBContents ),
1816 $this->backend->getFileSize( array( 'src' => $fileA ) ),
1817 "Correct file size of $fileA" );
1818 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1819 $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
1820 "Correct file SHA-1 of $fileA" );
1821 }
1822
1823 /**
1824 * @covers FileBackend::getFileList
1825 */
1826 public function testGetFileList() {
1827 $this->backend = $this->singleBackend;
1828 $this->tearDownFiles();
1829 $this->doTestGetFileList();
1830 $this->tearDownFiles();
1831
1832 $this->backend = $this->multiBackend;
1833 $this->tearDownFiles();
1834 $this->doTestGetFileList();
1835 $this->tearDownFiles();
1836 }
1837
1838 private function doTestGetFileList() {
1839 $backendName = $this->backendClass();
1840 $base = self::baseStorePath();
1841
1842 // Should have no errors
1843 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
1844
1845 $files = array(
1846 "$base/unittest-cont1/e/test1.txt",
1847 "$base/unittest-cont1/e/test2.txt",
1848 "$base/unittest-cont1/e/test3.txt",
1849 "$base/unittest-cont1/e/subdir1/test1.txt",
1850 "$base/unittest-cont1/e/subdir1/test2.txt",
1851 "$base/unittest-cont1/e/subdir2/test3.txt",
1852 "$base/unittest-cont1/e/subdir2/test4.txt",
1853 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
1854 "$base/unittest-cont1/e/subdir2/subdir/test2.txt",
1855 "$base/unittest-cont1/e/subdir2/subdir/test3.txt",
1856 "$base/unittest-cont1/e/subdir2/subdir/test4.txt",
1857 "$base/unittest-cont1/e/subdir2/subdir/test5.txt",
1858 "$base/unittest-cont1/e/subdir2/subdir/sub/test0.txt",
1859 "$base/unittest-cont1/e/subdir2/subdir/sub/120-px-file.txt",
1860 );
1861
1862 // Add the files
1863 $ops = array();
1864 foreach ( $files as $file ) {
1865 $this->prepare( array( 'dir' => dirname( $file ) ) );
1866 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1867 }
1868 $status = $this->backend->doQuickOperations( $ops );
1869 $this->assertGoodStatus( $status,
1870 "Creation of files succeeded ($backendName)." );
1871 $this->assertEquals( true, $status->isOK(),
1872 "Creation of files succeeded with OK status ($backendName)." );
1873
1874 // Expected listing at root
1875 $expected = array(
1876 "e/test1.txt",
1877 "e/test2.txt",
1878 "e/test3.txt",
1879 "e/subdir1/test1.txt",
1880 "e/subdir1/test2.txt",
1881 "e/subdir2/test3.txt",
1882 "e/subdir2/test4.txt",
1883 "e/subdir2/subdir/test1.txt",
1884 "e/subdir2/subdir/test2.txt",
1885 "e/subdir2/subdir/test3.txt",
1886 "e/subdir2/subdir/test4.txt",
1887 "e/subdir2/subdir/test5.txt",
1888 "e/subdir2/subdir/sub/test0.txt",
1889 "e/subdir2/subdir/sub/120-px-file.txt",
1890 );
1891 sort( $expected );
1892
1893 // Actual listing (no trailing slash) at root
1894 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1895 $list = $this->listToArray( $iter );
1896 sort( $list );
1897 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1898
1899 // Actual listing (no trailing slash) at root with advise
1900 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1", 'adviseStat' => 1 ) );
1901 $list = $this->listToArray( $iter );
1902 sort( $list );
1903 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1904
1905 // Actual listing (with trailing slash) at root
1906 $list = array();
1907 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1908 foreach ( $iter as $file ) {
1909 $list[] = $file;
1910 }
1911 sort( $list );
1912 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1913
1914 // Expected listing at subdir
1915 $expected = array(
1916 "test1.txt",
1917 "test2.txt",
1918 "test3.txt",
1919 "test4.txt",
1920 "test5.txt",
1921 "sub/test0.txt",
1922 "sub/120-px-file.txt",
1923 );
1924 sort( $expected );
1925
1926 // Actual listing (no trailing slash) at subdir
1927 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
1928 $list = $this->listToArray( $iter );
1929 sort( $list );
1930 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1931
1932 // Actual listing (no trailing slash) at subdir with advise
1933 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir", 'adviseStat' => 1 ) );
1934 $list = $this->listToArray( $iter );
1935 sort( $list );
1936 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1937
1938 // Actual listing (with trailing slash) at subdir
1939 $list = array();
1940 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir/" ) );
1941 foreach ( $iter as $file ) {
1942 $list[] = $file;
1943 }
1944 sort( $list );
1945 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1946
1947 // Actual listing (using iterator second time)
1948 $list = $this->listToArray( $iter );
1949 sort( $list );
1950 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
1951
1952 // Actual listing (top files only) at root
1953 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1" ) );
1954 $list = $this->listToArray( $iter );
1955 sort( $list );
1956 $this->assertEquals( array(), $list, "Correct top file listing ($backendName)." );
1957
1958 // Expected listing (top files only) at subdir
1959 $expected = array(
1960 "test1.txt",
1961 "test2.txt",
1962 "test3.txt",
1963 "test4.txt",
1964 "test5.txt"
1965 );
1966 sort( $expected );
1967
1968 // Actual listing (top files only) at subdir
1969 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) );
1970 $list = $this->listToArray( $iter );
1971 sort( $list );
1972 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
1973
1974 // Actual listing (top files only) at subdir with advise
1975 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir", 'adviseStat' => 1 ) );
1976 $list = $this->listToArray( $iter );
1977 sort( $list );
1978 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
1979
1980 foreach ( $files as $file ) { // clean up
1981 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1982 }
1983
1984 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1985 foreach ( $iter as $iter ) {
1986 // no errors
1987 }
1988 }
1989
1990 /**
1991 * @covers FileBackend::getTopDirectoryList
1992 * @covers FileBackend::getDirectoryList
1993 */
1994 public function testGetDirectoryList() {
1995 $this->backend = $this->singleBackend;
1996 $this->tearDownFiles();
1997 $this->doTestGetDirectoryList();
1998 $this->tearDownFiles();
1999
2000 $this->backend = $this->multiBackend;
2001 $this->tearDownFiles();
2002 $this->doTestGetDirectoryList();
2003 $this->tearDownFiles();
2004 }
2005
2006 private function doTestGetDirectoryList() {
2007 $backendName = $this->backendClass();
2008
2009 $base = self::baseStorePath();
2010 $files = array(
2011 "$base/unittest-cont1/e/test1.txt",
2012 "$base/unittest-cont1/e/test2.txt",
2013 "$base/unittest-cont1/e/test3.txt",
2014 "$base/unittest-cont1/e/subdir1/test1.txt",
2015 "$base/unittest-cont1/e/subdir1/test2.txt",
2016 "$base/unittest-cont1/e/subdir2/test3.txt",
2017 "$base/unittest-cont1/e/subdir2/test4.txt",
2018 "$base/unittest-cont1/e/subdir2/subdir/test1.txt",
2019 "$base/unittest-cont1/e/subdir3/subdir/test2.txt",
2020 "$base/unittest-cont1/e/subdir4/subdir/test3.txt",
2021 "$base/unittest-cont1/e/subdir4/subdir/test4.txt",
2022 "$base/unittest-cont1/e/subdir4/subdir/test5.txt",
2023 "$base/unittest-cont1/e/subdir4/subdir/sub/test0.txt",
2024 "$base/unittest-cont1/e/subdir4/subdir/sub/120-px-file.txt",
2025 );
2026
2027 // Add the files
2028 $ops = array();
2029 foreach ( $files as $file ) {
2030 $this->prepare( array( 'dir' => dirname( $file ) ) );
2031 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
2032 }
2033 $status = $this->backend->doQuickOperations( $ops );
2034 $this->assertGoodStatus( $status,
2035 "Creation of files succeeded ($backendName)." );
2036 $this->assertEquals( true, $status->isOK(),
2037 "Creation of files succeeded with OK status ($backendName)." );
2038
2039 $this->assertEquals( true,
2040 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) ),
2041 "Directory exists in ($backendName)." );
2042 $this->assertEquals( true,
2043 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/subdir" ) ),
2044 "Directory exists in ($backendName)." );
2045 $this->assertEquals( false,
2046 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/e/subdir2/test1.txt" ) ),
2047 "Directory does not exists in ($backendName)." );
2048
2049 // Expected listing
2050 $expected = array(
2051 "e",
2052 );
2053 sort( $expected );
2054
2055 // Actual listing (no trailing slash)
2056 $list = array();
2057 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
2058 foreach ( $iter as $file ) {
2059 $list[] = $file;
2060 }
2061 sort( $list );
2062
2063 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2064
2065 // Expected listing
2066 $expected = array(
2067 "subdir1",
2068 "subdir2",
2069 "subdir3",
2070 "subdir4",
2071 );
2072 sort( $expected );
2073
2074 // Actual listing (no trailing slash)
2075 $list = array();
2076 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e" ) );
2077 foreach ( $iter as $file ) {
2078 $list[] = $file;
2079 }
2080 sort( $list );
2081
2082 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2083
2084 // Actual listing (with trailing slash)
2085 $list = array();
2086 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/" ) );
2087 foreach ( $iter as $file ) {
2088 $list[] = $file;
2089 }
2090 sort( $list );
2091
2092 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2093
2094 // Expected listing
2095 $expected = array(
2096 "subdir",
2097 );
2098 sort( $expected );
2099
2100 // Actual listing (no trailing slash)
2101 $list = array();
2102 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2" ) );
2103 foreach ( $iter as $file ) {
2104 $list[] = $file;
2105 }
2106 sort( $list );
2107
2108 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2109
2110 // Actual listing (with trailing slash)
2111 $list = array();
2112 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir2/" ) );
2113 foreach ( $iter as $file ) {
2114 $list[] = $file;
2115 }
2116 sort( $list );
2117
2118 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
2119
2120 // Actual listing (using iterator second time)
2121 $list = array();
2122 foreach ( $iter as $file ) {
2123 $list[] = $file;
2124 }
2125 sort( $list );
2126
2127 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
2128
2129 // Expected listing (recursive)
2130 $expected = array(
2131 "e",
2132 "e/subdir1",
2133 "e/subdir2",
2134 "e/subdir3",
2135 "e/subdir4",
2136 "e/subdir2/subdir",
2137 "e/subdir3/subdir",
2138 "e/subdir4/subdir",
2139 "e/subdir4/subdir/sub",
2140 );
2141 sort( $expected );
2142
2143 // Actual listing (recursive)
2144 $list = array();
2145 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
2146 foreach ( $iter as $file ) {
2147 $list[] = $file;
2148 }
2149 sort( $list );
2150
2151 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2152
2153 // Expected listing (recursive)
2154 $expected = array(
2155 "subdir",
2156 "subdir/sub",
2157 );
2158 sort( $expected );
2159
2160 // Actual listing (recursive)
2161 $list = array();
2162 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir4" ) );
2163 foreach ( $iter as $file ) {
2164 $list[] = $file;
2165 }
2166 sort( $list );
2167
2168 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2169
2170 // Actual listing (recursive, second time)
2171 $list = array();
2172 foreach ( $iter as $file ) {
2173 $list[] = $file;
2174 }
2175 sort( $list );
2176
2177 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
2178
2179 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/subdir1" ) );
2180 $items = $this->listToArray( $iter );
2181 $this->assertEquals( array(), $items, "Directory listing is empty." );
2182
2183 foreach ( $files as $file ) { // clean up
2184 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
2185 }
2186
2187 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
2188 foreach ( $iter as $file ) {
2189 // no errors
2190 }
2191
2192 $items = $this->listToArray( $iter );
2193 $this->assertEquals( array(), $items, "Directory listing is empty." );
2194
2195 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/e/not/exists" ) );
2196 $items = $this->listToArray( $iter );
2197 $this->assertEquals( array(), $items, "Directory listing is empty." );
2198 }
2199
2200 /**
2201 * @covers FileBackend::lockFiles
2202 * @covers FileBackend::unlockFiles
2203 */
2204 public function testLockCalls() {
2205 $this->backend = $this->singleBackend;
2206 $this->doTestLockCalls();
2207 }
2208
2209 private function doTestLockCalls() {
2210 $backendName = $this->backendClass();
2211
2212 $paths = array(
2213 "test1.txt",
2214 "test2.txt",
2215 "test3.txt",
2216 "subdir1",
2217 "subdir1", // duplicate
2218 "subdir1/test1.txt",
2219 "subdir1/test2.txt",
2220 "subdir2",
2221 "subdir2", // duplicate
2222 "subdir2/test3.txt",
2223 "subdir2/test4.txt",
2224 "subdir2/subdir",
2225 "subdir2/subdir/test1.txt",
2226 "subdir2/subdir/test2.txt",
2227 "subdir2/subdir/test3.txt",
2228 "subdir2/subdir/test4.txt",
2229 "subdir2/subdir/test5.txt",
2230 "subdir2/subdir/sub",
2231 "subdir2/subdir/sub/test0.txt",
2232 "subdir2/subdir/sub/120-px-file.txt",
2233 );
2234
2235 for ( $i = 0; $i < 25; $i++ ) {
2236 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
2237 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2238 "Locking of files succeeded ($backendName) ($i)." );
2239 $this->assertEquals( true, $status->isOK(),
2240 "Locking of files succeeded with OK status ($backendName) ($i)." );
2241
2242 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
2243 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2244 "Locking of files succeeded ($backendName) ($i)." );
2245 $this->assertEquals( true, $status->isOK(),
2246 "Locking of files succeeded with OK status ($backendName) ($i)." );
2247
2248 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
2249 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2250 "Locking of files succeeded ($backendName) ($i)." );
2251 $this->assertEquals( true, $status->isOK(),
2252 "Locking of files succeeded with OK status ($backendName) ($i)." );
2253
2254 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
2255 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2256 "Locking of files succeeded ($backendName). ($i)" );
2257 $this->assertEquals( true, $status->isOK(),
2258 "Locking of files succeeded with OK status ($backendName) ($i)." );
2259
2260 ## Flip the acquire/release ordering around ##
2261
2262 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
2263 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2264 "Locking of files succeeded ($backendName) ($i)." );
2265 $this->assertEquals( true, $status->isOK(),
2266 "Locking of files succeeded with OK status ($backendName) ($i)." );
2267
2268 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
2269 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2270 "Locking of files succeeded ($backendName) ($i)." );
2271 $this->assertEquals( true, $status->isOK(),
2272 "Locking of files succeeded with OK status ($backendName) ($i)." );
2273
2274 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
2275 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2276 "Locking of files succeeded ($backendName). ($i)" );
2277 $this->assertEquals( true, $status->isOK(),
2278 "Locking of files succeeded with OK status ($backendName) ($i)." );
2279
2280 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
2281 $this->assertEquals( print_r( array(), true ), print_r( $status->errors, true ),
2282 "Locking of files succeeded ($backendName) ($i)." );
2283 $this->assertEquals( true, $status->isOK(),
2284 "Locking of files succeeded with OK status ($backendName) ($i)." );
2285 }
2286
2287 $status = Status::newGood();
2288 $sl = $this->backend->getScopedFileLocks( $paths, LockManager::LOCK_EX, $status );
2289 $this->assertType( 'ScopedLock', $sl,
2290 "Scoped locking of files succeeded ($backendName)." );
2291 $this->assertEquals( array(), $status->errors,
2292 "Scoped locking of files succeeded ($backendName)." );
2293 $this->assertEquals( true, $status->isOK(),
2294 "Scoped locking of files succeeded with OK status ($backendName)." );
2295
2296 ScopedLock::release( $sl );
2297 $this->assertEquals( null, $sl,
2298 "Scoped unlocking of files succeeded ($backendName)." );
2299 $this->assertEquals( array(), $status->errors,
2300 "Scoped unlocking of files succeeded ($backendName)." );
2301 $this->assertEquals( true, $status->isOK(),
2302 "Scoped unlocking of files succeeded with OK status ($backendName)." );
2303 }
2304
2305 // helper function
2306 private function listToArray( $iter ) {
2307 return is_array( $iter ) ? $iter : iterator_to_array( $iter );
2308 }
2309
2310 // test helper wrapper for backend prepare() function
2311 private function prepare( array $params ) {
2312 return $this->backend->prepare( $params );
2313 }
2314
2315 // test helper wrapper for backend prepare() function
2316 private function create( array $params ) {
2317 $params['op'] = 'create';
2318
2319 return $this->backend->doQuickOperations( array( $params ) );
2320 }
2321
2322 function tearDownFiles() {
2323 foreach ( $this->filesToPrune as $file ) {
2324 if ( is_file( $file ) ) {
2325 unlink( $file );
2326 }
2327 }
2328 $containers = array( 'unittest-cont1', 'unittest-cont2' );
2329 foreach ( $containers as $container ) {
2330 $this->deleteFiles( $container );
2331 }
2332 $this->filesToPrune = array();
2333 }
2334
2335 private function deleteFiles( $container ) {
2336 $base = self::baseStorePath();
2337 $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
2338 if ( $iter ) {
2339 foreach ( $iter as $file ) {
2340 $this->backend->quickDelete( array( 'src' => "$base/$container/$file" ) );
2341 }
2342 // free the directory, to avoid Permission denied under windows on rmdir
2343 unset( $iter );
2344 }
2345 $this->backend->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
2346 }
2347
2348 function assertBackendPathsConsistent( array $paths ) {
2349 if ( $this->backend instanceof FileBackendMultiWrite ) {
2350 $status = $this->backend->consistencyCheck( $paths );
2351 $this->assertGoodStatus( $status, "Files synced: " . implode( ',', $paths ) );
2352 }
2353 }
2354
2355 function assertGoodStatus( $status, $msg ) {
2356 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors, 1 ), $msg );
2357 }
2358 }