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