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'];
30 $userName = $user->getUser()->getName();
31 $password = $user->getPassword();
35 'lgname' => $userName,
36 'lgpassword' => $password
38 list( $result, , $session ) = $this->doApiRequest( $params );
39 $this->assertArrayHasKey( "login", $result );
40 $this->assertArrayHasKey( "result", $result['login'] );
41 $this->assertEquals( "NeedToken", $result['login']['result'] );
42 $token = $result['login']['token'];
47 'lgname' => $userName,
48 'lgpassword' => $password
50 list( $result, , $session ) = $this->doApiRequest( $params, $session );
51 $this->assertArrayHasKey( "login", $result );
52 $this->assertArrayHasKey( "result", $result['login'] );
53 $this->assertEquals( "Success", $result['login']['result'] );
55 $this->assertNotEmpty( $session, 'API Login must return a session' );
63 public function testUploadRequiresToken( $session ) {
66 $this->doApiRequest( [
69 } catch ( ApiUsageException
$e ) {
71 $this->assertContains( 'The "token" parameter must be set', $e->getMessage() );
73 $this->assertTrue( $exception, "Got exception" );
79 public function testUploadMissingParams( $session ) {
82 $this->doApiRequestWithToken( [
84 ], $session, self
::$users['uploader']->getUser() );
85 } catch ( ApiUsageException
$e ) {
88 'One of the parameters "filekey", "file" and "url" is required.',
92 $this->assertTrue( $exception, "Got exception" );
98 public function testUpload( $session ) {
100 $mimeType = 'image/png';
103 $randomImageGenerator = new RandomImageGenerator();
104 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
105 } catch ( Exception
$e ) {
106 $this->markTestIncomplete( $e->getMessage() );
109 /** @var array $filePaths */
110 $filePath = $filePaths[0];
111 $fileSize = filesize( $filePath );
112 $fileName = basename( $filePath );
114 $this->deleteFileByFileName( $fileName );
115 $this->deleteFileByContent( $filePath );
117 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
118 $this->markTestIncomplete( "Couldn't upload file!\n" );
122 'action' => 'upload',
123 'filename' => $fileName,
124 'file' => 'dummy content',
125 'comment' => 'dummy comment',
126 'text' => "This is the page text for $fileName",
131 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
132 self
::$users['uploader']->getUser() );
133 } catch ( ApiUsageException
$e ) {
136 $this->assertTrue( isset( $result['upload'] ) );
137 $this->assertEquals( 'Success', $result['upload']['result'] );
138 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
139 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
140 $this->assertFalse( $exception );
143 $this->deleteFileByFileName( $fileName );
149 public function testUploadZeroLength( $session ) {
150 $mimeType = 'image/png';
152 $filePath = $this->getNewTempFile();
153 $fileName = "apiTestUploadZeroLength.png";
155 $this->deleteFileByFileName( $fileName );
157 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
158 $this->markTestIncomplete( "Couldn't upload file!\n" );
162 'action' => 'upload',
163 'filename' => $fileName,
164 'file' => 'dummy content',
165 'comment' => 'dummy comment',
166 'text' => "This is the page text for $fileName",
171 $this->doApiRequestWithToken( $params, $session, self
::$users['uploader']->getUser() );
172 } catch ( ApiUsageException
$e ) {
173 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
176 $this->assertTrue( $exception );
179 $this->deleteFileByFileName( $fileName );
185 public function testUploadSameFileName( $session ) {
187 $mimeType = 'image/png';
190 $randomImageGenerator = new RandomImageGenerator();
191 $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
192 } catch ( Exception
$e ) {
193 $this->markTestIncomplete( $e->getMessage() );
196 // we'll reuse this filename
197 /** @var array $filePaths */
198 $fileName = basename( $filePaths[0] );
200 // clear any other files with the same name
201 $this->deleteFileByFileName( $fileName );
203 // we reuse these params
205 'action' => 'upload',
206 'filename' => $fileName,
207 'file' => 'dummy content',
208 'comment' => 'dummy comment',
209 'text' => "This is the page text for $fileName",
212 // first upload .... should succeed
214 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
215 $this->markTestIncomplete( "Couldn't upload file!\n" );
220 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
221 self
::$users['uploader']->getUser() );
222 } catch ( ApiUsageException
$e ) {
225 $this->assertTrue( isset( $result['upload'] ) );
226 $this->assertEquals( 'Success', $result['upload']['result'] );
227 $this->assertFalse( $exception );
229 // second upload with the same name (but different content)
231 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
232 $this->markTestIncomplete( "Couldn't upload file!\n" );
237 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
238 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
239 } catch ( ApiUsageException
$e ) {
242 $this->assertTrue( isset( $result['upload'] ) );
243 $this->assertEquals( 'Warning', $result['upload']['result'] );
244 $this->assertTrue( isset( $result['upload']['warnings'] ) );
245 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
246 $this->assertFalse( $exception );
249 $this->deleteFileByFileName( $fileName );
255 public function testUploadSameContent( $session ) {
257 $mimeType = 'image/png';
260 $randomImageGenerator = new RandomImageGenerator();
261 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
262 } catch ( Exception
$e ) {
263 $this->markTestIncomplete( $e->getMessage() );
266 /** @var array $filePaths */
267 $fileNames[0] = basename( $filePaths[0] );
268 $fileNames[1] = "SameContentAs" . $fileNames[0];
270 // clear any other files with the same name or content
271 $this->deleteFileByContent( $filePaths[0] );
272 $this->deleteFileByFileName( $fileNames[0] );
273 $this->deleteFileByFileName( $fileNames[1] );
275 // first upload .... should succeed
278 'action' => 'upload',
279 'filename' => $fileNames[0],
280 'file' => 'dummy content',
281 'comment' => 'dummy comment',
282 'text' => "This is the page text for " . $fileNames[0],
285 if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
286 $this->markTestIncomplete( "Couldn't upload file!\n" );
291 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
292 self
::$users['uploader']->getUser() );
293 } catch ( ApiUsageException
$e ) {
296 $this->assertTrue( isset( $result['upload'] ) );
297 $this->assertEquals( 'Success', $result['upload']['result'] );
298 $this->assertFalse( $exception );
300 // second upload with the same content (but different name)
302 if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
303 $this->markTestIncomplete( "Couldn't upload file!\n" );
307 'action' => 'upload',
308 'filename' => $fileNames[1],
309 'file' => 'dummy content',
310 'comment' => 'dummy comment',
311 'text' => "This is the page text for " . $fileNames[1],
316 list( $result ) = $this->doApiRequestWithToken( $params, $session,
317 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
318 } catch ( ApiUsageException
$e ) {
321 $this->assertTrue( isset( $result['upload'] ) );
322 $this->assertEquals( 'Warning', $result['upload']['result'] );
323 $this->assertTrue( isset( $result['upload']['warnings'] ) );
324 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
325 $this->assertFalse( $exception );
328 $this->deleteFileByFileName( $fileNames[0] );
329 $this->deleteFileByFileName( $fileNames[1] );
335 public function testUploadStash( $session ) {
336 $this->setMwGlobals( [
337 'wgUser' => self
::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
341 $mimeType = 'image/png';
344 $randomImageGenerator = new RandomImageGenerator();
345 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
346 } catch ( Exception
$e ) {
347 $this->markTestIncomplete( $e->getMessage() );
350 /** @var array $filePaths */
351 $filePath = $filePaths[0];
352 $fileSize = filesize( $filePath );
353 $fileName = basename( $filePath );
355 $this->deleteFileByFileName( $fileName );
356 $this->deleteFileByContent( $filePath );
358 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
359 $this->markTestIncomplete( "Couldn't upload file!\n" );
363 'action' => 'upload',
365 'filename' => $fileName,
366 'file' => 'dummy content',
367 'comment' => 'dummy comment',
368 'text' => "This is the page text for $fileName",
373 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
374 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
375 } catch ( ApiUsageException
$e ) {
378 $this->assertFalse( $exception );
379 $this->assertTrue( isset( $result['upload'] ) );
380 $this->assertEquals( 'Success', $result['upload']['result'] );
381 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
382 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
383 $this->assertTrue( isset( $result['upload']['filekey'] ) );
384 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
385 $filekey = $result['upload']['filekey'];
387 // it should be visible from Special:UploadStash
388 // XXX ...but how to test this, with a fake WebRequest with the session?
390 // now we should try to release the file from stash
392 'action' => 'upload',
393 'filekey' => $filekey,
394 'filename' => $fileName,
395 'comment' => 'dummy comment',
396 'text' => "This is the page text for $fileName, altered",
399 $this->clearFakeUploads();
402 list( $result ) = $this->doApiRequestWithToken( $params, $session,
403 self
::$users['uploader']->getUser() );
404 } catch ( ApiUsageException
$e ) {
407 $this->assertTrue( isset( $result['upload'] ) );
408 $this->assertEquals( 'Success', $result['upload']['result'] );
409 $this->assertFalse( $exception, "No ApiUsageException exception." );
412 $this->deleteFileByFileName( $fileName );
418 public function testUploadChunks( $session ) {
419 $this->setMwGlobals( [
420 // @todo FIXME: still used somewhere
421 'wgUser' => self
::$users['uploader']->getUser(),
424 $chunkSize = 1048576;
425 // Download a large image file
426 // (using RandomImageGenerator for large files is not stable)
427 // @todo Don't download files from wikimedia.org
428 $mimeType = 'image/jpeg';
429 $url = 'http://upload.wikimedia.org/wikipedia/commons/'
430 . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
431 $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
433 copy( $url, $filePath );
434 } catch ( Exception
$e ) {
435 $this->markTestIncomplete( $e->getMessage() );
438 $fileSize = filesize( $filePath );
439 $fileName = basename( $filePath );
441 $this->deleteFileByFileName( $fileName );
442 $this->deleteFileByContent( $filePath );
444 // Base upload params:
446 'action' => 'upload',
448 'filename' => $fileName,
449 'filesize' => $fileSize,
454 $chunkSessionKey = false;
457 MediaWiki\
suppressWarnings();
458 $handle = fopen( $filePath, "r" );
459 MediaWiki\restoreWarnings
();
461 if ( $handle === false ) {
462 $this->markTestIncomplete( "could not open file: $filePath" );
465 while ( !feof( $handle ) ) {
466 // Get the current chunk
467 MediaWiki\
suppressWarnings();
468 $chunkData = fread( $handle, $chunkSize );
469 MediaWiki\restoreWarnings
();
471 // Upload the current chunk into the $_FILE object:
472 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
474 // Check for chunkSessionKey
475 if ( !$chunkSessionKey ) {
476 // Upload fist chunk ( and get the session key )
478 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
479 self
::$users['uploader']->getUser() );
480 } catch ( ApiUsageException
$e ) {
481 $this->markTestIncomplete( $e->getMessage() );
483 // Make sure we got a valid chunk continue:
484 $this->assertTrue( isset( $result['upload'] ) );
485 $this->assertTrue( isset( $result['upload']['filekey'] ) );
486 // If we don't get a session key mark test incomplete.
487 if ( !isset( $result['upload']['filekey'] ) ) {
488 $this->markTestIncomplete( "no filekey provided" );
490 $chunkSessionKey = $result['upload']['filekey'];
491 $this->assertEquals( 'Continue', $result['upload']['result'] );
492 // First chunk should have chunkSize == offset
493 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
494 $resultOffset = $result['upload']['offset'];
497 // Filekey set to chunk session
498 $params['filekey'] = $chunkSessionKey;
499 // Update the offset ( always add chunkSize for subquent chunks
500 // should be in-sync with $result['upload']['offset'] )
501 $params['offset'] +
= $chunkSize;
502 // Make sure param offset is insync with resultOffset:
503 $this->assertEquals( $resultOffset, $params['offset'] );
504 // Upload current chunk
506 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
507 self
::$users['uploader']->getUser() );
508 } catch ( ApiUsageException
$e ) {
509 $this->markTestIncomplete( $e->getMessage() );
511 // Make sure we got a valid chunk continue:
512 $this->assertTrue( isset( $result['upload'] ) );
513 $this->assertTrue( isset( $result['upload']['filekey'] ) );
515 // Check if we were on the last chunk:
516 if ( $params['offset'] +
$chunkSize >= $fileSize ) {
517 $this->assertEquals( 'Success', $result['upload']['result'] );
520 $this->assertEquals( 'Continue', $result['upload']['result'] );
521 // update $resultOffset
522 $resultOffset = $result['upload']['offset'];
527 // Check that we got a valid file result:
529 . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
530 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
531 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
532 $this->assertTrue( isset( $result['upload']['filekey'] ) );
533 $filekey = $result['upload']['filekey'];
535 // Now we should try to release the file from stash
537 'action' => 'upload',
538 'filekey' => $filekey,
539 'filename' => $fileName,
540 'comment' => 'dummy comment',
541 'text' => "This is the page text for $fileName, altered",
543 $this->clearFakeUploads();
546 list( $result ) = $this->doApiRequestWithToken( $params, $session,
547 self
::$users['uploader']->getUser() );
548 } catch ( ApiUsageException
$e ) {
551 $this->assertTrue( isset( $result['upload'] ) );
552 $this->assertEquals( 'Success', $result['upload']['result'] );
553 $this->assertFalse( $exception );
556 $this->deleteFileByFileName( $fileName );