3 * n.b. Ensure that you can write to the images/ directory as the
4 * user that will run tests.
6 * Note for reviewers: this intentionally duplicates functionality already in
7 * "ApiSetup" and so on. This framework works better IMO and has less
8 * strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
9 * case of the other Upload tests, this flat out just actually works... )
11 * @todo Port the other Upload tests, and other API tests to this framework
13 * @todo Broken test, reports false errors from time to time.
14 * See https://phabricator.wikimedia.org/T28169
16 * @todo This is pretty sucky... needs to be prettified.
23 class ApiUploadTest
extends ApiTestCaseUpload
{
26 * XXX this is a funny way of getting session context
28 public function testLogin() {
29 $user = self
::$users['uploader'];
33 'lgname' => $user->username
,
34 'lgpassword' => $user->password
36 list( $result, , $session ) = $this->doApiRequest( $params );
37 $this->assertArrayHasKey( "login", $result );
38 $this->assertArrayHasKey( "result", $result['login'] );
39 $this->assertEquals( "NeedToken", $result['login']['result'] );
40 $token = $result['login']['token'];
45 'lgname' => $user->username
,
46 'lgpassword' => $user->password
48 list( $result, , $session ) = $this->doApiRequest( $params, $session );
49 $this->assertArrayHasKey( "login", $result );
50 $this->assertArrayHasKey( "result", $result['login'] );
51 $this->assertEquals( "Success", $result['login']['result'] );
52 $this->assertArrayHasKey( 'lgtoken', $result['login'] );
54 $this->assertNotEmpty( $session, 'API Login must return a session' );
62 public function testUploadRequiresToken( $session ) {
65 $this->doApiRequest( array(
68 } catch ( UsageException
$e ) {
70 $this->assertEquals( "The token parameter must be set", $e->getMessage() );
72 $this->assertTrue( $exception, "Got exception" );
78 public function testUploadMissingParams( $session ) {
81 $this->doApiRequestWithToken( array(
83 ), $session, self
::$users['uploader']->getUser() );
84 } catch ( UsageException
$e ) {
86 $this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
89 $this->assertTrue( $exception, "Got exception" );
95 public function testUpload( $session ) {
97 $mimeType = 'image/png';
100 $randomImageGenerator = new RandomImageGenerator();
101 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
102 } catch ( Exception
$e ) {
103 $this->markTestIncomplete( $e->getMessage() );
106 /** @var array $filePaths */
107 $filePath = $filePaths[0];
108 $fileSize = filesize( $filePath );
109 $fileName = basename( $filePath );
111 $this->deleteFileByFileName( $fileName );
112 $this->deleteFileByContent( $filePath );
114 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
115 $this->markTestIncomplete( "Couldn't upload file!\n" );
119 'action' => 'upload',
120 'filename' => $fileName,
121 'file' => 'dummy content',
122 'comment' => 'dummy comment',
123 'text' => "This is the page text for $fileName",
128 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
129 self
::$users['uploader']->getUser() );
130 } catch ( UsageException
$e ) {
133 $this->assertTrue( isset( $result['upload'] ) );
134 $this->assertEquals( 'Success', $result['upload']['result'] );
135 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
136 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
137 $this->assertFalse( $exception );
140 $this->deleteFileByFilename( $fileName );
146 public function testUploadZeroLength( $session ) {
147 $mimeType = 'image/png';
149 $filePath = $this->getNewTempFile();
150 $fileName = "apiTestUploadZeroLength.png";
152 $this->deleteFileByFileName( $fileName );
154 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
155 $this->markTestIncomplete( "Couldn't upload file!\n" );
159 'action' => 'upload',
160 'filename' => $fileName,
161 'file' => 'dummy content',
162 'comment' => 'dummy comment',
163 'text' => "This is the page text for $fileName",
168 $this->doApiRequestWithToken( $params, $session, self
::$users['uploader']->getUser() );
169 } catch ( UsageException
$e ) {
170 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
173 $this->assertTrue( $exception );
176 $this->deleteFileByFilename( $fileName );
182 public function testUploadSameFileName( $session ) {
184 $mimeType = 'image/png';
187 $randomImageGenerator = new RandomImageGenerator();
188 $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
189 } catch ( Exception
$e ) {
190 $this->markTestIncomplete( $e->getMessage() );
193 // we'll reuse this filename
194 /** @var array $filePaths */
195 $fileName = basename( $filePaths[0] );
197 // clear any other files with the same name
198 $this->deleteFileByFileName( $fileName );
200 // we reuse these params
202 'action' => 'upload',
203 'filename' => $fileName,
204 'file' => 'dummy content',
205 'comment' => 'dummy comment',
206 'text' => "This is the page text for $fileName",
209 // first upload .... should succeed
211 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
212 $this->markTestIncomplete( "Couldn't upload file!\n" );
217 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
218 self
::$users['uploader']->getUser() );
219 } catch ( UsageException
$e ) {
222 $this->assertTrue( isset( $result['upload'] ) );
223 $this->assertEquals( 'Success', $result['upload']['result'] );
224 $this->assertFalse( $exception );
226 // second upload with the same name (but different content)
228 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
229 $this->markTestIncomplete( "Couldn't upload file!\n" );
234 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
235 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
236 } catch ( UsageException
$e ) {
239 $this->assertTrue( isset( $result['upload'] ) );
240 $this->assertEquals( 'Warning', $result['upload']['result'] );
241 $this->assertTrue( isset( $result['upload']['warnings'] ) );
242 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
243 $this->assertFalse( $exception );
246 $this->deleteFileByFilename( $fileName );
252 public function testUploadSameContent( $session ) {
254 $mimeType = 'image/png';
257 $randomImageGenerator = new RandomImageGenerator();
258 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
259 } catch ( Exception
$e ) {
260 $this->markTestIncomplete( $e->getMessage() );
263 /** @var array $filePaths */
264 $fileNames[0] = basename( $filePaths[0] );
265 $fileNames[1] = "SameContentAs" . $fileNames[0];
267 // clear any other files with the same name or content
268 $this->deleteFileByContent( $filePaths[0] );
269 $this->deleteFileByFileName( $fileNames[0] );
270 $this->deleteFileByFileName( $fileNames[1] );
272 // first upload .... should succeed
275 'action' => 'upload',
276 'filename' => $fileNames[0],
277 'file' => 'dummy content',
278 'comment' => 'dummy comment',
279 'text' => "This is the page text for " . $fileNames[0],
282 if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
283 $this->markTestIncomplete( "Couldn't upload file!\n" );
288 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
289 self
::$users['uploader']->getUser() );
290 } catch ( UsageException
$e ) {
293 $this->assertTrue( isset( $result['upload'] ) );
294 $this->assertEquals( 'Success', $result['upload']['result'] );
295 $this->assertFalse( $exception );
297 // second upload with the same content (but different name)
299 if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
300 $this->markTestIncomplete( "Couldn't upload file!\n" );
304 'action' => 'upload',
305 'filename' => $fileNames[1],
306 'file' => 'dummy content',
307 'comment' => 'dummy comment',
308 'text' => "This is the page text for " . $fileNames[1],
313 list( $result ) = $this->doApiRequestWithToken( $params, $session,
314 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
315 } catch ( UsageException
$e ) {
318 $this->assertTrue( isset( $result['upload'] ) );
319 $this->assertEquals( 'Warning', $result['upload']['result'] );
320 $this->assertTrue( isset( $result['upload']['warnings'] ) );
321 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
322 $this->assertFalse( $exception );
325 $this->deleteFileByFilename( $fileNames[0] );
326 $this->deleteFileByFilename( $fileNames[1] );
332 public function testUploadStash( $session ) {
333 $this->setMwGlobals( array(
334 'wgUser' => self
::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
338 $mimeType = 'image/png';
341 $randomImageGenerator = new RandomImageGenerator();
342 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
343 } catch ( Exception
$e ) {
344 $this->markTestIncomplete( $e->getMessage() );
347 /** @var array $filePaths */
348 $filePath = $filePaths[0];
349 $fileSize = filesize( $filePath );
350 $fileName = basename( $filePath );
352 $this->deleteFileByFileName( $fileName );
353 $this->deleteFileByContent( $filePath );
355 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
356 $this->markTestIncomplete( "Couldn't upload file!\n" );
360 'action' => 'upload',
362 'filename' => $fileName,
363 'file' => 'dummy content',
364 'comment' => 'dummy comment',
365 'text' => "This is the page text for $fileName",
370 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
371 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
372 } catch ( UsageException
$e ) {
375 $this->assertFalse( $exception );
376 $this->assertTrue( isset( $result['upload'] ) );
377 $this->assertEquals( 'Success', $result['upload']['result'] );
378 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
379 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
380 $this->assertTrue( isset( $result['upload']['filekey'] ) );
381 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
382 $filekey = $result['upload']['filekey'];
384 // it should be visible from Special:UploadStash
385 // XXX ...but how to test this, with a fake WebRequest with the session?
387 // now we should try to release the file from stash
389 'action' => 'upload',
390 'filekey' => $filekey,
391 'filename' => $fileName,
392 'comment' => 'dummy comment',
393 'text' => "This is the page text for $fileName, altered",
396 $this->clearFakeUploads();
399 list( $result ) = $this->doApiRequestWithToken( $params, $session,
400 self
::$users['uploader']->getUser() );
401 } catch ( UsageException
$e ) {
404 $this->assertTrue( isset( $result['upload'] ) );
405 $this->assertEquals( 'Success', $result['upload']['result'] );
406 $this->assertFalse( $exception, "No UsageException exception." );
409 $this->deleteFileByFilename( $fileName );
415 public function testUploadChunks( $session ) {
416 $this->setMwGlobals( array(
417 // @todo FIXME: still used somewhere
418 'wgUser' => self
::$users['uploader']->getUser(),
421 $chunkSize = 1048576;
422 // Download a large image file
423 // (using RandomImageGenerator for large files is not stable)
424 // @todo Don't download files from wikimedia.org
425 $mimeType = 'image/jpeg';
426 $url = 'http://upload.wikimedia.org/wikipedia/commons/'
427 . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
428 $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
430 copy( $url, $filePath );
431 } catch ( Exception
$e ) {
432 $this->markTestIncomplete( $e->getMessage() );
435 $fileSize = filesize( $filePath );
436 $fileName = basename( $filePath );
438 $this->deleteFileByFileName( $fileName );
439 $this->deleteFileByContent( $filePath );
441 // Base upload params:
443 'action' => 'upload',
445 'filename' => $fileName,
446 'filesize' => $fileSize,
451 $chunkSessionKey = false;
454 MediaWiki\
suppressWarnings();
455 $handle = fopen( $filePath, "r" );
456 MediaWiki\restoreWarnings
();
458 if ( $handle === false ) {
459 $this->markTestIncomplete( "could not open file: $filePath" );
462 while ( !feof( $handle ) ) {
463 // Get the current chunk
464 MediaWiki\
suppressWarnings();
465 $chunkData = fread( $handle, $chunkSize );
466 MediaWiki\restoreWarnings
();
468 // Upload the current chunk into the $_FILE object:
469 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
471 // Check for chunkSessionKey
472 if ( !$chunkSessionKey ) {
473 // Upload fist chunk ( and get the session key )
475 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
476 self
::$users['uploader']->getUser() );
477 } catch ( UsageException
$e ) {
478 $this->markTestIncomplete( $e->getMessage() );
480 // Make sure we got a valid chunk continue:
481 $this->assertTrue( isset( $result['upload'] ) );
482 $this->assertTrue( isset( $result['upload']['filekey'] ) );
483 // If we don't get a session key mark test incomplete.
484 if ( !isset( $result['upload']['filekey'] ) ) {
485 $this->markTestIncomplete( "no filekey provided" );
487 $chunkSessionKey = $result['upload']['filekey'];
488 $this->assertEquals( 'Continue', $result['upload']['result'] );
489 // First chunk should have chunkSize == offset
490 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
491 $resultOffset = $result['upload']['offset'];
494 // Filekey set to chunk session
495 $params['filekey'] = $chunkSessionKey;
496 // Update the offset ( always add chunkSize for subquent chunks
497 // should be in-sync with $result['upload']['offset'] )
498 $params['offset'] +
= $chunkSize;
499 // Make sure param offset is insync with resultOffset:
500 $this->assertEquals( $resultOffset, $params['offset'] );
501 // Upload current chunk
503 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
504 self
::$users['uploader']->getUser() );
505 } catch ( UsageException
$e ) {
506 $this->markTestIncomplete( $e->getMessage() );
508 // Make sure we got a valid chunk continue:
509 $this->assertTrue( isset( $result['upload'] ) );
510 $this->assertTrue( isset( $result['upload']['filekey'] ) );
512 // Check if we were on the last chunk:
513 if ( $params['offset'] +
$chunkSize >= $fileSize ) {
514 $this->assertEquals( 'Success', $result['upload']['result'] );
517 $this->assertEquals( 'Continue', $result['upload']['result'] );
518 // update $resultOffset
519 $resultOffset = $result['upload']['offset'];
524 // Check that we got a valid file result:
526 . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
527 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
528 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
529 $this->assertTrue( isset( $result['upload']['filekey'] ) );
530 $filekey = $result['upload']['filekey'];
532 // Now we should try to release the file from stash
534 'action' => 'upload',
535 'filekey' => $filekey,
536 'filename' => $fileName,
537 'comment' => 'dummy comment',
538 'text' => "This is the page text for $fileName, altered",
540 $this->clearFakeUploads();
543 list( $result ) = $this->doApiRequestWithToken( $params, $session,
544 self
::$users['uploader']->getUser() );
545 } catch ( UsageException
$e ) {
548 $this->assertTrue( isset( $result['upload'] ) );
549 $this->assertEquals( 'Success', $result['upload']['result'] );
550 $this->assertFalse( $exception );
553 $this->deleteFileByFilename( $fileName );