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'] );
54 $this->assertArrayHasKey( 'lgtoken', $result['login'] );
56 $this->assertNotEmpty( $session, 'API Login must return a session' );
64 public function testUploadRequiresToken( $session ) {
67 $this->doApiRequest( [
70 } catch ( ApiUsageException
$e ) {
72 $this->assertEquals( 'The "token" parameter must be set', $e->getMessage() );
74 $this->assertTrue( $exception, "Got exception" );
80 public function testUploadMissingParams( $session ) {
83 $this->doApiRequestWithToken( [
85 ], $session, self
::$users['uploader']->getUser() );
86 } catch ( ApiUsageException
$e ) {
88 $this->assertEquals( "One of the parameters filekey, file, url is required",
91 $this->assertTrue( $exception, "Got exception" );
97 public function testUpload( $session ) {
99 $mimeType = 'image/png';
102 $randomImageGenerator = new RandomImageGenerator();
103 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
104 } catch ( Exception
$e ) {
105 $this->markTestIncomplete( $e->getMessage() );
108 /** @var array $filePaths */
109 $filePath = $filePaths[0];
110 $fileSize = filesize( $filePath );
111 $fileName = basename( $filePath );
113 $this->deleteFileByFileName( $fileName );
114 $this->deleteFileByContent( $filePath );
116 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
117 $this->markTestIncomplete( "Couldn't upload file!\n" );
121 'action' => 'upload',
122 'filename' => $fileName,
123 'file' => 'dummy content',
124 'comment' => 'dummy comment',
125 'text' => "This is the page text for $fileName",
130 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
131 self
::$users['uploader']->getUser() );
132 } catch ( ApiUsageException
$e ) {
135 $this->assertTrue( isset( $result['upload'] ) );
136 $this->assertEquals( 'Success', $result['upload']['result'] );
137 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
138 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
139 $this->assertFalse( $exception );
142 $this->deleteFileByFileName( $fileName );
148 public function testUploadZeroLength( $session ) {
149 $mimeType = 'image/png';
151 $filePath = $this->getNewTempFile();
152 $fileName = "apiTestUploadZeroLength.png";
154 $this->deleteFileByFileName( $fileName );
156 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
157 $this->markTestIncomplete( "Couldn't upload file!\n" );
161 'action' => 'upload',
162 'filename' => $fileName,
163 'file' => 'dummy content',
164 'comment' => 'dummy comment',
165 'text' => "This is the page text for $fileName",
170 $this->doApiRequestWithToken( $params, $session, self
::$users['uploader']->getUser() );
171 } catch ( ApiUsageException
$e ) {
172 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
175 $this->assertTrue( $exception );
178 $this->deleteFileByFileName( $fileName );
184 public function testUploadSameFileName( $session ) {
186 $mimeType = 'image/png';
189 $randomImageGenerator = new RandomImageGenerator();
190 $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
191 } catch ( Exception
$e ) {
192 $this->markTestIncomplete( $e->getMessage() );
195 // we'll reuse this filename
196 /** @var array $filePaths */
197 $fileName = basename( $filePaths[0] );
199 // clear any other files with the same name
200 $this->deleteFileByFileName( $fileName );
202 // we reuse these params
204 'action' => 'upload',
205 'filename' => $fileName,
206 'file' => 'dummy content',
207 'comment' => 'dummy comment',
208 'text' => "This is the page text for $fileName",
211 // first upload .... should succeed
213 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
214 $this->markTestIncomplete( "Couldn't upload file!\n" );
219 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
220 self
::$users['uploader']->getUser() );
221 } catch ( ApiUsageException
$e ) {
224 $this->assertTrue( isset( $result['upload'] ) );
225 $this->assertEquals( 'Success', $result['upload']['result'] );
226 $this->assertFalse( $exception );
228 // second upload with the same name (but different content)
230 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
231 $this->markTestIncomplete( "Couldn't upload file!\n" );
236 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
237 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
238 } catch ( ApiUsageException
$e ) {
241 $this->assertTrue( isset( $result['upload'] ) );
242 $this->assertEquals( 'Warning', $result['upload']['result'] );
243 $this->assertTrue( isset( $result['upload']['warnings'] ) );
244 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
245 $this->assertFalse( $exception );
248 $this->deleteFileByFileName( $fileName );
254 public function testUploadSameContent( $session ) {
256 $mimeType = 'image/png';
259 $randomImageGenerator = new RandomImageGenerator();
260 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
261 } catch ( Exception
$e ) {
262 $this->markTestIncomplete( $e->getMessage() );
265 /** @var array $filePaths */
266 $fileNames[0] = basename( $filePaths[0] );
267 $fileNames[1] = "SameContentAs" . $fileNames[0];
269 // clear any other files with the same name or content
270 $this->deleteFileByContent( $filePaths[0] );
271 $this->deleteFileByFileName( $fileNames[0] );
272 $this->deleteFileByFileName( $fileNames[1] );
274 // first upload .... should succeed
277 'action' => 'upload',
278 'filename' => $fileNames[0],
279 'file' => 'dummy content',
280 'comment' => 'dummy comment',
281 'text' => "This is the page text for " . $fileNames[0],
284 if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
285 $this->markTestIncomplete( "Couldn't upload file!\n" );
290 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
291 self
::$users['uploader']->getUser() );
292 } catch ( ApiUsageException
$e ) {
295 $this->assertTrue( isset( $result['upload'] ) );
296 $this->assertEquals( 'Success', $result['upload']['result'] );
297 $this->assertFalse( $exception );
299 // second upload with the same content (but different name)
301 if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
302 $this->markTestIncomplete( "Couldn't upload file!\n" );
306 'action' => 'upload',
307 'filename' => $fileNames[1],
308 'file' => 'dummy content',
309 'comment' => 'dummy comment',
310 'text' => "This is the page text for " . $fileNames[1],
315 list( $result ) = $this->doApiRequestWithToken( $params, $session,
316 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
317 } catch ( ApiUsageException
$e ) {
320 $this->assertTrue( isset( $result['upload'] ) );
321 $this->assertEquals( 'Warning', $result['upload']['result'] );
322 $this->assertTrue( isset( $result['upload']['warnings'] ) );
323 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
324 $this->assertFalse( $exception );
327 $this->deleteFileByFileName( $fileNames[0] );
328 $this->deleteFileByFileName( $fileNames[1] );
334 public function testUploadStash( $session ) {
335 $this->setMwGlobals( [
336 'wgUser' => self
::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
340 $mimeType = 'image/png';
343 $randomImageGenerator = new RandomImageGenerator();
344 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
345 } catch ( Exception
$e ) {
346 $this->markTestIncomplete( $e->getMessage() );
349 /** @var array $filePaths */
350 $filePath = $filePaths[0];
351 $fileSize = filesize( $filePath );
352 $fileName = basename( $filePath );
354 $this->deleteFileByFileName( $fileName );
355 $this->deleteFileByContent( $filePath );
357 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
358 $this->markTestIncomplete( "Couldn't upload file!\n" );
362 'action' => 'upload',
364 'filename' => $fileName,
365 'file' => 'dummy content',
366 'comment' => 'dummy comment',
367 'text' => "This is the page text for $fileName",
372 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
373 self
::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
374 } catch ( ApiUsageException
$e ) {
377 $this->assertFalse( $exception );
378 $this->assertTrue( isset( $result['upload'] ) );
379 $this->assertEquals( 'Success', $result['upload']['result'] );
380 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
381 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
382 $this->assertTrue( isset( $result['upload']['filekey'] ) );
383 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
384 $filekey = $result['upload']['filekey'];
386 // it should be visible from Special:UploadStash
387 // XXX ...but how to test this, with a fake WebRequest with the session?
389 // now we should try to release the file from stash
391 'action' => 'upload',
392 'filekey' => $filekey,
393 'filename' => $fileName,
394 'comment' => 'dummy comment',
395 'text' => "This is the page text for $fileName, altered",
398 $this->clearFakeUploads();
401 list( $result ) = $this->doApiRequestWithToken( $params, $session,
402 self
::$users['uploader']->getUser() );
403 } catch ( ApiUsageException
$e ) {
406 $this->assertTrue( isset( $result['upload'] ) );
407 $this->assertEquals( 'Success', $result['upload']['result'] );
408 $this->assertFalse( $exception, "No ApiUsageException exception." );
411 $this->deleteFileByFileName( $fileName );
417 public function testUploadChunks( $session ) {
418 $this->setMwGlobals( [
419 // @todo FIXME: still used somewhere
420 'wgUser' => self
::$users['uploader']->getUser(),
423 $chunkSize = 1048576;
424 // Download a large image file
425 // (using RandomImageGenerator for large files is not stable)
426 // @todo Don't download files from wikimedia.org
427 $mimeType = 'image/jpeg';
428 $url = 'http://upload.wikimedia.org/wikipedia/commons/'
429 . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
430 $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
432 copy( $url, $filePath );
433 } catch ( Exception
$e ) {
434 $this->markTestIncomplete( $e->getMessage() );
437 $fileSize = filesize( $filePath );
438 $fileName = basename( $filePath );
440 $this->deleteFileByFileName( $fileName );
441 $this->deleteFileByContent( $filePath );
443 // Base upload params:
445 'action' => 'upload',
447 'filename' => $fileName,
448 'filesize' => $fileSize,
453 $chunkSessionKey = false;
456 MediaWiki\
suppressWarnings();
457 $handle = fopen( $filePath, "r" );
458 MediaWiki\restoreWarnings
();
460 if ( $handle === false ) {
461 $this->markTestIncomplete( "could not open file: $filePath" );
464 while ( !feof( $handle ) ) {
465 // Get the current chunk
466 MediaWiki\
suppressWarnings();
467 $chunkData = fread( $handle, $chunkSize );
468 MediaWiki\restoreWarnings
();
470 // Upload the current chunk into the $_FILE object:
471 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
473 // Check for chunkSessionKey
474 if ( !$chunkSessionKey ) {
475 // Upload fist chunk ( and get the session key )
477 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
478 self
::$users['uploader']->getUser() );
479 } catch ( ApiUsageException
$e ) {
480 $this->markTestIncomplete( $e->getMessage() );
482 // Make sure we got a valid chunk continue:
483 $this->assertTrue( isset( $result['upload'] ) );
484 $this->assertTrue( isset( $result['upload']['filekey'] ) );
485 // If we don't get a session key mark test incomplete.
486 if ( !isset( $result['upload']['filekey'] ) ) {
487 $this->markTestIncomplete( "no filekey provided" );
489 $chunkSessionKey = $result['upload']['filekey'];
490 $this->assertEquals( 'Continue', $result['upload']['result'] );
491 // First chunk should have chunkSize == offset
492 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
493 $resultOffset = $result['upload']['offset'];
496 // Filekey set to chunk session
497 $params['filekey'] = $chunkSessionKey;
498 // Update the offset ( always add chunkSize for subquent chunks
499 // should be in-sync with $result['upload']['offset'] )
500 $params['offset'] +
= $chunkSize;
501 // Make sure param offset is insync with resultOffset:
502 $this->assertEquals( $resultOffset, $params['offset'] );
503 // Upload current chunk
505 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
506 self
::$users['uploader']->getUser() );
507 } catch ( ApiUsageException
$e ) {
508 $this->markTestIncomplete( $e->getMessage() );
510 // Make sure we got a valid chunk continue:
511 $this->assertTrue( isset( $result['upload'] ) );
512 $this->assertTrue( isset( $result['upload']['filekey'] ) );
514 // Check if we were on the last chunk:
515 if ( $params['offset'] +
$chunkSize >= $fileSize ) {
516 $this->assertEquals( 'Success', $result['upload']['result'] );
519 $this->assertEquals( 'Continue', $result['upload']['result'] );
520 // update $resultOffset
521 $resultOffset = $result['upload']['offset'];
526 // Check that we got a valid file result:
528 . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
529 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
530 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
531 $this->assertTrue( isset( $result['upload']['filekey'] ) );
532 $filekey = $result['upload']['filekey'];
534 // Now we should try to release the file from stash
536 'action' => 'upload',
537 'filekey' => $filekey,
538 'filename' => $fileName,
539 'comment' => 'dummy comment',
540 'text' => "This is the page text for $fileName, altered",
542 $this->clearFakeUploads();
545 list( $result ) = $this->doApiRequestWithToken( $params, $session,
546 self
::$users['uploader']->getUser() );
547 } catch ( ApiUsageException
$e ) {
550 $this->assertTrue( isset( $result['upload'] ) );
551 $this->assertEquals( 'Success', $result['upload']['result'] );
552 $this->assertFalse( $exception );
555 $this->deleteFileByFileName( $fileName );