* Modified StoreBatchTest and FileBackendTest to allow specifying a registered backen...
[lhc/web/wiklou.git] / tests / phpunit / includes / filerepo / FileBackendTest.php
1 <?php
2
3 /**
4 * @group FileRepo
5 */
6 class FileBackendTest extends MediaWikiTestCase {
7 private $backend, $multiBackend;
8 private $filesToPrune;
9
10 function setUp() {
11 global $wgFileBackends;
12 parent::setUp();
13 $tmpDir = wfTempDir() . '/file-backend-test-' . time() . '-' . mt_rand();
14 if ( $this->getCliArg( 'use-filebackend=' ) ) {
15 $name = $this->getCliArg( 'use-filebackend=' );
16 $useConfig = array();
17 foreach ( $wgFileBackends as $conf ) {
18 if ( $conf['name'] == $name ) {
19 $useConfig = $conf;
20 }
21 }
22 $useConfig['name'] = 'localtesting'; // swap name
23 $this->singleBackend = new $conf['class']( $useConfig );
24 } else {
25 $this->singleBackend = new FSFileBackend( array(
26 'name' => 'localtesting',
27 'lockManager' => 'fsLockManager',
28 'containerPaths' => array(
29 'unittest-cont1' => "$tmpDir/localtesting/unittest-cont1",
30 'unittest-cont2' => "$tmpDir/localtesting/unittest-cont2" )
31 ) );
32 }
33 $this->multiBackend = new FileBackendMultiWrite( array(
34 'name' => 'localtesting',
35 'lockManager' => 'fsLockManager',
36 'backends' => array(
37 array(
38 'name' => 'localmutlitesting1',
39 'class' => 'FSFileBackend',
40 'lockManager' => 'nullLockManager',
41 'containerPaths' => array(
42 'unittest-cont1' => "$tmpDir/localtestingmulti1/cont1",
43 'unittest-cont2' => "$tmpDir/localtestingmulti1/unittest-cont2" ),
44 'isMultiMaster' => false
45 ),
46 array(
47 'name' => 'localmutlitesting2',
48 'class' => 'FSFileBackend',
49 'lockManager' => 'nullLockManager',
50 'containerPaths' => array(
51 'unittest-cont1' => "$tmpDir/localtestingmulti2/cont1",
52 'unittest-cont2' => "$tmpDir/localtestingmulti2/unittest-cont2" ),
53 'isMultiMaster' => true
54 )
55 )
56 ) );
57 $this->filesToPrune = array();
58 }
59
60 private function baseStorePath() {
61 return 'mwstore://localtesting';
62 }
63
64 private function backendClass() {
65 return get_class( $this->backend );
66 }
67
68 /**
69 * @dataProvider provider_testStore
70 */
71 public function testStore( $op, $source, $dest ) {
72 $this->filesToPrune[] = $source;
73
74 $this->backend = $this->singleBackend;
75 $this->tearDownFiles();
76 $this->doTestStore( $op, $source, $dest );
77 $this->tearDownFiles();
78
79 $this->backend = $this->multiBackend;
80 $this->tearDownFiles();
81 $this->doTestStore( $op, $source, $dest );
82 $this->tearDownFiles();
83 }
84
85 function doTestStore( $op, $source, $dest ) {
86 $backendName = $this->backendClass();
87
88 $this->backend->prepare( array( 'dir' => dirname( $dest ) ) );
89
90 file_put_contents( $source, "Unit test file" );
91 $status = $this->backend->doOperation( $op );
92
93 $this->assertEquals( array(), $status->errors,
94 "Store from $source to $dest succeeded without warnings ($backendName)." );
95 $this->assertEquals( true, $status->isOK(),
96 "Store from $source to $dest succeeded ($backendName)." );
97 $this->assertEquals( array( 0 => true ), $status->success,
98 "Store from $source to $dest has proper 'success' field in Status ($backendName)." );
99 $this->assertEquals( true, file_exists( $source ),
100 "Source file $source still exists ($backendName)." );
101 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
102 "Destination file $dest exists ($backendName)." );
103
104 $this->assertEquals( filesize( $source ),
105 $this->backend->getFileSize( array( 'src' => $dest ) ),
106 "Destination file $dest has correct size ($backendName)." );
107
108 $props1 = FSFile::getPropsFromPath( $source );
109 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
110 $this->assertEquals( $props1, $props2,
111 "Source and destination have the same props ($backendName)." );
112 }
113
114 public function provider_testStore() {
115 $cases = array();
116
117 $tmpName = TempFSFile::factory( "unittests_", 'txt' )->getPath();
118 $toPath = $this->baseStorePath() . '/unittest-cont1/fun/obj1.txt';
119 $op = array( 'op' => 'store', 'src' => $tmpName, 'dst' => $toPath );
120 $cases[] = array(
121 $op, // operation
122 $tmpName, // source
123 $toPath, // dest
124 );
125
126 $op['overwrite'] = true;
127 $cases[] = array(
128 $op, // operation
129 $tmpName, // source
130 $toPath, // dest
131 );
132
133 // @TODO: test overwriteSame
134
135 return $cases;
136 }
137
138 /**
139 * @dataProvider provider_testCopy
140 */
141 public function testCopy( $op, $source, $dest ) {
142 $this->backend = $this->singleBackend;
143 $this->tearDownFiles();
144 $this->doTestCopy( $op, $source, $dest );
145 $this->tearDownFiles();
146
147 $this->backend = $this->multiBackend;
148 $this->tearDownFiles();
149 $this->doTestCopy( $op, $source, $dest );
150 $this->tearDownFiles();
151 }
152
153 function doTestCopy( $op, $source, $dest ) {
154 $backendName = $this->backendClass();
155
156 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
157 $this->backend->prepare( array( 'dir' => dirname( $dest ) ) );
158
159 $status = $this->backend->doOperation(
160 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
161 $this->assertEquals( true, $status->isOK(),
162 "Creation of file at $source succeeded ($backendName)." );
163
164 $status = $this->backend->doOperation( $op );
165 $this->assertEquals( array(), $status->errors,
166 "Copy from $source to $dest succeeded without warnings ($backendName)." );
167 $this->assertEquals( true, $status->isOK(),
168 "Copy from $source to $dest succeeded ($backendName)." );
169 $this->assertEquals( array( 0 => true ), $status->success,
170 "Copy from $source to $dest has proper 'success' field in Status ($backendName)." );
171 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $source ) ),
172 "Source file $source still exists ($backendName)." );
173 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
174 "Destination file $dest exists after copy ($backendName)." );
175
176 $this->assertEquals(
177 $this->backend->getFileSize( array( 'src' => $source ) ),
178 $this->backend->getFileSize( array( 'src' => $dest ) ),
179 "Destination file $dest has correct size ($backendName)." );
180
181 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
182 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
183 $this->assertEquals( $props1, $props2,
184 "Source and destination have the same props ($backendName)." );
185 }
186
187 public function provider_testCopy() {
188 $cases = array();
189
190 $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
191 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
192
193 $op = array( 'op' => 'copy', 'src' => $source, 'dst' => $dest );
194 $cases[] = array(
195 $op, // operation
196 $source, // source
197 $dest, // dest
198 );
199
200 $op['overwrite'] = true;
201 $cases[] = array(
202 $op, // operation
203 $source, // source
204 $dest, // dest
205 );
206
207 return $cases;
208 }
209
210 /**
211 * @dataProvider provider_testMove
212 */
213 public function testMove( $op, $source, $dest ) {
214 $this->backend = $this->singleBackend;
215 $this->tearDownFiles();
216 $this->doTestMove( $op, $source, $dest );
217 $this->tearDownFiles();
218
219 $this->backend = $this->multiBackend;
220 $this->tearDownFiles();
221 $this->doTestMove( $op, $source, $dest );
222 $this->tearDownFiles();
223 }
224
225 private function doTestMove( $op, $source, $dest ) {
226 $backendName = $this->backendClass();
227
228 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
229 $this->backend->prepare( array( 'dir' => dirname( $dest ) ) );
230
231 $status = $this->backend->doOperation(
232 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
233 $this->assertEquals( true, $status->isOK(),
234 "Creation of file at $source succeeded ($backendName)." );
235
236 $status = $this->backend->doOperation( $op );
237 $this->assertEquals( array(), $status->errors,
238 "Move from $source to $dest succeeded without warnings ($backendName)." );
239 $this->assertEquals( true, $status->isOK(),
240 "Move from $source to $dest succeeded ($backendName)." );
241 $this->assertEquals( array( 0 => true ), $status->success,
242 "Move from $source to $dest has proper 'success' field in Status ($backendName)." );
243 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
244 "Source file $source does not still exists ($backendName)." );
245 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
246 "Destination file $dest exists after move ($backendName)." );
247
248 $this->assertNotEquals(
249 $this->backend->getFileSize( array( 'src' => $source ) ),
250 $this->backend->getFileSize( array( 'src' => $dest ) ),
251 "Destination file $dest has correct size ($backendName)." );
252
253 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
254 $props2 = $this->backend->getFileProps( array( 'src' => $dest ) );
255 $this->assertEquals( false, $props1['fileExists'],
256 "Source file does not exist accourding to props ($backendName)." );
257 $this->assertEquals( true, $props2['fileExists'],
258 "Destination file exists accourding to props ($backendName)." );
259 }
260
261 public function provider_testMove() {
262 $cases = array();
263
264 $source = $this->baseStorePath() . '/unittest-cont1/file.txt';
265 $dest = $this->baseStorePath() . '/unittest-cont2/fileMoved.txt';
266
267 $op = array( 'op' => 'move', 'src' => $source, 'dst' => $dest );
268 $cases[] = array(
269 $op, // operation
270 $source, // source
271 $dest, // dest
272 );
273
274 $op['overwrite'] = true;
275 $cases[] = array(
276 $op, // operation
277 $source, // source
278 $dest, // dest
279 );
280
281 return $cases;
282 }
283
284 /**
285 * @dataProvider provider_testDelete
286 */
287 public function testDelete( $op, $source, $withSource, $okStatus ) {
288 $this->backend = $this->singleBackend;
289 $this->tearDownFiles();
290 $this->doTestDelete( $op, $source, $withSource, $okStatus );
291 $this->tearDownFiles();
292
293 $this->backend = $this->multiBackend;
294 $this->tearDownFiles();
295 $this->doTestDelete( $op, $source, $withSource, $okStatus );
296 $this->tearDownFiles();
297 }
298
299 private function doTestDelete( $op, $source, $withSource, $okStatus ) {
300 $backendName = $this->backendClass();
301
302 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
303
304 if ( $withSource ) {
305 $status = $this->backend->doOperation(
306 array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
307 $this->assertEquals( true, $status->isOK(),
308 "Creation of file at $source succeeded ($backendName)." );
309 }
310
311 $status = $this->backend->doOperation( $op );
312 if ( $okStatus ) {
313 $this->assertEquals( array(), $status->errors,
314 "Deletion of file at $source succeeded without warnings ($backendName)." );
315 $this->assertEquals( true, $status->isOK(),
316 "Deletion of file at $source succeeded ($backendName)." );
317 $this->assertEquals( array( 0 => true ), $status->success,
318 "Deletion of file at $source has proper 'success' field in Status ($backendName)." );
319 } else {
320 $this->assertEquals( false, $status->isOK(),
321 "Deletion of file at $source failed ($backendName)." );
322 }
323
324 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $source ) ),
325 "Source file $source does not exist after move ($backendName)." );
326
327 $this->assertFalse(
328 $this->backend->getFileSize( array( 'src' => $source ) ),
329 "Source file $source has correct size (false) ($backendName)." );
330
331 $props1 = $this->backend->getFileProps( array( 'src' => $source ) );
332 $this->assertFalse( $props1['fileExists'],
333 "Source file $source does not exist according to props ($backendName)." );
334 }
335
336 public function provider_testDelete() {
337 $cases = array();
338
339 $source = $this->baseStorePath() . '/unittest-cont1/myfacefile.txt';
340
341 $op = array( 'op' => 'delete', 'src' => $source );
342 $cases[] = array(
343 $op, // operation
344 $source, // source
345 true, // with source
346 true // succeeds
347 );
348
349 $cases[] = array(
350 $op, // operation
351 $source, // source
352 false, // without source
353 false // fails
354 );
355
356 $op['ignoreMissingSource'] = true;
357 $cases[] = array(
358 $op, // operation
359 $source, // source
360 false, // without source
361 true // succeeds
362 );
363
364 return $cases;
365 }
366
367 /**
368 * @dataProvider provider_testCreate
369 */
370 public function testCreate( $op, $dest, $alreadyExists, $okStatus, $newSize ) {
371 $this->backend = $this->singleBackend;
372 $this->tearDownFiles();
373 $this->doTestCreate( $op, $dest, $alreadyExists, $okStatus, $newSize );
374 $this->tearDownFiles();
375
376 $this->backend = $this->multiBackend;
377 $this->tearDownFiles();
378 $this->doTestCreate( $op, $dest, $alreadyExists, $okStatus, $newSize );
379 $this->tearDownFiles();
380 }
381
382 private function doTestCreate( $op, $dest, $alreadyExists, $okStatus, $newSize ) {
383 $backendName = $this->backendClass();
384
385 $this->backend->prepare( array( 'dir' => dirname( $dest ) ) );
386
387 $oldText = 'blah...blah...waahwaah';
388 if ( $alreadyExists ) {
389 $status = $this->backend->doOperation(
390 array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
391 $this->assertEquals( true, $status->isOK(),
392 "Creation of file at $dest succeeded ($backendName)." );
393 }
394
395 $status = $this->backend->doOperation( $op );
396 if ( $okStatus ) {
397 $this->assertEquals( array(), $status->errors,
398 "Creation of file at $dest succeeded without warnings ($backendName)." );
399 $this->assertEquals( true, $status->isOK(),
400 "Creation of file at $dest succeeded ($backendName)." );
401 $this->assertEquals( array( 0 => true ), $status->success,
402 "Creation of file at $dest has proper 'success' field in Status ($backendName)." );
403 } else {
404 $this->assertEquals( false, $status->isOK(),
405 "Creation of file at $dest failed ($backendName)." );
406 }
407
408 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $dest ) ),
409 "Destination file $dest exists after creation ($backendName)." );
410
411 $props1 = $this->backend->getFileProps( array( 'src' => $dest ) );
412 $this->assertEquals( true, $props1['fileExists'],
413 "Destination file $dest exists according to props ($backendName)." );
414 if ( $okStatus ) { // file content is what we saved
415 $this->assertEquals( $newSize, $props1['size'],
416 "Destination file $dest has expected size according to props ($backendName)." );
417 $this->assertEquals( $newSize,
418 $this->backend->getFileSize( array( 'src' => $dest ) ),
419 "Destination file $dest has correct size ($backendName)." );
420 } else { // file content is some other previous text
421 $this->assertEquals( strlen( $oldText ), $props1['size'],
422 "Destination file $dest has original size according to props ($backendName)." );
423 $this->assertEquals( strlen( $oldText ),
424 $this->backend->getFileSize( array( 'src' => $dest ) ),
425 "Destination file $dest has original size according to props ($backendName)." );
426 }
427 }
428
429 /**
430 * @dataProvider provider_testCreate
431 */
432 public function provider_testCreate() {
433 $cases = array();
434
435 $source = $this->baseStorePath() . '/unittest-cont2/myspacefile.txt';
436
437 $dummyText = 'hey hey';
438 $op = array( 'op' => 'create', 'content' => $dummyText, 'dst' => $source );
439 $cases[] = array(
440 $op, // operation
441 $source, // source
442 false, // no dest already exists
443 true, // succeeds
444 strlen( $dummyText )
445 );
446
447 $cases[] = array(
448 $op, // operation
449 $source, // source
450 true, // dest already exists
451 false, // fails
452 strlen( $dummyText )
453 );
454
455 $op['overwrite'] = true;
456 $cases[] = array(
457 $op, // operation
458 $source, // source
459 true, // dest already exists
460 true, // succeeds
461 strlen( $dummyText )
462 );
463
464 return $cases;
465 }
466
467 /**
468 * @dataProvider provider_testConcatenate
469 */
470 public function testConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
471 $this->filesToPrune[] = $op['dst'];
472
473 $this->backend = $this->singleBackend;
474 $this->tearDownFiles();
475 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
476 $this->tearDownFiles();
477
478 $this->backend = $this->multiBackend;
479 $this->tearDownFiles();
480 $this->doTestConcatenate( $op, $srcs, $srcsContent, $alreadyExists, $okStatus );
481 $this->tearDownFiles();
482 }
483
484 public function doTestConcatenate( $params, $srcs, $srcsContent, $alreadyExists, $okStatus ) {
485 $backendName = $this->backendClass();
486
487 $expContent = '';
488 // Create sources
489 $ops = array();
490 foreach ( $srcs as $i => $source ) {
491 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
492 $ops[] = array(
493 'op' => 'create', // operation
494 'dst' => $source, // source
495 'content' => $srcsContent[$i]
496 );
497 $expContent .= $srcsContent[$i];
498 }
499 $status = $this->backend->doOperations( $ops );
500
501 $this->assertEquals( true, $status->isOK(),
502 "Creation of source files succeeded ($backendName)." );
503
504 $dest = $params['dst'];
505 if ( $alreadyExists ) {
506 $ok = file_put_contents( $dest, 'blah...blah...waahwaah' ) !== false;
507 $this->assertEquals( true, $ok,
508 "Creation of file at $dest succeeded ($backendName)." );
509 } else {
510 $ok = file_put_contents( $dest, '' ) !== false;
511 $this->assertEquals( true, $ok,
512 "Creation of 0-byte file at $dest succeeded ($backendName)." );
513 }
514
515 // Combine the files into one
516 $status = $this->backend->concatenate( $params );
517 if ( $okStatus ) {
518 $this->assertEquals( array(), $status->errors,
519 "Creation of concat file at $dest succeeded without warnings ($backendName)." );
520 $this->assertEquals( true, $status->isOK(),
521 "Creation of concat file at $dest succeeded ($backendName)." );
522 } else {
523 $this->assertEquals( false, $status->isOK(),
524 "Creation of concat file at $dest failed ($backendName)." );
525 }
526
527 if ( $okStatus ) {
528 $this->assertEquals( true, is_file( $dest ),
529 "Dest concat file $dest exists after creation ($backendName)." );
530 } else {
531 $this->assertEquals( true, is_file( $dest ),
532 "Dest concat file $dest exists after failed creation ($backendName)." );
533 }
534
535 $contents = file_get_contents( $dest );
536 $this->assertNotEquals( false, $contents, "File at $dest exists ($backendName)." );
537
538 if ( $okStatus ) {
539 $this->assertEquals( $expContent, $contents,
540 "Concat file at $dest has correct contents ($backendName)." );
541 } else {
542 $this->assertNotEquals( $expContent, $contents,
543 "Concat file at $dest has correct contents ($backendName)." );
544 }
545 }
546
547 function provider_testConcatenate() {
548 $cases = array();
549
550 $rand = mt_rand( 0, 2000000000 ) . time();
551 $dest = wfTempDir() . "/randomfile!$rand.txt";
552 $srcs = array(
553 $this->baseStorePath() . '/unittest-cont1/file1.txt',
554 $this->baseStorePath() . '/unittest-cont1/file2.txt',
555 $this->baseStorePath() . '/unittest-cont1/file3.txt',
556 $this->baseStorePath() . '/unittest-cont1/file4.txt',
557 $this->baseStorePath() . '/unittest-cont1/file5.txt',
558 $this->baseStorePath() . '/unittest-cont1/file6.txt',
559 $this->baseStorePath() . '/unittest-cont1/file7.txt',
560 $this->baseStorePath() . '/unittest-cont1/file8.txt',
561 $this->baseStorePath() . '/unittest-cont1/file9.txt',
562 $this->baseStorePath() . '/unittest-cont1/file10.txt'
563 );
564 $content = array(
565 'egfage',
566 'ageageag',
567 'rhokohlr',
568 'shgmslkg',
569 'kenga',
570 'owagmal',
571 'kgmae',
572 'g eak;g',
573 'lkaem;a',
574 'legma'
575 );
576 $params = array( 'srcs' => $srcs, 'dst' => $dest );
577
578 $cases[] = array(
579 $params, // operation
580 $srcs, // sources
581 $content, // content for each source
582 false, // no dest already exists
583 true, // succeeds
584 );
585
586 $cases[] = array(
587 $params, // operation
588 $srcs, // sources
589 $content, // content for each source
590 true, // dest already exists
591 false, // succeeds
592 );
593
594 return $cases;
595 }
596
597 /**
598 * @dataProvider provider_testGetFileContents
599 */
600 public function testGetFileContents( $src, $content ) {
601 $this->backend = $this->singleBackend;
602 $this->tearDownFiles();
603 $this->doTestGetFileContents( $src, $content );
604 $this->tearDownFiles();
605
606 $this->backend = $this->multiBackend;
607 $this->tearDownFiles();
608 $this->doTestGetFileContents( $src, $content );
609 $this->tearDownFiles();
610 }
611
612 /**
613 * @dataProvider provider_testGetFileContents
614 */
615 public function doTestGetFileContents( $source, $content ) {
616 $backendName = $this->backendClass();
617
618 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
619
620 $status = $this->backend->doOperation(
621 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
622 $this->assertEquals( array(), $status->errors,
623 "Creation of file at $source succeeded ($backendName)." );
624 $this->assertEquals( true, $status->isOK(),
625 "Creation of file at $source succeeded with OK status ($backendName)." );
626
627 $newContents = $this->backend->getFileContents( array( 'src' => $source ) );
628 $this->assertNotEquals( false, $newContents,
629 "Read of file at $source succeeded ($backendName)." );
630
631 $this->assertEquals( $content, $newContents,
632 "Contents read match data at $source ($backendName)." );
633 }
634
635 function provider_testGetFileContents() {
636 $cases = array();
637
638 $base = $this->baseStorePath();
639 $cases[] = array( "$base/unittest-cont1/b/z/some_file.txt", "some file contents" );
640 $cases[] = array( "$base/unittest-cont1/b/some-other_file.txt", "more file contents" );
641
642 return $cases;
643 }
644
645 /**
646 * @dataProvider provider_testGetLocalCopy
647 */
648 public function testGetLocalCopy( $src, $content ) {
649 $this->backend = $this->singleBackend;
650 $this->tearDownFiles();
651 $this->doTestGetLocalCopy( $src, $content );
652 $this->tearDownFiles();
653
654 $this->backend = $this->multiBackend;
655 $this->tearDownFiles();
656 $this->doTestGetLocalCopy( $src, $content );
657 $this->tearDownFiles();
658 }
659
660 public function doTestGetLocalCopy( $source, $content ) {
661 $backendName = $this->backendClass();
662
663 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
664
665 $status = $this->backend->doOperation(
666 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
667 $this->assertEquals( true, $status->isOK(),
668 "Creation of file at $source succeeded ($backendName)." );
669
670 $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
671 $this->assertNotNull( $tmpFile,
672 "Creation of local copy of $source succeeded ($backendName)." );
673
674 $contents = file_get_contents( $tmpFile->getPath() );
675 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
676 }
677
678 function provider_testGetLocalCopy() {
679 $cases = array();
680
681 $base = $this->baseStorePath();
682 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
683 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
684
685 return $cases;
686 }
687
688 /**
689 * @dataProvider provider_testGetLocalReference
690 */
691 public function testGetLocalReference( $src, $content ) {
692 $this->backend = $this->singleBackend;
693 $this->tearDownFiles();
694 $this->doTestGetLocalReference( $src, $content );
695 $this->tearDownFiles();
696
697 $this->backend = $this->multiBackend;
698 $this->tearDownFiles();
699 $this->doTestGetLocalReference( $src, $content );
700 $this->tearDownFiles();
701 }
702
703 private function doTestGetLocalReference( $source, $content ) {
704 $backendName = $this->backendClass();
705
706 $this->backend->prepare( array( 'dir' => dirname( $source ) ) );
707
708 $status = $this->backend->doOperation(
709 array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
710 $this->assertEquals( true, $status->isOK(),
711 "Creation of file at $source succeeded ($backendName)." );
712
713 $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
714 $this->assertNotNull( $tmpFile,
715 "Creation of local copy of $source succeeded ($backendName)." );
716
717 $contents = file_get_contents( $tmpFile->getPath() );
718 $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." );
719 }
720
721 function provider_testGetLocalReference() {
722 $cases = array();
723
724 $base = $this->baseStorePath();
725 $cases[] = array( "$base/unittest-cont1/a/z/some_file.txt", "some file contents" );
726 $cases[] = array( "$base/unittest-cont1/a/some-other_file.txt", "more file contents" );
727
728 return $cases;
729 }
730
731 /**
732 * @dataProvider provider_testPrepareAndClean
733 */
734 public function testPrepareAndClean( $path, $isOK ) {
735 $this->backend = $this->singleBackend;
736 $this->doTestPrepareAndClean( $path, $isOK );
737
738 $this->backend = $this->multiBackend;
739 $this->doTestPrepareAndClean( $path, $isOK );
740 }
741
742 function provider_testPrepareAndClean() {
743 $base = $this->baseStorePath();
744 return array(
745 array( "$base/unittest-cont1/a/z/some_file1.txt", true ),
746 array( "$base/unittest-cont2/a/z/some_file2.txt", true ),
747 # Specific to FS backend with no basePath field set
748 #array( "$base/unittest-cont3/a/z/some_file3.txt", false ),
749 );
750 }
751
752 function doTestPrepareAndClean( $path, $isOK ) {
753 $backendName = $this->backendClass();
754
755 $status = $this->backend->prepare( array( 'dir' => $path ) );
756 if ( $isOK ) {
757 $this->assertEquals( array(), $status->errors,
758 "Preparing dir $path succeeded without warnings ($backendName)." );
759 $this->assertEquals( true, $status->isOK(),
760 "Preparing dir $path succeeded ($backendName)." );
761 } else {
762 $this->assertEquals( false, $status->isOK(),
763 "Preparing dir $path failed ($backendName)." );
764 }
765
766 $status = $this->backend->clean( array( 'dir' => $path ) );
767 if ( $isOK ) {
768 $this->assertEquals( array(), $status->errors,
769 "Cleaning dir $path succeeded without warnings ($backendName)." );
770 $this->assertEquals( true, $status->isOK(),
771 "Cleaning dir $path succeeded ($backendName)." );
772 } else {
773 $this->assertEquals( false, $status->isOK(),
774 "Cleaning dir $path failed ($backendName)." );
775 }
776 }
777
778 // @TODO: testSecure
779
780 public function testDoOperations() {
781 $this->backend = $this->singleBackend;
782 $this->doTestDoOperations();
783
784 $this->backend = $this->multiBackend;
785 $this->doTestDoOperations();
786 }
787
788 function doTestDoOperations() {
789 $base = $this->baseStorePath();
790
791 $fileA = "$base/unittest-cont1/a/b/fileA.txt";
792 $fileAContents = '3tqtmoeatmn4wg4qe-mg3qt3 tq';
793 $fileB = "$base/unittest-cont1/a/b/fileB.txt";
794 $fileBContents = 'g-jmq3gpqgt3qtg q3GT ';
795 $fileC = "$base/unittest-cont1/a/b/fileC.txt";
796 $fileCContents = 'eigna[ogmewt 3qt g3qg flew[ag';
797 $fileD = "$base/unittest-cont1/a/b/fileD.txt";
798
799 $this->backend->prepare( array( 'dir' => dirname( $fileA ) ) );
800 $this->backend->create( array( 'dst' => $fileA, 'content' => $fileAContents ) );
801 $this->backend->prepare( array( 'dir' => dirname( $fileB ) ) );
802 $this->backend->create( array( 'dst' => $fileB, 'content' => $fileBContents ) );
803 $this->backend->prepare( array( 'dir' => dirname( $fileC ) ) );
804 $this->backend->create( array( 'dst' => $fileC, 'content' => $fileCContents ) );
805
806 $status = $this->backend->doOperations( array(
807 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC, 'overwrite' => 1 ),
808 // Now: A:<A>, B:<B>, C:<A>, D:<D> (file:<orginal contents>)
809 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileA, 'overwriteSame' => 1 ),
810 // Now: A:<A>, B:<B>, C:<A>, D:<D>
811 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileD, 'overwrite' => 1 ),
812 // Now: A:<A>, B:<B>, C:<empty>, D:<A>
813 array( 'op' => 'move', 'src' => $fileB, 'dst' => $fileC ),
814 // Now: A:<A>, B:<empty>, C:<B>, D:<A>
815 array( 'op' => 'move', 'src' => $fileD, 'dst' => $fileA, 'overwriteSame' => 1 ),
816 // Now: A:<A>, B:<empty>, C:<B>, D:<empty>
817 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileA, 'overwrite' => 1 ),
818 // Now: A:<B>, B:<empty>, C:<empty>, D:<empty>
819 array( 'op' => 'copy', 'src' => $fileA, 'dst' => $fileC ),
820 // Now: A:<B>, B:<empty>, C:<B>, D:<empty>
821 array( 'op' => 'move', 'src' => $fileA, 'dst' => $fileC, 'overwriteSame' => 1 ),
822 // Now: A:<empty>, B:<empty>, C:<B>, D:<empty>
823 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
824 // Does nothing
825 array( 'op' => 'copy', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
826 // Does nothing
827 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwrite' => 1 ),
828 // Does nothing
829 array( 'op' => 'move', 'src' => $fileC, 'dst' => $fileC, 'overwriteSame' => 1 ),
830 // Does nothing
831 ) );
832
833 $this->assertEquals( array(), $status->errors, "Operation batch succeeded" );
834 $this->assertEquals( true, $status->isOK(), "Operation batch succeeded" );
835 $this->assertEquals( 12, count( $status->success ),
836 "Operation batch has correct success array" );
837
838 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileA ) ),
839 "File does not exist at $fileA" );
840 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileB ) ),
841 "File does not exist at $fileB" );
842 $this->assertEquals( false, $this->backend->fileExists( array( 'src' => $fileD ) ),
843 "File does not exist at $fileD" );
844
845 $this->assertEquals( true, $this->backend->fileExists( array( 'src' => $fileC ) ),
846 "File exists at $fileC" );
847 $this->assertEquals( $fileBContents,
848 $this->backend->getFileContents( array( 'src' => $fileC ) ),
849 "Correct file contents of $fileC" );
850 $this->assertEquals( strlen( $fileBContents ),
851 $this->backend->getFileSize( array( 'src' => $fileC ) ),
852 "Correct file size of $fileC" );
853 $this->assertEquals( wfBaseConvert( sha1( $fileBContents ), 16, 36, 31 ),
854 $this->backend->getFileSha1Base36( array( 'src' => $fileC ) ),
855 "Correct file SHA-1 of $fileC" );
856
857 // @TODO: test some cases where the ops should fail
858 }
859
860 public function testGetFileList() {
861 $this->backend = $this->singleBackend;
862 $this->tearDownFiles();
863 $this->doTestGetFileList();
864 $this->tearDownFiles();
865
866 $this->backend = $this->multiBackend;
867 $this->tearDownFiles();
868 $this->doTestGetFileList();
869 $this->tearDownFiles();
870 }
871
872 private function doTestGetFileList() {
873 $backendName = $this->backendClass();
874
875 $base = $this->baseStorePath();
876 $files = array(
877 "$base/unittest-cont1/test1.txt",
878 "$base/unittest-cont1/test2.txt",
879 "$base/unittest-cont1/test3.txt",
880 "$base/unittest-cont1/subdir1/test1.txt",
881 "$base/unittest-cont1/subdir1/test2.txt",
882 "$base/unittest-cont1/subdir2/test3.txt",
883 "$base/unittest-cont1/subdir2/test4.txt",
884 "$base/unittest-cont1/subdir2/subdir/test1.txt",
885 "$base/unittest-cont1/subdir2/subdir/test2.txt",
886 "$base/unittest-cont1/subdir2/subdir/test3.txt",
887 "$base/unittest-cont1/subdir2/subdir/test4.txt",
888 "$base/unittest-cont1/subdir2/subdir/test5.txt",
889 "$base/unittest-cont1/subdir2/subdir/sub/test0.txt",
890 "$base/unittest-cont1/subdir2/subdir/sub/120-px-file.txt",
891 );
892
893 // Add the files
894 $ops = array();
895 foreach ( $files as $file ) {
896 $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file );
897 $this->backend->prepare( array( 'dir' => dirname( $file ) ) );
898 }
899 $status = $this->backend->doOperations( $ops );
900 $this->assertEquals( array(), $status->errors,
901 "Creation of files succeeded ($backendName)." );
902 $this->assertEquals( true, $status->isOK(),
903 "Creation of files succeeded with OK status ($backendName)." );
904
905 // Expected listing
906 $expected = array(
907 "test1.txt",
908 "test2.txt",
909 "test3.txt",
910 "subdir1/test1.txt",
911 "subdir1/test2.txt",
912 "subdir2/test3.txt",
913 "subdir2/test4.txt",
914 "subdir2/subdir/test1.txt",
915 "subdir2/subdir/test2.txt",
916 "subdir2/subdir/test3.txt",
917 "subdir2/subdir/test4.txt",
918 "subdir2/subdir/test5.txt",
919 "subdir2/subdir/sub/test0.txt",
920 "subdir2/subdir/sub/120-px-file.txt",
921 );
922 sort( $expected );
923
924 // Actual listing (no trailing slash)
925 $list = array();
926 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1" ) );
927 foreach ( $iter as $file ) {
928 $list[] = $file;
929 }
930 sort( $list );
931
932 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
933
934 // Actual listing (with trailing slash)
935 $list = array();
936 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/" ) );
937 foreach ( $iter as $file ) {
938 $list[] = $file;
939 }
940 sort( $list );
941
942 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
943
944 // Expected listing
945 $expected = array(
946 "test1.txt",
947 "test2.txt",
948 "test3.txt",
949 "test4.txt",
950 "test5.txt",
951 "sub/test0.txt",
952 "sub/120-px-file.txt",
953 );
954 sort( $expected );
955
956 // Actual listing (no trailing slash)
957 $list = array();
958 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir" ) );
959 foreach ( $iter as $file ) {
960 $list[] = $file;
961 }
962 sort( $list );
963
964 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
965
966 // Actual listing (with trailing slash)
967 $list = array();
968 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/subdir2/subdir/" ) );
969 foreach ( $iter as $file ) {
970 $list[] = $file;
971 }
972 sort( $list );
973
974 $this->assertEquals( $expected, $list, "Correct file listing ($backendName)." );
975
976 foreach ( $files as $file ) {
977 $this->backend->doOperation( array( 'op' => 'delete', 'src' => "$base/$file" ) );
978 }
979
980 $iter = $this->backend->getFileList( array( 'dir' => "$base/unittest-cont1/not/exists" ) );
981 foreach ( $iter as $iter ) {} // no errors
982 }
983
984 function tearDownFiles() {
985 foreach ( $this->filesToPrune as $file ) {
986 @unlink( $file );
987 }
988 $containers = array( 'unittest-cont1', 'unittest-cont2', 'unittest-cont3' );
989 foreach ( $containers as $container ) {
990 $this->deleteFiles( $this->backend, $container );
991 }
992 }
993
994 private function deleteFiles( $backend, $container ) {
995 $base = $this->baseStorePath();
996 $iter = $backend->getFileList( array( 'dir' => "$base/$container" ) );
997 if ( $iter ) {
998 foreach ( $iter as $file ) {
999 $backend->doOperation( array( 'op' => 'delete', 'src' => "$base/$container/$file" ) );
1000 $tmp = $file;
1001 while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) {
1002 $backend->clean( array( 'dir' => $tmp ) );
1003 }
1004 }
1005 }
1006 }
1007
1008 function tearDown() {
1009 parent::tearDown();
1010 }
1011 }