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 $base = $this->baseStorePath();
1399
1400 // Should have no errors
1401 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont-notexists" ) );
1402
1403 $files = array(
1404 "$base/unittest-cont1/test1.txt",
1405 "$base/unittest-cont1/test2.txt",
1406 "$base/unittest-cont1/test3.txt",
1407 "$base/unittest-cont1/subdir1/test1.txt",
1408 "$base/unittest-cont1/subdir1/test2.txt",
1409 "$base/unittest-cont1/subdir2/test3.txt",
1410 "$base/unittest-cont1/subdir2/test4.txt",
1411 "$base/unittest-cont1/subdir2/subdir/test1.txt",
1412 "$base/unittest-cont1/subdir2/subdir/test2.txt",
1413 "$base/unittest-cont1/subdir2/subdir/test3.txt",
1414 "$base/unittest-cont1/subdir2/subdir/test4.txt",
1415 "$base/unittest-cont1/subdir2/subdir/test5.txt",
1416 "$base/unittest-cont1/subdir2/subdir/sub/test0.txt",
1417 "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt",
1418 );
1419
1420 // Add the files
1421 $ops = array();
1422 foreach ( $files as $file ) {
1423 $this->prepare( array( 'dir' => dirname( $file ) ) );
1424 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1425 }
1426 $status = $this->backend->doQuickOperations( $ops );
1427 $this->assertGoodStatus( $status,
1428 "Creation of files succeeded ($backendName)." );
1429 $this->assertEquals( true, $status->isOK(),
1430 "Creation of files succeeded with OK status ($backendName)." );
1431
1432 // Expected listing
1433 $expected = array(
1434 "test1.txt",
1435 "test2.txt",
1436 "test3.txt",
1437 "subdir1/test1.txt",
1438 "subdir1/test2.txt",
1439 "subdir2/test3.txt",
1440 "subdir2/test4.txt",
1441 "subdir2/subdir/test1.txt",
1442 "subdir2/subdir/test2.txt",
1443 "subdir2/subdir/test3.txt",
1444 "subdir2/subdir/test4.txt",
1445 "subdir2/subdir/test5.txt",
1446 "subdir2/subdir/sub/test0.txt",
1447 "subdir2/subdir/sub/120-px-file.txt",
1448 );
1449 sort( $expected );
1450
1451 // Actual listing (no trailing slash)
1452 $list = array();
1453 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
1454 foreach ( $iter as $file ) {
1455 $list[] = $file;
1456 }
1457 sort( $list );
1458
1459 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1460
1461 // Actual listing (with trailing slash)
1462 $list = array();
1463 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
1464 foreach ( $iter as $file ) {
1465 $list[] = $file;
1466 }
1467 sort( $list );
1468
1469 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1470
1471 // Expected listing
1472 $expected = array(
1473 "test1.txt",
1474 "test2.txt",
1475 "test3.txt",
1476 "test4.txt",
1477 "test5.txt",
1478 "sub/test0.txt",
1479 "sub/120-px-file.txt",
1480 );
1481 sort( $expected );
1482
1483 // Actual listing (no trailing slash)
1484 $list = array();
1485 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
1486 foreach ( $iter as $file ) {
1487 $list[] = $file;
1488 }
1489 sort( $list );
1490
1491 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1492
1493 // Actual listing (with trailing slash)
1494 $list = array();
1495 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) );
1496 foreach ( $iter as $file ) {
1497 $list[] = $file;
1498 }
1499 sort( $list );
1500
1501 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
1502
1503 // Actual listing (using iterator second time)
1504 $list = array();
1505 foreach ( $iter as $file ) {
1506 $list[] = $file;
1507 }
1508 sort( $list );
1509
1510 $this->assertEquals( $expected, $list, "Correct file listing ($backendName), second iteration." );
1511
1512 // Expected listing (top files only)
1513 $expected = array(
1514 "test1.txt",
1515 "test2.txt",
1516 "test3.txt",
1517 "test4.txt",
1518 "test5.txt"
1519 );
1520 sort( $expected );
1521
1522 // Actual listing (top files only)
1523 $list = array();
1524 $iter = $this->backend->getTopFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
1525 foreach ( $iter as $file ) {
1526 $list[] = $file;
1527 }
1528 sort( $list );
1529
1530 $this->assertEquals( $expected, $list, "Correct top file listing ($backendName)." );
1531
1532 foreach ( $files as $file ) { // clean up
1533 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1534 }
1535
1536 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1537 foreach ( $iter as $iter ) {} // no errors
1538 }
1539
1540 public function testGetDirectoryList() {
1541 $this->backend = $this->singleBackend;
1542 $this->tearDownFiles();
1543 $this->doTestGetDirectoryList();
1544 $this->tearDownFiles();
1545
1546 $this->backend = $this->multiBackend;
1547 $this->tearDownFiles();
1548 $this->doTestGetDirectoryList();
1549 $this->tearDownFiles();
1550 }
1551
1552 private function doTestGetDirectoryList() {
1553 $backendName = $this->backendClass();
1554
1555 $base = $this->baseStorePath();
1556 $files = array(
1557 "$base/unittest-cont1/test1.txt",
1558 "$base/unittest-cont1/test2.txt",
1559 "$base/unittest-cont1/test3.txt",
1560 "$base/unittest-cont1/subdir1/test1.txt",
1561 "$base/unittest-cont1/subdir1/test2.txt",
1562 "$base/unittest-cont1/subdir2/test3.txt",
1563 "$base/unittest-cont1/subdir2/test4.txt",
1564 "$base/unittest-cont1/subdir2/subdir/test1.txt",
1565 "$base/unittest-cont1/subdir3/subdir/test2.txt",
1566 "$base/unittest-cont1/subdir4/subdir/test3.txt",
1567 "$base/unittest-cont1/subdir4/subdir/test4.txt",
1568 "$base/unittest-cont1/subdir4/subdir/test5.txt",
1569 "$base/unittest-cont1/subdir4/subdir/sub/test0.txt",
1570 "$base/unittest-cont1/subdir4/subdir/sub/120-px-file.txt",
1571 );
1572
1573 // Add the files
1574 $ops = array();
1575 foreach ( $files as $file ) {
1576 $this->prepare( array( 'dir' => dirname( $file ) ) );
1577 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
1578 }
1579 $status = $this->backend->doQuickOperations( $ops );
1580 $this->assertGoodStatus( $status,
1581 "Creation of files succeeded ($backendName)." );
1582 $this->assertEquals( true, $status->isOK(),
1583 "Creation of files succeeded with OK status ($backendName)." );
1584
1585 // Expected listing
1586 $expected = array(
1587 "subdir1",
1588 "subdir2",
1589 "subdir3",
1590 "subdir4",
1591 );
1592 sort( $expected );
1593
1594 $this->assertEquals( true,
1595 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir1" ) ),
1596 "Directory exists in ($backendName)." );
1597 $this->assertEquals( true,
1598 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) ),
1599 "Directory exists in ($backendName)." );
1600 $this->assertEquals( false,
1601 $this->backend->directoryExists( array( 'dir' => "$base/unittest-cont1/subdir2/test1.txt" ) ),
1602 "Directory does not exists in ($backendName)." );
1603
1604 // Actual listing (no trailing slash)
1605 $list = array();
1606 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1" ) );
1607 foreach ( $iter as $file ) {
1608 $list[] = $file;
1609 }
1610 sort( $list );
1611
1612 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1613
1614 // Actual listing (with trailing slash)
1615 $list = array();
1616 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
1617 foreach ( $iter as $file ) {
1618 $list[] = $file;
1619 }
1620 sort( $list );
1621
1622 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1623
1624 // Expected listing
1625 $expected = array(
1626 "subdir",
1627 );
1628 sort( $expected );
1629
1630 // Actual listing (no trailing slash)
1631 $list = array();
1632 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir2" ) );
1633 foreach ( $iter as $file ) {
1634 $list[] = $file;
1635 }
1636 sort( $list );
1637
1638 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1639
1640 // Actual listing (with trailing slash)
1641 $list = array();
1642 $iter = $this->backend->getTopDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir2/" ) );
1643 foreach ( $iter as $file ) {
1644 $list[] = $file;
1645 }
1646 sort( $list );
1647
1648 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName)." );
1649
1650 // Actual listing (using iterator second time)
1651 $list = array();
1652 foreach ( $iter as $file ) {
1653 $list[] = $file;
1654 }
1655 sort( $list );
1656
1657 $this->assertEquals( $expected, $list, "Correct top dir listing ($backendName), second iteration." );
1658
1659 // Expected listing (recursive)
1660 $expected = array(
1661 "subdir1",
1662 "subdir2",
1663 "subdir3",
1664 "subdir4",
1665 "subdir2/subdir",
1666 "subdir3/subdir",
1667 "subdir4/subdir",
1668 "subdir4/subdir/sub",
1669 );
1670 sort( $expected );
1671
1672 // Actual listing (recursive)
1673 $list = array();
1674 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/" ) );
1675 foreach ( $iter as $file ) {
1676 $list[] = $file;
1677 }
1678 sort( $list );
1679
1680 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1681
1682 // Expected listing (recursive)
1683 $expected = array(
1684 "subdir",
1685 "subdir/sub",
1686 );
1687 sort( $expected );
1688
1689 // Actual listing (recursive)
1690 $list = array();
1691 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/subdir4" ) );
1692 foreach ( $iter as $file ) {
1693 $list[] = $file;
1694 }
1695 sort( $list );
1696
1697 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1698
1699 // Actual listing (recursive, second time)
1700 $list = array();
1701 foreach ( $iter as $file ) {
1702 $list[] = $file;
1703 }
1704 sort( $list );
1705
1706 $this->assertEquals( $expected, $list, "Correct dir listing ($backendName)." );
1707
1708 foreach ( $files as $file ) { // clean up
1709 $this->backend->doOperation( array( 'op' => 'delete', 'src' => $file ) );
1710 }
1711
1712 $iter = $this->backend->getDirectoryList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
1713 foreach ( $iter as $iter ) {} // no errors
1714 }
1715
1716 public function testLockCalls() {
1717 $this->backend = $this->singleBackend;
1718 $this->doTestLockCalls();
1719 }
1720
1721 private function doTestLockCalls() {
1722 $backendName = $this->backendClass();
1723
1724 for ( $i=0; $i<50; $i++ ) {
1725 $paths = array(
1726 "test1.txt",
1727 "test2.txt",
1728 "test3.txt",
1729 "subdir1",
1730 "subdir1", // duplicate
1731 "subdir1/test1.txt",
1732 "subdir1/test2.txt",
1733 "subdir2",
1734 "subdir2", // duplicate
1735 "subdir2/test3.txt",
1736 "subdir2/test4.txt",
1737 "subdir2/subdir",
1738 "subdir2/subdir/test1.txt",
1739 "subdir2/subdir/test2.txt",
1740 "subdir2/subdir/test3.txt",
1741 "subdir2/subdir/test4.txt",
1742 "subdir2/subdir/test5.txt",
1743 "subdir2/subdir/sub",
1744 "subdir2/subdir/sub/test0.txt",
1745 "subdir2/subdir/sub/120-px-file.txt",
1746 );
1747
1748 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_EX );
1749 $this->assertEquals( array(), $status->errors,
1750 "Locking of files succeeded ($backendName)." );
1751 $this->assertEquals( true, $status->isOK(),
1752 "Locking of files succeeded with OK status ($backendName)." );
1753
1754 $status = $this->backend->lockFiles( $paths, LockManager::LOCK_SH );
1755 $this->assertEquals( array(), $status->errors,
1756 "Locking of files succeeded ($backendName)." );
1757 $this->assertEquals( true, $status->isOK(),
1758 "Locking of files succeeded with OK status ($backendName)." );
1759
1760 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_SH );
1761 $this->assertEquals( array(), $status->errors,
1762 "Locking of files succeeded ($backendName)." );
1763 $this->assertEquals( true, $status->isOK(),
1764 "Locking of files succeeded with OK status ($backendName)." );
1765
1766 $status = $this->backend->unlockFiles( $paths, LockManager::LOCK_EX );
1767 $this->assertEquals( array(), $status->errors,
1768 "Locking of files succeeded ($backendName)." );
1769 $this->assertEquals( true, $status->isOK(),
1770 "Locking of files succeeded with OK status ($backendName)." );
1771 }
1772 }
1773
1774 // test helper wrapper for backend prepare() function
1775 private function prepare( array $params ) {
1776 return $this->backend->prepare( $params );
1777 }
1778
1779 // test helper wrapper for backend prepare() function
1780 private function create( array $params ) {
1781 $params['op'] = 'create';
1782 return $this->backend->doQuickOperations( array( $params ) );
1783 }
1784
1785 function tearDownFiles() {
1786 foreach ( $this->filesToPrune as $file ) {
1787 @unlink( $file );
1788 }
1789 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' );
1790 foreach ( $containers as $container ) {
1791 $this->deleteFiles( $container );
1792 }
1793 $this->filesToPrune = array();
1794 }
1795
1796 private function deleteFiles( $container ) {
1797 $base = $this->baseStorePath();
1798 $iter = $this->backend->getFileList( array( 'dir' => "$base/$container" ) );
1799 if ( $iter ) {
1800 foreach ( $iter as $file ) {
1801 $this->backend->delete( array( 'src' => "$base/$container/$file" ),
1802 array( 'force' => 1, 'nonLocking' => 1 ) );
1803 }
1804 }
1805 $this->backend->clean( array( 'dir' => "$base/$container", 'recursive' => 1 ) );
1806 }
1807
1808 function assertGoodStatus( $status, $msg ) {
1809 $this->assertEquals( print_r( array(), 1 ), print_r( $status->errors, 1 ), $msg );
1810 }
1811
1812 function tearDown() {
1813 parent::tearDown();
1814 }
1815 }