merged master
[lhc/web/wiklou.git] / tests / phpunit / includes / filerepo / FileBackendTest.php
1 <?php
2
3 /**
4 * @group medium
5 * ^---- causes phpunit to use a higher timeout threshold
6 *
7 * @group FileRepo
8 * @group FileBackend
9 */
10 class FileBackendTest extends MediaWikiTestCase {
11 private $backend, $multiBackend;
12 private $filesToPrune = array();
13 private static $backendToUse;
14
15 function setUp() {
16 global $wgFileBackends;
17 parent::setUp();
18 $tmpPrefix = wfTempDir() . '/filebackend-unittest-' . time() . '-' . mt_rand();
19 if ( $this->getCliArg( 'use-filebackend=' ) ) {
20 if ( self::$backendToUse ) {
21 $this->singleBackend = self::$backendToUse;
22 } else {
23 $name = $this->getCliArg( 'use-filebackend=' );
24 $useConfig = array();
25 foreach ( $wgFileBackends as $conf ) {
26 if ( $conf['name'] == $name ) {
27 $useConfig = $conf;
28 break;
29 }
30 }
31 $useConfig['name'] = 'localtesting'; // swap name
32 $class = $useConfig['class'];
33 self::$backendToUse = new $class( $useConfig );
34 $this->singleBackend = self::$backendToUse;
35 }
36 } else {
37 $this->singleBackend = new FSFileBackend( array(
38 'name' => 'localtesting',
39 'lockManager' => 'fsLockManager',
40 #'parallelize' => 'implicit',
41 'containerPaths' => array(
42 'unittest-cont1' => "{$tmpPrefix}-localtesting-cont1",
43 'unittest-cont2' => "{$tmpPrefix}-localtesting-cont2" )
44 ) );
45 }
46 $this->multiBackend = new FileBackendMultiWrite( array(
47 'name' => 'localtesting',
48 'lockManager' => 'fsLockManager',
49 'parallelize' => 'implicit',
50 'backends' => array(
51 array(
52 'name' => 'localmutlitesting1',
53 'class' => 'FSFileBackend',
54 'lockManager' => 'nullLockManager',
55 'containerPaths' => array(
56 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti1-cont1",
57 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti1-cont2" ),
58 'isMultiMaster' => false
59 ),
60 array(
61 'name' => 'localmutlitesting2',
62 'class' => 'FSFileBackend',
63 'lockManager' => 'nullLockManager',
64 'containerPaths' => array(
65 'unittest-cont1' => "{$tmpPrefix}-localtestingmulti2-cont1",
66 'unittest-cont2' => "{$tmpPrefix}-localtestingmulti2-cont2" ),
67 'isMultiMaster' => true
68 )
69 )
70 ) );
71 $this->filesToPrune = array();
72 }
73
74 private function baseStorePath() {
75 return 'mwstore://localtesting';
76 }
77
78 private function backendClass() {
79 return get_class( $this->backend );
80 }
81
82 /**
83 * @dataProvider provider_testIsStoragePath
84 */
85 public function testIsStoragePath( $path, $isStorePath ) {
86 $this->assertEquals( $isStorePath, FileBackend::isStoragePath( $path ),
87 "FileBackend::isStoragePath on path '$path'" );
88 }
89
90 function provider_testIsStoragePath() {
91 return array(
92 array( 'mwstore://', true ),
93 array( 'mwstore://backend', true ),
94 array( 'mwstore://backend/container', true ),
95 array( 'mwstore://backend/container/', true ),
96 array( 'mwstore://backend/container/path', true ),
97 array( 'mwstore://backend//container/', true ),
98 array( 'mwstore://backend//container//', true ),
99 array( 'mwstore://backend//container//path', true ),
100 array( 'mwstore:///', true ),
101 array( 'mwstore:/', false ),
102 array( 'mwstore:', false ),
103 );
104 }
105
106 /**
107 * @dataProvider provider_testSplitStoragePath
108 */
109 public function testSplitStoragePath( $path, $res ) {
110 $this->assertEquals( $res, FileBackend::splitStoragePath( $path ),
111 "FileBackend::splitStoragePath on path '$path'" );
112 }
113
114 function provider_testSplitStoragePath() {
115 return array(
116 array( 'mwstore://backend/container', array( 'backend', 'container', '' ) ),
117 array( 'mwstore://backend/container/', array( 'backend', 'container', '' ) ),
118 array( 'mwstore://backend/container/path', array( 'backend', 'container', 'path' ) ),
119 array( 'mwstore://backend/container//path', array( 'backend', 'container', '/path' ) ),
120 array( 'mwstore://backend//container/path', array( null, null, null ) ),
121 array( 'mwstore://backend//container//path', array( null, null, null ) ),
122 array( 'mwstore://', array( null, null, null ) ),
123 array( 'mwstore://backend', array( null, null, null ) ),
124 array( 'mwstore:///', array( null, null, null ) ),
125 array( 'mwstore:/', array( null, null, null ) ),
126 array( 'mwstore:', array( null, null, null ) )
127 );
128 }
129
130 /**
131 * @dataProvider provider_normalizeStoragePath
132 */
133 public function testNormalizeStoragePath( $path, $res ) {
134 $this->assertEquals( $res, FileBackend::normalizeStoragePath( $path ),
135 "FileBackend::normalizeStoragePath on path '$path'" );
136 }
137
138 function provider_normalizeStoragePath() {
139 return array(
140 array( 'mwstore://backend/container', 'mwstore://backend/container' ),
141 array( 'mwstore://backend/container/', 'mwstore://backend/container' ),
142 array( 'mwstore://backend/container/path', 'mwstore://backend/container/path' ),
143 array( 'mwstore://backend/container//path', 'mwstore://backend/container/path' ),
144 array( 'mwstore://backend/container///path', 'mwstore://backend/container/path' ),
145 array( 'mwstore://backend/container///path//to///obj', 'mwstore://backend/container/path/to/obj',
146 array( 'mwstore://', null ),
147 array( 'mwstore://backend', null ),
148 array( 'mwstore://backend//container/path', null ),
149 array( 'mwstore://backend//container//path', null ),
150 array( 'mwstore:///', null ),
151 array( 'mwstore:/', null ),
152 array( 'mwstore:', null ), )
153 );
154 }
155
156 /**
157 * @dataProvider provider_testParentStoragePath
158 */
159 public function testParentStoragePath( $path, $res ) {
160 $this->assertEquals( $res, FileBackend::parentStoragePath( $path ),
161 "FileBackend::parentStoragePath on path '$path'" );
162 }
163
164 function provider_testParentStoragePath() {
165 return array(
166 array( 'mwstore://backend/container/path/to/obj', 'mwstore://backend/container/path/to' ),
167 array( 'mwstore://backend/container/path/to', 'mwstore://backend/container/path' ),
168 array( 'mwstore://backend/container/path', 'mwstore://backend/container' ),
169 array( 'mwstore://backend/container', null ),
170 array( 'mwstore://backend/container/path/to/obj/', 'mwstore://backend/container/path/to' ),
171 array( 'mwstore://backend/container/path/to/', 'mwstore://backend/container/path' ),
172 array( 'mwstore://backend/container/path/', 'mwstore://backend/container' ),
173 array( 'mwstore://backend/container/', null ),
174 );
175 }
176
177 /**
178 * @dataProvider provider_testExtensionFromPath
179 */
180 public function testExtensionFromPath( $path, $res ) {
181 $this->assertEquals( $res, FileBackend::extensionFromPath( $path ),
182 "FileBackend::extensionFromPath on path '$path'" );
183 }
184
185 function provider_testExtensionFromPath() {
186 return array(
187 array( 'mwstore://backend/container/path.txt', 'txt' ),
188 array( 'mwstore://backend/container/path.svg.png', 'png' ),
189 array( 'mwstore://backend/container/path', '' ),
190 array( 'mwstore://backend/container/path.', '' ),
191 );
192 }
193
194 /**
195 * @dataProvider provider_testStore
196 */
197 public function testStore( $op ) {
198 $this->filesToPrune[] = $op['src'];
199
200 $this->backend = $this->singleBackend;
201 $this->tearDownFiles();
202 $this->doTestStore( $op );
203 $this->tearDownFiles();
204
205 $this->backend = $this->multiBackend;
206 $this->tearDownFiles();
207 $this->doTestStore( $op );
208 $this->filesToPrune[] = $op['src']; # avoid file leaking
209 $this->tearDownFiles();
210 }
211
212 private function doTestStore( $op ) {
213 $backendName = $this->backendClass();
214
215 $source = $op['src'];
216 $dest = $op['dst'];
217 $this->prepare( array( 'dir' => dirname( $dest ) ) );
218
219 file_put_contents( $source, "Unit test file" );
220
221 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
222 $this->backend->store( $op );
223 }
224
225 $status = $this->backend->doOperation( $op );
226
227 $this->assertGoodStatus( $status,
228 "Store from $source to $dest succeeded without warnings ($backendName)." );
229 $this->assertEquals( true, $status->isOK(),
230 "Store from $source to $dest succeeded ($backendName)." );
231 $this->assertEquals( array( 0 => true ), $status->success,
232 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
233 $this->assertEquals( true, file_exists( $source ),
234 "Source file $source still exists ($backendName)." );
235 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
236 "Destination file $dest exists ($backendName)." );
237
238 $this->assertEquals( filesize( $source ),
239 $this->backend->getFileSize( array( 'src' => $dest ) ),
240 "Destination file $dest has correct size ($backendName)." );
241
242 $props1 = FSFile::getPropsFromPath( $source );
243 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
244 $this->assertEquals( $props1, $props2,
245 "Source and destination have the same props ($backendName)." );
246 }
247
248 public function provider_testStore() {
249 $cases = array();
250
251 $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
252 $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt';
253 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
254 $cases[] = array(
255 $op, // operation
256 $tmpName, // source
257 $toPath, // dest
258 );
259
260 $op2 = $op;
261 $op2['overwrite'] = true;
262 $cases[] = array(
263 $op2, // operation
264 $tmpName, // source
265 $toPath, // dest
266 );
267
268 $op2 = $op;
269 $op2['overwriteSame'] = true;
270 $cases[] = array(
271 $op2, // operation
272 $tmpName, // source
273 $toPath, // dest
274 );
275
276 return $cases;
277 }
278
279 /**
280 * @dataProvider provider_testCopy
281 */
282 public function testCopy( $op ) {
283 $this->backend = $this->singleBackend;
284 $this->tearDownFiles();
285 $this->doTestCopy( $op );
286 $this->tearDownFiles();
287
288 $this->backend = $this->multiBackend;
289 $this->tearDownFiles();
290 $this->doTestCopy( $op );
291 $this->tearDownFiles();
292 }
293
294 private function doTestCopy( $op ) {
295 $backendName = $this->backendClass();
296
297 $source = $op['src'];
298 $dest = $op['dst'];
299 $this->prepare( array( 'dir' => dirname( $source ) ) );
300 $this->prepare( array( 'dir' => dirname( $dest ) ) );
301
302 $status = $this->backend->doOperation(
303 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
304 $this->assertGoodStatus( $status,
305 "Creation of file at $source succeeded ($backendName)." );
306
307 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
308 $this->backend->copy( $op );
309 }
310
311 $status = $this->backend->doOperation( $op );
312
313 $this->assertGoodStatus( $status,
314 "Copy from $source to $dest succeeded without warnings ($backendName)." );
315 $this->assertEquals( true, $status->isOK(),
316 "Copy from $source to $dest succeeded ($backendName)." );
317 $this->assertEquals( array( 0 => true ), $status->success,
318 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
319 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
320 "Source file $source still exists ($backendName)." );
321 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
322 "Destination file $dest exists after copy ($backendName)." );
323
324 $this->assertEquals(
325 $this->backend->getFileSize( array( 'src' => $source ) ),
326 $this->backend->getFileSize( array( 'src' => $dest ) ),
327 "Destination file $dest has correct size ($backendName)." );
328
329 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
330 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
331 $this->assertEquals( $props1, $props2,
332 "Source and destination have the same props ($backendName)." );
333 }
334
335 public function provider_testCopy() {
336 $cases = array();
337
338 $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
339 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
340
341 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
342 $cases[] = array(
343 $op, // operation
344 $source, // source
345 $dest, // dest
346 );
347
348 $op2 = $op;
349 $op2['overwrite'] = true;
350 $cases[] = array(
351 $op2, // operation
352 $source, // source
353 $dest, // dest
354 );
355
356 $op2 = $op;
357 $op2['overwriteSame'] = true;
358 $cases[] = array(
359 $op2, // operation
360 $source, // source
361 $dest, // dest
362 );
363
364 return $cases;
365 }
366
367 /**
368 * @dataProvider provider_testMove
369 */
370 public function testMove( $op ) {
371 $this->backend = $this->singleBackend;
372 $this->tearDownFiles();
373 $this->doTestMove( $op );
374 $this->tearDownFiles();
375
376 $this->backend = $this->multiBackend;
377 $this->tearDownFiles();
378 $this->doTestMove( $op );
379 $this->tearDownFiles();
380 }
381
382 private function doTestMove( $op ) {
383 $backendName = $this->backendClass();
384
385 $source = $op['src'];
386 $dest = $op['dst'];
387 $this->prepare( array( 'dir' => dirname( $source ) ) );
388 $this->prepare( array( 'dir' => dirname( $dest ) ) );
389
390 $status = $this->backend->doOperation(
391 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
392 $this->assertGoodStatus( $status,
393 "Creation of file at $source succeeded ($backendName)." );
394
395 if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
396 $this->backend->copy( $op );
397 }
398
399 $status = $this->backend->doOperation( $op );
400 $this->assertGoodStatus( $status,
401 "Move from $source to $dest succeeded without warnings ($backendName)." );
402 $this->assertEquals( true, $status->isOK(),
403 "Move from $source to $dest succeeded ($backendName)." );
404 $this->assertEquals( array( 0 => true ), $status->success,
405 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
406 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
407 "Source file $source does not still exists ($backendName)." );
408 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
409 "Destination file $dest exists after move ($backendName)." );
410
411 $this->assertNotEquals(
412 $this->backend->getFileSize( array( 'src' => $source ) ),
413 $this->backend->getFileSize( array( 'src' => $dest ) ),
414 "Destination file $dest has correct size ($backendName)." );
415
416 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
417 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
418 $this->assertEquals( false, $props1['fileExists'],
419 "Source file does not exist accourding to props ($backendName)." );
420 $this->assertEquals( true, $props2['fileExists'],
421 "Destination file exists accourding to props ($backendName)." );
422 }
423
424 public function provider_testMove() {
425 $cases = array();
426
427 $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
428 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
429
430 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
431 $cases[] = array(
432 $op, // operation
433 $source, // source
434 $dest, // dest
435 );
436
437 $op2 = $op;
438 $op2['overwrite'] = true;
439 $cases[] = array(
440 $op2, // operation
441 $source, // source
442 $dest, // dest
443 );
444
445 $op2 = $op;
446 $op2['overwriteSame'] = true;
447 $cases[] = array(
448 $op2, // operation
449 $source, // source
450 $dest, // dest
451 );
452
453 return $cases;
454 }
455
456 /**
457 * @dataProvider provider_testDelete
458 */
459 public function testDelete( $op, $withSource, $okStatus ) {
460 $this->backend = $this->singleBackend;
461 $this->tearDownFiles();
462 $this->doTestDelete( $op, $withSource, $okStatus );
463 $this->tearDownFiles();
464
465 $this->backend = $this->multiBackend;
466 $this->tearDownFiles();
467 $this->doTestDelete( $op, $withSource, $okStatus );
468 $this->tearDownFiles();
469 }
470
471 private function doTestDelete( $op, $withSource, $okStatus ) {
472 $backendName = $this->backendClass();
473
474 $source = $op['src'];
475 $this->prepare( array( 'dir' => dirname( $source ) ) );
476
477 if ( $withSource ) {
478 $status = $this->backend->doOperation(
479 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
480 $this->assertGoodStatus( $status,
481 "Creation of file at $source succeeded ($backendName)." );
482 }
483
484 $status = $this->backend->doOperation( $op );
485 if ( $okStatus ) {
486 $this->assertGoodStatus( $status,
487 "Deletion of file at $source succeeded without warnings ($backendName)." );
488 $this->assertEquals( true, $status->isOK(),
489 "Deletion of file at $source succeeded ($backendName)." );
490 $this->assertEquals( array( 0 => true ), $status->success,
491 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
492 } else {
493 $this->assertEquals( false, $status->isOK(),
494 "Deletion of file at $source failed ($backendName)." );
495 }
496
497 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
498 "Source file $source does not exist after move ($backendName)." );
499
500 $this->assertFalse(
501 $this->backend->getFileSize( array( 'src' => $source ) ),
502 "Source file $source has correct size (false) ($backendName)." );
503
504 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
505 $this->assertFalse( $props1['fileExists'],
506 "Source file $source does not exist according to props ($backendName)." );
507 }
508
509 public function provider_testDelete() {
510 $cases = array();
511
512 $source = $this->baseStorePath() . '/unittest-cont1/myfacefile.txt';
513
514 $op = array( 'op' => 'delete', 'src' => $source );
515 $cases[] = array(
516 $op, // operation
517 true, // with source
518 true // succeeds
519 );
520
521 $cases[] = array(
522 $op, // operation
523 false, // without source
524 false // fails
525 );
526
527 $op['ignoreMissingSource'] = true;
528 $cases[] = array(
529 $op, // operation
530 false, // without source
531 true // succeeds
532 );
533
534 return $cases;
535 }
536
537 /**
538 * @dataProvider provider_testCreate
539 */
540 public function testCreate( $op, $alreadyExists, $okStatus, $newSize ) {
541 $this->backend = $this->singleBackend;
542 $this->tearDownFiles();
543 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
544 $this->tearDownFiles();
545
546 $this->backend = $this->multiBackend;
547 $this->tearDownFiles();
548 $this->doTestCreate( $op, $alreadyExists, $okStatus, $newSize );
549 $this->tearDownFiles();
550 }
551
552 private function doTestCreate( $op, $alreadyExists, $okStatus, $newSize ) {
553 $backendName = $this->backendClass();
554
555 $dest = $op['dst'];
556 $this->prepare( array( 'dir' => dirname( $dest ) ) );
557
558 $oldText = 'blah...blah...waahwaah';
559 if ( $alreadyExists ) {
560 $status = $this->backend->doOperation(
561 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
562 $this->assertGoodStatus( $status,
563 "Creation of file at $dest succeeded ($backendName)." );
564 }
565
566 $status = $this->backend->doOperation( $op );
567 if ( $okStatus ) {
568 $this->assertGoodStatus( $status,
569 "Creation of file at $dest succeeded without warnings ($backendName)." );
570 $this->assertEquals( true, $status->isOK(),
571 "Creation of file at $dest succeeded ($backendName)." );
572 $this->assertEquals( array( 0 => true ), $status->success,
573 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
574 } else {
575 $this->assertEquals( false, $status->isOK(),
576 "Creation of file at $dest failed ($backendName)." );
577 }
578
579 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
580 "Destination file $dest exists after creation ($backendName)." );
581
582 $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
583 $this->assertEquals( true, $props1['fileExists'],
584 "Destination file $dest exists according to props ($backendName)." );
585 if ( $okStatus ) { // file content is what we saved
586 $this->assertEquals( $newSize, $props1['size'],
587 "Destination file $dest has expected size according to props ($backendName)." );
588 $this->assertEquals( $newSize,
589 $this->backend->getFileSize( array( 'src' => $dest ) ),
590 "Destination file $dest has correct size ($backendName)." );
591 } else { // file content is some other previous text
592 $this->assertEquals( strlen( $oldText ), $props1['size'],
593 "Destination file $dest has original size according to props ($backendName)." );
594 $this->assertEquals( strlen( $oldText ),
595 $this->backend->getFileSize( array( 'src' => $dest ) ),
596 "Destination file $dest has original size according to props ($backendName)." );
597 }
598 }
599
600 /**
601 * @dataProvider provider_testCreate
602 */
603 public function provider_testCreate() {
604 $cases = array();
605
606 $dest = $this->baseStorePath() . '/unittest-cont2/myspacefile.txt';
607
608 $op = array( 'op' => 'create', 'content' => 'test test testing', 'dst' => $dest );
609 $cases[] = array(
610 $op, // operation
611 false, // no dest already exists
612 true, // succeeds
613 strlen( $op['content'] )
614 );
615
616 $op2 = $op;
617 $op2['content'] = "\n";
618 $cases[] = array(
619 $op2, // operation
620 false, // no dest already exists
621 true, // succeeds
622 strlen( $op2['content'] )
623 );
624
625 $op2 = $op;
626 $op2['content'] = "fsf\n waf 3kt";
627 $cases[] = array(
628 $op2, // operation
629 true, // dest already exists
630 false, // fails
631 strlen( $op2['content'] )
632 );
633
634 $op2 = $op;
635 $op2['content'] = "egm'g gkpe gpqg eqwgwqg";
636 $op2['overwrite'] = true;
637 $cases[] = array(
638 $op2, // operation
639 true, // dest already exists
640 true, // succeeds
641 strlen( $op2['content'] )
642 );
643
644 $op2 = $op;
645 $op2['content'] = "39qjmg3-qg";
646 $op2['overwriteSame'] = true;
647 $cases[] = array(
648 $op2, // operation
649 true, // dest already exists
650 false, // succeeds
651 strlen( $op2['content'] )
652 );
653
654 return $cases;
655 }
656
657 public function testDoQuickOperations() {
658 $this->backend = $this->singleBackend;
659 $this->doTestDoQuickOperations();
660 $this->tearDownFiles();
661
662 $this->backend = $this->multiBackend;
663 $this->doTestDoQuickOperations();
664 $this->tearDownFiles();
665 }
666
667 private function doTestDoQuickOperations() {
668 $backendName = $this->backendClass();
669
670 $base = $this->baseStorePath();
671 $files = array(
672 "$base/unittest-cont1/fileA.a",
673 "$base/unittest-cont1/fileB.a",
674 "$base/unittest-cont1/fileC.a"
675 );
676 $ops = array();
677 $purgeOps = array();
678 foreach ( $files as $path ) {
679 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
680 $this->assertGoodStatus( $status,
681 "Preparing $path succeeded without warnings ($backendName)." );
682 $ops[] = array( 'op' => 'create', 'dst' => $path, 'content' => mt_rand(0,50000) );
683 $purgeOps[] = array( 'op' => 'delete', 'src' => $path );
684 }
685 $purgeOps[] = array( 'op' => 'null' );
686 $status = $this->backend->doQuickOperations( $ops );
687 $this->assertGoodStatus( $status,
688 "Creation of source files succeeded ($backendName)." );
689
690 foreach ( $files as $file ) {
691 $this->assertTrue( $this->backend->fileExists( array( 'src' => $file ) ),
692 "File $file exists." );
693 }
694
695 $status = $this->backend->doQuickOperations( $purgeOps );
696 $this->assertGoodStatus( $status,
697 "Quick deletion of source files succeeded ($backendName)." );
698
699 foreach ( $files as $file ) {
700 $this->assertFalse( $this->backend->fileExists( array( 'src' => $file ) ),
701 "File $file purged." );
702 }
703 }
704
705 /**
706 * @dataProvider provider_testConcatenate
707 */
708 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
709 $this->filesToPrune[] = $op['dst'];
710
711 $this->backend = $this->singleBackend;
712 $this->tearDownFiles();
713 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
714 $this->tearDownFiles();
715
716 $this->backend = $this->multiBackend;
717 $this->tearDownFiles();
718 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
719 $this->filesToPrune[] = $op['dst']; # avoid file leaking
720 $this->tearDownFiles();
721 }
722
723 private function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
724 $backendName = $this->backendClass();
725
726 $expContent = '';
727 // Create sources
728 $ops = array();
729 foreach ( $srcs as $i => $source ) {
730 $this->prepare( array( 'dir' => dirname( $source ) ) );
731 $ops[] = array(
732 'op' => 'create', // operation
733 'dst' => $source, // source
734 'content' => $srcsContent[$i]
735 );
736 $expContent .= $srcsContent[$i];
737 }
738 $status = $this->backend->doOperations( $ops );
739
740 $this->assertGoodStatus( $status,
741 "Creation of source files succeeded ($backendName)." );
742
743 $dest = $params['dst'];
744 if ( $alreadyExists ) {
745 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
746 $this->assertEquals( true, $ok,
747 "Creation of file at $dest succeeded ($backendName)." );
748 } else {
749 $ok = file_put_contents( $dest, '' ) !== false;
750 $this->assertEquals( true, $ok,
751 "Creation of 0-byte file at $dest succeeded ($backendName)." );
752 }
753
754 // Combine the files into one
755 $status = $this->backend->concatenate( $params );
756 if ( $okStatus ) {
757 $this->assertGoodStatus( $status,
758 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
759 $this->assertEquals( true, $status->isOK(),
760 "Creation of concat file at $dest succeeded ($backendName)." );
761 } else {
762 $this->assertEquals( false, $status->isOK(),
763 "Creation of concat file at $dest failed ($backendName)." );
764 }
765
766 if ( $okStatus ) {
767 $this->assertEquals( true, is_file( $dest ),
768 "Dest concat file $dest exists after creation ($backendName)." );
769 } else {
770 $this->assertEquals( true, is_file( $dest ),
771 "Dest concat file $dest exists after failed creation ($backendName)." );
772 }
773
774 $contents = file_get_contents( $dest );
775 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
776
777 if ( $okStatus ) {
778 $this->assertEquals( $expContent, $contents,
779 "Concat file at $dest has correct contents ($backendName)." );
780 } else {
781 $this->assertNotEquals( $expContent, $contents,
782 "Concat file at $dest has correct contents ($backendName)." );
783 }
784 }
785
786 function provider_testConcatenate() {
787 $cases = array();
788
789 $rand = mt_rand( 0, 2000000000 ) . time();
790 $dest = wfTempDir() . "/randomfile!$rand.txt";
791 $srcs = array(
792 $this->baseStorePath() . '/unittest-cont1/file1.txt',
793 $this->baseStorePath() . '/unittest-cont1/file2.txt',
794 $this->baseStorePath() . '/unittest-cont1/file3.txt',
795 $this->baseStorePath() . '/unittest-cont1/file4.txt',
796 $this->baseStorePath() . '/unittest-cont1/file5.txt',
797 $this->baseStorePath() . '/unittest-cont1/file6.txt',
798 $this->baseStorePath() . '/unittest-cont1/file7.txt',
799 $this->baseStorePath() . '/unittest-cont1/file8.txt',
800 $this->baseStorePath() . '/unittest-cont1/file9.txt',
801 $this->baseStorePath() . '/unittest-cont1/file10.txt'
802 );
803 $content = array(
804 'egfage',
805 'ageageag',
806 'rhokohlr',
807 'shgmslkg',
808 'kenga',
809 'owagmal',
810 'kgmae',
811 'g eak;g',
812 'lkaem;a',
813 'legma'
814 );
815 $params = array( 'srcs' => $srcs, 'dst' => $dest );
816
817 $cases[] = array(
818 $params, // operation
819 $srcs, // sources
820 $content, // content for each source
821 false, // no dest already exists
822 true, // succeeds
823 );
824
825 $cases[] = array(
826 $params, // operation
827 $srcs, // sources
828 $content, // content for each source
829 true, // dest already exists
830 false, // succeeds
831 );
832
833 return $cases;
834 }
835
836 /**
837 * @dataProvider provider_testGetFileStat
838 */
839 public function testGetFileStat( $path, $content, $alreadyExists ) {
840 $this->backend = $this->singleBackend;
841 $this->tearDownFiles();
842 $this->doTestGetFileStat( $path, $content, $alreadyExists );
843 $this->tearDownFiles();
844
845 $this->backend = $this->multiBackend;
846 $this->tearDownFiles();
847 $this->doTestGetFileStat( $path, $content, $alreadyExists );
848 $this->tearDownFiles();
849 }
850
851 private function doTestGetFileStat( $path, $content, $alreadyExists ) {
852 $backendName = $this->backendClass();
853
854 if ( $alreadyExists ) {
855 $this->prepare( array( 'dir' => dirname( $path ) ) );
856 $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
857 $this->assertGoodStatus( $status,
858 "Creation of file at $path succeeded ($backendName)." );
859
860 $size = $this->backend->getFileSize( array( 'src' => $path ) );
861 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
862 $stat = $this->backend->getFileStat( array( 'src' => $path ) );
863
864 $this->assertEquals( strlen( $content ), $size,
865 "Correct file size of '$path'" );
866 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
867 "Correct file timestamp of '$path'" );
868
869 $size = $stat['size'];
870 $time = $stat['mtime'];
871 $this->assertEquals( strlen( $content ), $size,
872 "Correct file size of '$path'" );
873 $this->assertTrue( abs( time() - wfTimestamp( TS_UNIX, $time ) ) < 10,
874 "Correct file timestamp of '$path'" );
875 } else {
876 $size = $this->backend->getFileSize( array( 'src' => $path ) );
877 $time = $this->backend->getFileTimestamp( array( 'src' => $path ) );
878 $stat = $this->backend->getFileStat( array( 'src' => $path ) );
879
880 $this->assertFalse( $size, "Correct file size of '$path'" );
881 $this->assertFalse( $time, "Correct file timestamp of '$path'" );
882 $this->assertFalse( $stat, "Correct file stat of '$path'" );
883 }
884 }
885
886 function provider_testGetFileStat() {
887 $cases = array();
888
889 $base = $this->baseStorePath();
890 $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents", true );
891 $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "", true );
892 $cases[] = array( "$base/unittest-cont1/b/some-diff_file.txt", null, false );
893
894 return $cases;
895 }
896
897 /**
898 * @dataProvider provider_testGetFileContents
899 */
900 public function testGetFileContents( $source, $content ) {
901 $this->backend = $this->singleBackend;
902 $this->tearDownFiles();
903 $this->doTestGetFileContents( $source, $content );
904 $this->tearDownFiles();
905
906 $this->backend = $this->multiBackend;
907 $this->tearDownFiles();
908 $this->doTestGetFileContents( $source, $content );
909 $this->tearDownFiles();
910 }
911
912 private function doTestGetFileContents( $source, $content ) {
913 $backendName = $this->backendClass();
914
915 $this->prepare( array( 'dir' => dirname( $source ) ) );
916
917 $status = $this->backend->doOperation(
918 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
919 $this->assertGoodStatus( $status,
920 "Creation of file at $source succeeded ($backendName)." );
921 $this->assertEquals( true, $status->isOK(),
922 "Creation of file at $source succeeded with OK status ($backendName)." );
923
924 $newContents = $this->backend->getFileContents( array( 'src' => $source, 'latest' => 1 ) );
925 $this->assertNotEquals( false, $newContents,
926 "Read of file at $source succeeded ($backendName)." );
927
928 $this->assertEquals( $content, $newContents,
929 "Contents read match data at $source ($backendName)." );
930 }
931
932 function provider_testGetFileContents() {
933 $cases = array();
934
935 $base = $this->baseStorePath();
936 $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents" );
937 $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "more file contents" );
938
939 return $cases;
940 }
941
942 /**
943 * @dataProvider provider_testGetLocalCopy
944 */
945 public function testGetLocalCopy( $source, $content ) {
946 $this->backend = $this->singleBackend;
947 $this->tearDownFiles();
948 $this->doTestGetLocalCopy( $source, $content );
949 $this->tearDownFiles();
950
951 $this->backend = $this->multiBackend;
952 $this->tearDownFiles();
953 $this->doTestGetLocalCopy( $source, $content );
954 $this->tearDownFiles();
955 }
956
957 private function doTestGetLocalCopy( $source, $content ) {
958 $backendName = $this->backendClass();
959
960 $this->prepare( array( 'dir' => dirname( $source ) ) );
961
962 $status = $this->backend->doOperation(
963 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
964 $this->assertGoodStatus( $status,
965 "Creation of file at $source succeeded ($backendName)." );
966
967 $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
968 $this->assertNotNull( $tmpFile,
969 "Creation of local copy of $source succeeded ($backendName)." );
970
971 $contents = file_get_contents( $tmpFile->getPath() );
972 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
973 }
974
975 function provider_testGetLocalCopy() {
976 $cases = array();
977
978 $base = $this->baseStorePath();
979 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
980 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
981
982 return $cases;
983 }
984
985 /**
986 * @dataProvider provider_testGetLocalReference
987 */
988 public function testGetLocalReference( $source, $content ) {
989 $this->backend = $this->singleBackend;
990 $this->tearDownFiles();
991 $this->doTestGetLocalReference( $source, $content );
992 $this->tearDownFiles();
993
994 $this->backend = $this->multiBackend;
995 $this->tearDownFiles();
996 $this->doTestGetLocalReference( $source, $content );
997 $this->tearDownFiles();
998 }
999
1000 private function doTestGetLocalReference( $source, $content ) {
1001 $backendName = $this->backendClass();
1002
1003 $this->prepare( array( 'dir' => dirname( $source ) ) );
1004
1005 $status = $this->create( array( 'content' => $content, 'dst' => $source ) );
1006 $this->assertGoodStatus( $status,
1007 "Creation of file at $source succeeded ($backendName)." );
1008
1009 $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
1010 $this->assertNotNull( $tmpFile,
1011 "Creation of local copy of $source succeeded ($backendName)." );
1012
1013 $contents = file_get_contents( $tmpFile->getPath() );
1014 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
1015 }
1016
1017 function provider_testGetLocalReference() {
1018 $cases = array();
1019
1020 $base = $this->baseStorePath();
1021 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
1022 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
1023
1024 return $cases;
1025 }
1026
1027 /**
1028 * @dataProvider provider_testPrepareAndClean
1029 */
1030 public function testPrepareAndClean( $path, $isOK ) {
1031 $this->backend = $this->singleBackend;
1032 $this->doTestPrepareAndClean( $path, $isOK );
1033 $this->tearDownFiles();
1034
1035 $this->backend = $this->multiBackend;
1036 $this->doTestPrepareAndClean( $path, $isOK );
1037 $this->tearDownFiles();
1038 }
1039
1040 function provider_testPrepareAndClean() {
1041 $base = $this->baseStorePath();
1042 return array(
1043 array( "$base/unittest-cont1/a/z/some_file1.txt", true ),
1044 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
1045 # Specific to FS backend with no basePath field set
1046 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
1047 );
1048 }
1049
1050 private function doTestPrepareAndClean( $path, $isOK ) {
1051 $backendName = $this->backendClass();
1052
1053 $status = $this->prepare( array( 'dir' => dirname( $path ) ) );
1054 if ( $isOK ) {
1055 $this->assertGoodStatus( $status,
1056 "Preparing dir $path succeeded without warnings ($backendName)." );
1057 $this->assertEquals( true, $status->isOK(),
1058 "Preparing dir $path succeeded ($backendName)." );
1059 } else {
1060 $this->assertEquals( false, $status->isOK(),
1061 "Preparing dir $path failed ($backendName)." );
1062 }
1063
1064 $status = $this->backend->clean( array( 'dir' => dirname( $path ) ) );
1065 if ( $isOK ) {
1066 $this->assertGoodStatus( $status,
1067 "Cleaning dir $path succeeded without warnings ($backendName)." );
1068 $this->assertEquals( true, $status->isOK(),
1069 "Cleaning dir $path succeeded ($backendName)." );
1070 } else {
1071 $this->assertEquals( false, $status->isOK(),
1072 "Cleaning dir $path failed ($backendName)." );
1073 }
1074 }
1075
1076 public function testRecursiveClean() {
1077 $this->backend = $this->singleBackend;
1078 $this->doTestRecursiveClean();
1079 $this->tearDownFiles();
1080
1081 $this->backend = $this->multiBackend;
1082 $this->doTestRecursiveClean();
1083 $this->tearDownFiles();
1084 }
1085
1086 private function doTestRecursiveClean() {
1087 $backendName = $this->backendClass();
1088
1089 $base = $this->baseStorePath();
1090 $dirs = array(
1091 "$base/unittest-cont1/a",
1092 "$base/unittest-cont1/a/b",
1093 "$base/unittest-cont1/a/b/c",
1094 "$base/unittest-cont1/a/b/c/d0",
1095 "$base/unittest-cont1/a/b/c/d1",
1096 "$base/unittest-cont1/a/b/c/d2",
1097 "$base/unittest-cont1/a/b/c/d0/1",
1098 "$base/unittest-cont1/a/b/c/d0/2",
1099 "$base/unittest-cont1/a/b/c/d1/3",
1100 "$base/unittest-cont1/a/b/c/d1/4",
1101 "$base/unittest-cont1/a/b/c/d2/5",
1102 "$base/unittest-cont1/a/b/c/d2/6"
1103 );
1104 foreach ( $dirs as $dir ) {
1105 $status = $this->prepare( array( 'dir' => $dir ) );
1106 $this->assertGoodStatus( $status,
1107 "Preparing dir $dir succeeded without warnings ($backendName)." );
1108 }
1109
1110 if ( $this->backend instanceof FSFileBackend ) {
1111 foreach ( $dirs as $dir ) {
1112 $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ),
1113 "Dir $dir exists ($backendName)." );
1114 }
1115 }
1116
1117 $status = $this->backend->clean(
1118 array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) );
1119 $this->assertGoodStatus( $status,
1120 "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." );
1121
1122 foreach ( $dirs as $dir ) {
1123 $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ),
1124 "Dir $dir no longer exists ($backendName)." );
1125 }
1126 }
1127
1128 // @TODO: testSecure
1129
1130 public function testDoOperations() {
1131 $this->backend = $this->singleBackend;
1132 $this->tearDownFiles();
1133 $this->doTestDoOperations();
1134 $this->tearDownFiles();
1135
1136 $this->backend = $this->multiBackend;
1137 $this->tearDownFiles();
1138 $this->doTestDoOperations();
1139 $this->tearDownFiles();
1140
1141 $this->backend = $this->singleBackend;
1142 $this->tearDownFiles();
1143 $this->doTestDoOperations2();
1144 $this->tearDownFiles();
1145
1146 $this->backend = $this->multiBackend;
1147 $this->tearDownFiles();
1148 $this->doTestDoOperations2();
1149 $this->tearDownFiles();
1150
1151 $this->backend = $this->singleBackend;
1152 $this->tearDownFiles();
1153 $this->doTestDoOperationsFailing();
1154 $this->tearDownFiles();
1155
1156 $this->backend = $this->multiBackend;
1157 $this->tearDownFiles();
1158 $this->doTestDoOperationsFailing();
1159 $this->tearDownFiles();
1160 }
1161
1162 private function doTestDoOperations() {
1163 $base = $this->baseStorePath();
1164
1165 $fileA = "$base/unittest-cont1/a/b/fileA.txt";
1166 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1167 $fileB = "$base/unittest-cont1/a/b/fileB.txt";
1168 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1169 $fileC = "$base/unittest-cont1/a/b/fileC.txt";
1170 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1171 $fileD = "$base/unittest-cont1/a/b/fileD.txt";
1172
1173 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1174 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1175 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1176 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1177 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1178 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1179 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1180
1181 $status = $this->backend->doOperations( array(
1182 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1183 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1184 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1185 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1186 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1187 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1188 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1189 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1190 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1191 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1192 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1193 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1194 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1195 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1196 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1197 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1198 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1199 // Does nothing
1200 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1201 // Does nothing
1202 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1203 // Does nothing
1204 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1205 // Does nothing
1206 array( 'op' => 'null' ),
1207 // Does nothing
1208 ) );
1209
1210 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1211 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1212 $this->assertEquals( 13, count( $status->success ),
1213 "Operation batch has correct success array" );
1214
1215 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
1216 "File does not exist at $fileA" );
1217 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1218 "File does not exist at $fileB" );
1219 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1220 "File does not exist at $fileD" );
1221
1222 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1223 "File exists at $fileC" );
1224 $this->assertEquals( $fileBContents,
1225 $this->backend->getFileContents( array( 'src' => $fileC ) ),
1226 "Correct file contents of $fileC" );
1227 $this->assertEquals( strlen( $fileBContents ),
1228 $this->backend->getFileSize( array( 'src' => $fileC ) ),
1229 "Correct file size of $fileC" );
1230 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1231 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
1232 "Correct file SHA-1 of $fileC" );
1233 }
1234
1235 // concurrency orientated
1236 private function doTestDoOperations2() {
1237 $base = $this->baseStorePath();
1238
1239 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1240 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1241 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1242
1243 $tmpNameA = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1244 file_put_contents( $tmpNameA, $fileAContents );
1245 $tmpNameB = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1246 file_put_contents( $tmpNameB, $fileBContents );
1247 $tmpNameC = TempFSFile::factory( "unittests_", 'txt' )->getPath();
1248 file_put_contents( $tmpNameC, $fileCContents );
1249
1250 $this->filesToPrune[] = $tmpNameA; # avoid file leaking
1251 $this->filesToPrune[] = $tmpNameB; # avoid file leaking
1252 $this->filesToPrune[] = $tmpNameC; # avoid file leaking
1253
1254 $fileA = "$base/unittest-cont1/a/b/fileA.txt";
1255 $fileB = "$base/unittest-cont1/a/b/fileB.txt";
1256 $fileC = "$base/unittest-cont1/a/b/fileC.txt";
1257 $fileD = "$base/unittest-cont1/a/b/fileD.txt";
1258
1259 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1260 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1261 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1262 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1263 $this->prepare( array( 'dir' => dirname( $fileD ) ) );
1264
1265 $status = $this->backend->doOperations( array(
1266 array( 'op' => 'store', 'src' => $tmpNameA, 'dst' => $fileA, 'overwriteSame' => 1 ),
1267 array( 'op' => 'store', 'src' => $tmpNameB, 'dst' => $fileB, 'overwrite' => 1 ),
1268 array( 'op' => 'store', 'src' => $tmpNameC, 'dst' => $fileC, 'overwrite' => 1 ),
1269 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1270 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1271 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1272 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1273 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
1274 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
1275 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
1276 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
1277 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
1278 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
1279 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
1280 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
1281 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
1282 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
1283 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
1284 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
1285 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1286 // Does nothing
1287 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1288 // Does nothing
1289 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
1290 // Does nothing
1291 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
1292 // Does nothing
1293 array( 'op' => 'null' ),
1294 // Does nothing
1295 ) );
1296
1297 $this->assertGoodStatus( $status, "Operation batch succeeded" );
1298 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1299 $this->assertEquals( 16, count( $status->success ),
1300 "Operation batch has correct success array" );
1301
1302 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
1303 "File does not exist at $fileA" );
1304 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1305 "File does not exist at $fileB" );
1306 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1307 "File does not exist at $fileD" );
1308
1309 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1310 "File exists at $fileC" );
1311 $this->assertEquals( $fileBContents,
1312 $this->backend->getFileContents( array( 'src' => $fileC ) ),
1313 "Correct file contents of $fileC" );
1314 $this->assertEquals( strlen( $fileBContents ),
1315 $this->backend->getFileSize( array( 'src' => $fileC ) ),
1316 "Correct file size of $fileC" );
1317 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1318 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
1319 "Correct file SHA-1 of $fileC" );
1320 }
1321
1322 private function doTestDoOperationsFailing() {
1323 $base = $this->baseStorePath();
1324
1325 $fileA = "$base/unittest-cont2/a/b/fileA.txt";
1326 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
1327 $fileB = "$base/unittest-cont2/a/b/fileB.txt";
1328 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
1329 $fileC = "$base/unittest-cont2/a/b/fileC.txt";
1330 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
1331 $fileD = "$base/unittest-cont2/a/b/fileD.txt";
1332
1333 $this->prepare( array( 'dir' => dirname( $fileA ) ) );
1334 $this->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
1335 $this->prepare( array( 'dir' => dirname( $fileB ) ) );
1336 $this->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
1337 $this->prepare( array( 'dir' => dirname( $fileC ) ) );
1338 $this->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
1339
1340 $status = $this->backend->doOperations( array(
1341 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
1342 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (file:<orginal contents>)
1343 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
1344 // Now: A:<A>, B:<B>, C:<A>, D:<empty>
1345 array( 'op' => 'copy', 'src' => $fileB, 'dst' => $fileD, 'overwrite' => 1 ),
1346 // Now: A:<A>, B:<B>, C:<A>, D:<B>
1347 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD ),
1348 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1349 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC, 'overwriteSame' => 1 ),
1350 // Now: A:<A>, B:<B>, C:<A>, D:<empty> (failed)
1351 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileA, 'overwrite' => 1 ),
1352 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1353 array( 'op' => 'delete', 'src' => $fileD ),
1354 // Now: A:<B>, B:<empty>, C:<A>, D:<empty>
1355 array( 'op' => 'null' ),
1356 // Does nothing
1357 ), array( 'force' => 1 ) );
1358
1359 $this->assertNotEquals( array(), $status->errors, "Operation had warnings" );
1360 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
1361 $this->assertEquals( 8, count( $status->success ),
1362 "Operation batch has correct success array" );
1363
1364 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
1365 "File does not exist at $fileB" );
1366 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
1367 "File does not exist at $fileD" );
1368
1369 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileA ) ),
1370 "File does not exist at $fileA" );
1371 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
1372 "File exists at $fileC" );
1373 $this->assertEquals( $fileBContents,
1374 $this->backend->getFileContents( array( 'src' => $fileA ) ),
1375 "Correct file contents of $fileA" );
1376 $this->assertEquals( strlen( $fileBContents ),
1377 $this->backend->getFileSize( array( 'src' => $fileA ) ),
1378 "Correct file size of $fileA" );
1379 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
1380 $this->backend->getFileSha1Base36( array( 'src' => $fileA ) ),
1381 "Correct file SHA-1 of $fileA" );
1382 }
1383
1384 public function testGetFileList() {
1385 $this->backend = $this->singleBackend;
1386 $this->tearDownFiles();
1387 $this->doTestGetFileList();
1388 $this->tearDownFiles();
1389
1390 $this->backend = $this->multiBackend;
1391 $this->tearDownFiles();
1392 $this->doTestGetFileList();
1393 $this->tearDownFiles();
1394 }
1395
1396 private function doTestGetFileList() {
1397 $backendName = $this->backendClass();
1398
1399 $base = $this->baseStorePath();
1400 $files = array(
1401 "$base/unittest-cont1/test1.txt",
1402 "$base/unittest-cont1/test2.txt",
1403 "$base/unittest-cont1/test3.txt",
1404 "$base/unittest-cont1/subdir1/test1.txt",
1405 "$base/unittest-cont1/subdir1/test2.txt",
1406 "$base/unittest-cont1/subdir2/test3.txt",
1407 "$base/unittest-cont1/subdir2/test4.txt",
1408 "$base/unittest-cont1/subdir2/subdir/test1.txt",
1409 "$base/unittest-cont1/subdir2/subdir/test2.txt",
1410 "$base/unittest-cont1/subdir2/subdir/test3.txt",
1411 "$base/unittest-cont1/subdir2/subdir/test4.txt",
1412 "$base/unittest-cont1/subdir2/subdir/test5.txt",
1413 "$base/unittest-cont1/subdir2/subdir/sub/test0.txt",
1414 "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt",
1415 );
1416
1417 // Add the files
1418 $ops = array();
1419 foreach ( $files as $file ) {
1420 $this->prepare( array( 'dir' => dirname( $file ) ) );
1421 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1422 }
1423 $status = $this->backend->doQuickOperations( $ops );
1424 $this->assertGoodStatus( $status,
1425 "Creation of files succeeded ($backendName)." );
1426 $this->assertEquals( true, $status->isOK(),
1427 "Creation of files succeeded with OK status ($backendName)." );
1428
1429 // Expected listing
1430 $expected = array(
1431 "test1.txt",
1432 "test2.txt",
1433 "test3.txt",
1434 "subdir1/test1.txt",
1435 "subdir1/test2.txt",
1436 "subdir2/test3.txt",
1437 "subdir2/test4.txt",
1438 "subdir2/subdir/test1.txt",
1439 "subdir2/subdir/test2.txt",
1440 "subdir2/subdir/test3.txt",
1441 "subdir2/subdir/test4.txt",
1442 "subdir2/subdir/test5.txt",
1443 "subdir2/subdir/sub/test0.txt",
1444 "subdir2/subdir/sub/120-px-file.txt",
1445 );
1446 sort( $expected );
1447
1448 // Actual listing (no trailing slash)
1449 $list = array();
1450 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1451 foreach ( $iter as $file ) {
1452 $list[] = $file;
1453 }
1454 sort( $list );
1455
1456 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1457
1458 // Actual listing (with trailing slash)
1459 $list = array();
1460 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1461 foreach ( $iter as $file ) {
1462 $list[] = $file;
1463 }
1464 sort( $list );
1465
1466 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1467
1468 // Expected listing
1469 $expected = array(
1470 "test1.txt",
1471 "test2.txt",
1472 "test3.txt",
1473 "test4.txt",
1474 "test5.txt",
1475 "sub/test0.txt",
1476 "sub/120-px-file.txt",
1477 );
1478 sort( $expected );
1479
1480 // Actual listing (no trailing slash)
1481 $list = array();
1482 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
1483 foreach ( $iter as $file ) {
1484 $list[] = $file;
1485 }
1486 sort( $list );
1487
1488 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1489
1490 // Actual listing (with trailing slash)
1491 $list = array();
1492 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) );
1493 foreach ( $iter as $file ) {
1494 $list[] = $file;
1495 }
1496 sort( $list );
1497
1498 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1499
1500 // Actual listing (using iterator second time)
1501 $list = array();
1502 foreach ( $iter as $file ) {
1503 $list[] = $file;
1504 }
1505 sort( $list );
1506
1507 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
1508
1509 // Expected listing (top files only)
1510 $expected = array(
1511 "test1.txt",
1512 "test2.txt",
1513 "test3.txt",
1514 "test4.txt",
1515 "test5.txt"
1516 );
1517 sort( $expected );
1518
1519 // Actual listing (top files only)
1520 $list = array();
1521 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
1522 foreach ( $iter as $file ) {
1523 $list[] = $file;
1524 }
1525 sort( $list );
1526
1527 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
1528
1529 foreach ( $files as $file ) { // clean up
1530 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1531 }
1532
1533 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1534 foreach ( $iter as $iter ) {} // no errors
1535 }
1536
1537 public function testGetDirectoryList() {
1538 $this->backend = $this->singleBackend;
1539 $this->tearDownFiles();
1540 $this->doTestGetDirectoryList();
1541 $this->tearDownFiles();
1542
1543 $this->backend = $this->multiBackend;
1544 $this->tearDownFiles();
1545 $this->doTestGetDirectoryList();
1546 $this->tearDownFiles();
1547 }
1548
1549 private function doTestGetDirectoryList() {
1550 $backendName = $this->backendClass();
1551
1552 $base = $this->baseStorePath();
1553 $files = array(
1554 "$base/unittest-cont1/test1.txt",
1555 "$base/unittest-cont1/test2.txt",
1556 "$base/unittest-cont1/test3.txt",
1557 "$base/unittest-cont1/subdir1/test1.txt",
1558 "$base/unittest-cont1/subdir1/test2.txt",
1559 "$base/unittest-cont1/subdir2/test3.txt",
1560 "$base/unittest-cont1/subdir2/test4.txt",
1561 "$base/unittest-cont1/subdir2/subdir/test1.txt",
1562 "$base/unittest-cont1/subdir3/subdir/test2.txt",
1563 "$base/unittest-cont1/subdir4/subdir/test3.txt",
1564 "$base/unittest-cont1/subdir4/subdir/test4.txt",
1565 "$base/unittest-cont1/subdir4/subdir/test5.txt",
1566 "$base/unittest-cont1/subdir4/subdir/sub/test0.txt",
1567 "$base/unittest-cont1/subdir4/subdir/sub/120-px-file.txt",
1568 );
1569
1570 // Add the files
1571 $ops = array();
1572 foreach ( $files as $file ) {
1573 $this->prepare( array( 'dir' => dirname( $file ) ) );
1574 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1575 }
1576 $status = $this->backend->doQuickOperations( $ops );
1577 $this->assertGoodStatus( $status,
1578 "Creation of files succeeded ($backendName)." );
1579 $this->assertEquals( true, $status->isOK(),
1580 "Creation of files succeeded with OK status ($backendName)." );
1581
1582 // Expected listing
1583 $expected = array(
1584 "subdir1",
1585 "subdir2",
1586 "subdir3",
1587 "subdir4",
1588 );
1589 sort( $expected );
1590
1591 $this->assertEquals( true,
1592 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir1" ) ),
1593 "Directory exists in ($backendName)." );
1594 $this->assertEquals( true,
1595 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) ),
1596 "Directory exists in ($backendName)." );
1597 $this->assertEquals( false,
1598 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir2/test1.txt" ) ),
1599 "Directory does not exists in ($backendName)." );
1600
1601 // Actual listing (no trailing slash)
1602 $list = array();
1603 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
1604 foreach ( $iter as $file ) {
1605 $list[] = $file;
1606 }
1607 sort( $list );
1608
1609 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1610
1611 // Actual listing (with trailing slash)
1612 $list = array();
1613 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
1614 foreach ( $iter as $file ) {
1615 $list[] = $file;
1616 }
1617 sort( $list );
1618
1619 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1620
1621 // Expected listing
1622 $expected = array(
1623 "subdir",
1624 );
1625 sort( $expected );
1626
1627 // Actual listing (no trailing slash)
1628 $list = array();
1629 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir2" ) );
1630 foreach ( $iter as $file ) {
1631 $list[] = $file;
1632 }
1633 sort( $list );
1634
1635 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1636
1637 // Actual listing (with trailing slash)
1638 $list = array();
1639 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir2/" ) );
1640 foreach ( $iter as $file ) {
1641 $list[] = $file;
1642 }
1643 sort( $list );
1644
1645 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1646
1647 // Actual listing (using iterator second time)
1648 $list = array();
1649 foreach ( $iter as $file ) {
1650 $list[] = $file;
1651 }
1652 sort( $list );
1653
1654 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
1655
1656 // Expected listing (recursive)
1657 $expected = array(
1658 "subdir1",
1659 "subdir2",
1660 "subdir3",
1661 "subdir4",
1662 "subdir2/subdir",
1663 "subdir3/subdir",
1664 "subdir4/subdir",
1665 "subdir4/subdir/sub",
1666 );
1667 sort( $expected );
1668
1669 // Actual listing (recursive)
1670 $list = array();
1671 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
1672 foreach ( $iter as $file ) {
1673 $list[] = $file;
1674 }
1675 sort( $list );
1676
1677 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1678
1679 // Expected listing (recursive)
1680 $expected = array(
1681 "subdir",
1682 "subdir/sub",
1683 );
1684 sort( $expected );
1685
1686 // Actual listing (recursive)
1687 $list = array();
1688 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir4" ) );
1689 foreach ( $iter as $file ) {
1690 $list[] = $file;
1691 }
1692 sort( $list );
1693
1694 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1695
1696 // Actual listing (recursive, second time)
1697 $list = array();
1698 foreach ( $iter as $file ) {
1699 $list[] = $file;
1700 }
1701 sort( $list );
1702
1703 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1704
1705 foreach ( $files as $file ) { // clean up
1706 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1707 }
1708
1709 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1710 foreach ( $iter as $iter ) {} // no errors
1711 }
1712
1713 public function testLockCalls() {
1714 $this->backend = $this->singleBackend;
1715 $this->doTestLockCalls();
1716 }
1717
1718 private function doTestLockCalls() {
1719 $backendName = $this->backendClass();
1720
1721 for ( $i=0; $i<50; $i++ ) {
1722 $paths = array(
1723 "test1.txt",
1724 "test2.txt",
1725 "test3.txt",
1726 "subdir1",
1727 "subdir1", // duplicate
1728 "subdir1/test1.txt",
1729 "subdir1/test2.txt",
1730 "subdir2",
1731 "subdir2", // duplicate
1732 "subdir2/test3.txt",
1733 "subdir2/test4.txt",
1734 "subdir2/subdir",
1735 "subdir2/subdir/test1.txt",
1736 "subdir2/subdir/test2.txt",
1737 "subdir2/subdir/test3.txt",
1738 "subdir2/subdir/test4.txt",
1739 "subdir2/subdir/test5.txt",
1740 "subdir2/subdir/sub",
1741 "subdir2/subdir/sub/test0.txt",
1742 "subdir2/subdir/sub/120-px-file.txt",
1743 );
1744
1745 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
1746 $this->assertEquals( array(), $status->errors,
1747 "Locking of files succeeded ($backendName)." );
1748 $this->assertEquals( true, $status->isOK(),
1749 "Locking of files succeeded with OK status ($backendName)." );
1750
1751 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
1752 $this->assertEquals( array(), $status->errors,
1753 "Locking of files succeeded ($backendName)." );
1754 $this->assertEquals( true, $status->isOK(),
1755 "Locking of files succeeded with OK status ($backendName)." );
1756
1757 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
1758 $this->assertEquals( array(), $status->errors,
1759 "Locking of files succeeded ($backendName)." );
1760 $this->assertEquals( true, $status->isOK(),
1761 "Locking of files succeeded with OK status ($backendName)." );
1762
1763 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
1764 $this->assertEquals( array(), $status->errors,
1765 "Locking of files succeeded ($backendName)." );
1766 $this->assertEquals( true, $status->isOK(),
1767 "Locking of files succeeded with OK status ($backendName)." );
1768 }
1769 }
1770
1771 // test helper wrapper for backend prepare() function
1772 private function prepare( array $params ) {
1773 return $this->backend->prepare( $params );
1774 }
1775
1776 // test helper wrapper for backend prepare() function
1777 private function create( array $params ) {
1778 $params['op'] = 'create';
1779 return $this->backend->doQuickOperations( array( $params ) );
1780 }
1781
1782 function tearDownFiles() {
1783 foreach ( $this->filesToPrune as $file ) {
1784 @unlink( $file );
1785 }
1786 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' );
1787 foreach ( $containers as $container ) {
1788 $this->deleteFiles( $container );
1789 }
1790 $this->filesToPrune = array();
1791 }
1792
1793 private function deleteFiles( $container ) {
1794 $base = $this->baseStorePath();
1795 $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
1796 if ( $iter ) {
1797 foreach ( $iter as $file ) {
1798 $this->backend->delete( array( 'src' => "$base/$container/$file" ),
1799 array( 'force' => 1, 'nonLocking' => 1 ) );
1800 }
1801 }
1802 $this->backend->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
1803 }
1804
1805 function assertGoodStatus( $status, $msg ) {
1806 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors, 1 ), $msg );
1807 }
1808
1809 function tearDown() {
1810 parent::tearDown();
1811 }
1812 }