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