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