Remove messages.inc, rebuildLanguage.php, writeMessagesArray.inc
[mediawiki.git] / tests / phpunit / includes / api / ApiUploadTest.php
blob8ea761f8a707a4f4cac47f58616c8aec6c076e1d
1 <?php
2 /**
3 * @group API
4 * @group Database
5 * @group medium
6 */
8 /**
9 * n.b. Ensure that you can write to the images/ directory as the
10 * user that will run tests.
13 // Note for reviewers: this intentionally duplicates functionality already in
14 // "ApiSetup" and so on. This framework works better IMO and has less
15 // strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
16 // case of the other Upload tests, this flat out just actually works... )
18 // @todo Port the other Upload tests, and other API tests to this framework
20 require_once 'ApiTestCaseUpload.php';
22 /**
23 * @group Database
24 * @group Broken
25 * Broken test, reports false errors from time to time.
26 * See https://bugzilla.wikimedia.org/26169
28 * This is pretty sucky... needs to be prettified.
30 class ApiUploadTest extends ApiTestCaseUpload {
31 /**
32 * Testing login
33 * XXX this is a funny way of getting session context
35 public function testLogin() {
36 $user = self::$users['uploader'];
38 $params = array(
39 'action' => 'login',
40 'lgname' => $user->username,
41 'lgpassword' => $user->password
43 list( $result, , $session ) = $this->doApiRequest( $params );
44 $this->assertArrayHasKey( "login", $result );
45 $this->assertArrayHasKey( "result", $result['login'] );
46 $this->assertEquals( "NeedToken", $result['login']['result'] );
47 $token = $result['login']['token'];
49 $params = array(
50 'action' => 'login',
51 'lgtoken' => $token,
52 'lgname' => $user->username,
53 'lgpassword' => $user->password
55 list( $result, , $session ) = $this->doApiRequest( $params, $session );
56 $this->assertArrayHasKey( "login", $result );
57 $this->assertArrayHasKey( "result", $result['login'] );
58 $this->assertEquals( "Success", $result['login']['result'] );
59 $this->assertArrayHasKey( 'lgtoken', $result['login'] );
61 $this->assertNotEmpty( $session, 'API Login must return a session' );
63 return $session;
66 /**
67 * @depends testLogin
69 public function testUploadRequiresToken( $session ) {
70 $exception = false;
71 try {
72 $this->doApiRequest( array(
73 'action' => 'upload'
74 ) );
75 } catch ( UsageException $e ) {
76 $exception = true;
77 $this->assertEquals( "The token parameter must be set", $e->getMessage() );
79 $this->assertTrue( $exception, "Got exception" );
82 /**
83 * @depends testLogin
85 public function testUploadMissingParams( $session ) {
86 $exception = false;
87 try {
88 $this->doApiRequestWithToken( array(
89 'action' => 'upload',
90 ), $session, self::$users['uploader']->user );
91 } catch ( UsageException $e ) {
92 $exception = true;
93 $this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
94 $e->getMessage() );
96 $this->assertTrue( $exception, "Got exception" );
99 /**
100 * @depends testLogin
102 public function testUpload( $session ) {
103 $extension = 'png';
104 $mimeType = 'image/png';
106 try {
107 $randomImageGenerator = new RandomImageGenerator();
108 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
109 } catch ( Exception $e ) {
110 $this->markTestIncomplete( $e->getMessage() );
113 /** @var array $filePaths */
114 $filePath = $filePaths[0];
115 $fileSize = filesize( $filePath );
116 $fileName = basename( $filePath );
118 $this->deleteFileByFileName( $fileName );
119 $this->deleteFileByContent( $filePath );
121 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
122 $this->markTestIncomplete( "Couldn't upload file!\n" );
125 $params = array(
126 'action' => 'upload',
127 'filename' => $fileName,
128 'file' => 'dummy content',
129 'comment' => 'dummy comment',
130 'text' => "This is the page text for $fileName",
133 $exception = false;
134 try {
135 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
136 self::$users['uploader']->user );
137 } catch ( UsageException $e ) {
138 $exception = true;
140 $this->assertTrue( isset( $result['upload'] ) );
141 $this->assertEquals( 'Success', $result['upload']['result'] );
142 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
143 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
144 $this->assertFalse( $exception );
146 // clean up
147 $this->deleteFileByFilename( $fileName );
148 unlink( $filePath );
152 * @depends testLogin
154 public function testUploadZeroLength( $session ) {
155 $mimeType = 'image/png';
157 $filePath = tempnam( wfTempDir(), "" );
158 $fileName = "apiTestUploadZeroLength.png";
160 $this->deleteFileByFileName( $fileName );
162 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
163 $this->markTestIncomplete( "Couldn't upload file!\n" );
166 $params = array(
167 'action' => 'upload',
168 'filename' => $fileName,
169 'file' => 'dummy content',
170 'comment' => 'dummy comment',
171 'text' => "This is the page text for $fileName",
174 $exception = false;
175 try {
176 $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
177 } catch ( UsageException $e ) {
178 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
179 $exception = true;
181 $this->assertTrue( $exception );
183 // clean up
184 $this->deleteFileByFilename( $fileName );
185 unlink( $filePath );
189 * @depends testLogin
191 public function testUploadSameFileName( $session ) {
192 $extension = 'png';
193 $mimeType = 'image/png';
195 try {
196 $randomImageGenerator = new RandomImageGenerator();
197 $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
198 } catch ( Exception $e ) {
199 $this->markTestIncomplete( $e->getMessage() );
202 // we'll reuse this filename
203 /** @var array $filePaths */
204 $fileName = basename( $filePaths[0] );
206 // clear any other files with the same name
207 $this->deleteFileByFileName( $fileName );
209 // we reuse these params
210 $params = array(
211 'action' => 'upload',
212 'filename' => $fileName,
213 'file' => 'dummy content',
214 'comment' => 'dummy comment',
215 'text' => "This is the page text for $fileName",
218 // first upload .... should succeed
220 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
221 $this->markTestIncomplete( "Couldn't upload file!\n" );
224 $exception = false;
225 try {
226 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
227 self::$users['uploader']->user );
228 } catch ( UsageException $e ) {
229 $exception = true;
231 $this->assertTrue( isset( $result['upload'] ) );
232 $this->assertEquals( 'Success', $result['upload']['result'] );
233 $this->assertFalse( $exception );
235 // second upload with the same name (but different content)
237 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
238 $this->markTestIncomplete( "Couldn't upload file!\n" );
241 $exception = false;
242 try {
243 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
244 self::$users['uploader']->user ); // FIXME: leaks a temporary file
245 } catch ( UsageException $e ) {
246 $exception = true;
248 $this->assertTrue( isset( $result['upload'] ) );
249 $this->assertEquals( 'Warning', $result['upload']['result'] );
250 $this->assertTrue( isset( $result['upload']['warnings'] ) );
251 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
252 $this->assertFalse( $exception );
254 // clean up
255 $this->deleteFileByFilename( $fileName );
256 unlink( $filePaths[0] );
257 unlink( $filePaths[1] );
261 * @depends testLogin
263 public function testUploadSameContent( $session ) {
264 $extension = 'png';
265 $mimeType = 'image/png';
267 try {
268 $randomImageGenerator = new RandomImageGenerator();
269 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
270 } catch ( Exception $e ) {
271 $this->markTestIncomplete( $e->getMessage() );
274 /** @var array $filePaths */
275 $fileNames[0] = basename( $filePaths[0] );
276 $fileNames[1] = "SameContentAs" . $fileNames[0];
278 // clear any other files with the same name or content
279 $this->deleteFileByContent( $filePaths[0] );
280 $this->deleteFileByFileName( $fileNames[0] );
281 $this->deleteFileByFileName( $fileNames[1] );
283 // first upload .... should succeed
285 $params = array(
286 'action' => 'upload',
287 'filename' => $fileNames[0],
288 'file' => 'dummy content',
289 'comment' => 'dummy comment',
290 'text' => "This is the page text for " . $fileNames[0],
293 if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
294 $this->markTestIncomplete( "Couldn't upload file!\n" );
297 $exception = false;
298 try {
299 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
300 self::$users['uploader']->user );
301 } catch ( UsageException $e ) {
302 $exception = true;
304 $this->assertTrue( isset( $result['upload'] ) );
305 $this->assertEquals( 'Success', $result['upload']['result'] );
306 $this->assertFalse( $exception );
308 // second upload with the same content (but different name)
310 if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
311 $this->markTestIncomplete( "Couldn't upload file!\n" );
314 $params = array(
315 'action' => 'upload',
316 'filename' => $fileNames[1],
317 'file' => 'dummy content',
318 'comment' => 'dummy comment',
319 'text' => "This is the page text for " . $fileNames[1],
322 $exception = false;
323 try {
324 list( $result ) = $this->doApiRequestWithToken( $params, $session,
325 self::$users['uploader']->user ); // FIXME: leaks a temporary file
326 } catch ( UsageException $e ) {
327 $exception = true;
329 $this->assertTrue( isset( $result['upload'] ) );
330 $this->assertEquals( 'Warning', $result['upload']['result'] );
331 $this->assertTrue( isset( $result['upload']['warnings'] ) );
332 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
333 $this->assertFalse( $exception );
335 // clean up
336 $this->deleteFileByFilename( $fileNames[0] );
337 $this->deleteFileByFilename( $fileNames[1] );
338 unlink( $filePaths[0] );
342 * @depends testLogin
344 public function testUploadStash( $session ) {
345 $this->setMwGlobals( array(
346 'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
347 ) );
349 $extension = 'png';
350 $mimeType = 'image/png';
352 try {
353 $randomImageGenerator = new RandomImageGenerator();
354 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
355 } catch ( Exception $e ) {
356 $this->markTestIncomplete( $e->getMessage() );
359 /** @var array $filePaths */
360 $filePath = $filePaths[0];
361 $fileSize = filesize( $filePath );
362 $fileName = basename( $filePath );
364 $this->deleteFileByFileName( $fileName );
365 $this->deleteFileByContent( $filePath );
367 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
368 $this->markTestIncomplete( "Couldn't upload file!\n" );
371 $params = array(
372 'action' => 'upload',
373 'stash' => 1,
374 'filename' => $fileName,
375 'file' => 'dummy content',
376 'comment' => 'dummy comment',
377 'text' => "This is the page text for $fileName",
380 $exception = false;
381 try {
382 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
383 self::$users['uploader']->user ); // FIXME: leaks a temporary file
384 } catch ( UsageException $e ) {
385 $exception = true;
387 $this->assertFalse( $exception );
388 $this->assertTrue( isset( $result['upload'] ) );
389 $this->assertEquals( 'Success', $result['upload']['result'] );
390 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
391 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
392 $this->assertTrue( isset( $result['upload']['filekey'] ) );
393 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
394 $filekey = $result['upload']['filekey'];
396 // it should be visible from Special:UploadStash
397 // XXX ...but how to test this, with a fake WebRequest with the session?
399 // now we should try to release the file from stash
400 $params = array(
401 'action' => 'upload',
402 'filekey' => $filekey,
403 'filename' => $fileName,
404 'comment' => 'dummy comment',
405 'text' => "This is the page text for $fileName, altered",
408 $this->clearFakeUploads();
409 $exception = false;
410 try {
411 list( $result ) = $this->doApiRequestWithToken( $params, $session,
412 self::$users['uploader']->user );
413 } catch ( UsageException $e ) {
414 $exception = true;
416 $this->assertTrue( isset( $result['upload'] ) );
417 $this->assertEquals( 'Success', $result['upload']['result'] );
418 $this->assertFalse( $exception, "No UsageException exception." );
420 // clean up
421 $this->deleteFileByFilename( $fileName );
422 unlink( $filePath );
426 * @depends testLogin
428 public function testUploadChunks( $session ) {
429 $this->setMwGlobals( array(
430 // @todo FIXME: still used somewhere
431 'wgUser' => self::$users['uploader']->user,
432 ) );
434 $chunkSize = 1048576;
435 // Download a large image file
436 // ( using RandomImageGenerator for large files is not stable )
437 $mimeType = 'image/jpeg';
438 $url = 'http://upload.wikimedia.org/wikipedia/commons/'
439 . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
440 $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg';
441 try {
442 // Only download if the file is not avaliable in the temp location:
443 if ( !is_file( $filePath ) ) {
444 copy( $url, $filePath );
446 } catch ( Exception $e ) {
447 $this->markTestIncomplete( $e->getMessage() );
450 $fileSize = filesize( $filePath );
451 $fileName = basename( $filePath );
453 $this->deleteFileByFileName( $fileName );
454 $this->deleteFileByContent( $filePath );
456 // Base upload params:
457 $params = array(
458 'action' => 'upload',
459 'stash' => 1,
460 'filename' => $fileName,
461 'filesize' => $fileSize,
462 'offset' => 0,
465 // Upload chunks
466 $chunkSessionKey = false;
467 $resultOffset = 0;
468 // Open the file:
469 wfSuppressWarnings();
470 $handle = fopen( $filePath, "r" );
471 wfRestoreWarnings();
473 if ( $handle === false ) {
474 $this->markTestIncomplete( "could not open file: $filePath" );
477 while ( !feof( $handle ) ) {
478 // Get the current chunk
479 wfSuppressWarnings();
480 $chunkData = fread( $handle, $chunkSize );
481 wfRestoreWarnings();
483 // Upload the current chunk into the $_FILE object:
484 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
486 // Check for chunkSessionKey
487 if ( !$chunkSessionKey ) {
488 // Upload fist chunk ( and get the session key )
489 try {
490 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
491 self::$users['uploader']->user );
492 } catch ( UsageException $e ) {
493 $this->markTestIncomplete( $e->getMessage() );
495 // Make sure we got a valid chunk continue:
496 $this->assertTrue( isset( $result['upload'] ) );
497 $this->assertTrue( isset( $result['upload']['filekey'] ) );
498 // If we don't get a session key mark test incomplete.
499 if ( !isset( $result['upload']['filekey'] ) ) {
500 $this->markTestIncomplete( "no filekey provided" );
502 $chunkSessionKey = $result['upload']['filekey'];
503 $this->assertEquals( 'Continue', $result['upload']['result'] );
504 // First chunk should have chunkSize == offset
505 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
506 $resultOffset = $result['upload']['offset'];
507 continue;
509 // Filekey set to chunk session
510 $params['filekey'] = $chunkSessionKey;
511 // Update the offset ( always add chunkSize for subquent chunks
512 // should be in-sync with $result['upload']['offset'] )
513 $params['offset'] += $chunkSize;
514 // Make sure param offset is insync with resultOffset:
515 $this->assertEquals( $resultOffset, $params['offset'] );
516 // Upload current chunk
517 try {
518 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
519 self::$users['uploader']->user );
520 } catch ( UsageException $e ) {
521 $this->markTestIncomplete( $e->getMessage() );
523 // Make sure we got a valid chunk continue:
524 $this->assertTrue( isset( $result['upload'] ) );
525 $this->assertTrue( isset( $result['upload']['filekey'] ) );
527 // Check if we were on the last chunk:
528 if ( $params['offset'] + $chunkSize >= $fileSize ) {
529 $this->assertEquals( 'Success', $result['upload']['result'] );
530 break;
531 } else {
532 $this->assertEquals( 'Continue', $result['upload']['result'] );
533 // update $resultOffset
534 $resultOffset = $result['upload']['offset'];
537 fclose( $handle );
539 // Check that we got a valid file result:
540 wfDebug( __METHOD__
541 . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
542 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
543 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
544 $this->assertTrue( isset( $result['upload']['filekey'] ) );
545 $filekey = $result['upload']['filekey'];
547 // Now we should try to release the file from stash
548 $params = array(
549 'action' => 'upload',
550 'filekey' => $filekey,
551 'filename' => $fileName,
552 'comment' => 'dummy comment',
553 'text' => "This is the page text for $fileName, altered",
555 $this->clearFakeUploads();
556 $exception = false;
557 try {
558 list( $result ) = $this->doApiRequestWithToken( $params, $session,
559 self::$users['uploader']->user );
560 } catch ( UsageException $e ) {
561 $exception = true;
563 $this->assertTrue( isset( $result['upload'] ) );
564 $this->assertEquals( 'Success', $result['upload']['result'] );
565 $this->assertFalse( $exception );
567 // clean up
568 $this->deleteFileByFilename( $fileName );
569 // don't remove downloaded temporary file for fast subquent tests.
570 //unlink( $filePath );