MediaWiki REL1_31
ApiUploadTest.php
Go to the documentation of this file.
1<?php
30 public function testLogin() {
31 $user = self::$users['uploader'];
32 $userName = $user->getUser()->getName();
33 $password = $user->getPassword();
34
35 $params = [
36 'action' => 'login',
37 'lgname' => $userName,
38 'lgpassword' => $password
39 ];
40 list( $result, , $session ) = $this->doApiRequest( $params );
41 $this->assertArrayHasKey( "login", $result );
42 $this->assertArrayHasKey( "result", $result['login'] );
43 $this->assertEquals( "NeedToken", $result['login']['result'] );
44 $token = $result['login']['token'];
45
46 $params = [
47 'action' => 'login',
48 'lgtoken' => $token,
49 'lgname' => $userName,
50 'lgpassword' => $password
51 ];
52 list( $result, , $session ) = $this->doApiRequest( $params, $session );
53 $this->assertArrayHasKey( "login", $result );
54 $this->assertArrayHasKey( "result", $result['login'] );
55 $this->assertEquals( "Success", $result['login']['result'] );
56
57 $this->assertNotEmpty( $session, 'API Login must return a session' );
58
59 return $session;
60 }
61
65 public function testUploadRequiresToken( $session ) {
66 $exception = false;
67 try {
68 $this->doApiRequest( [
69 'action' => 'upload'
70 ] );
71 } catch ( ApiUsageException $e ) {
72 $exception = true;
73 $this->assertContains( 'The "token" parameter must be set', $e->getMessage() );
74 }
75 $this->assertTrue( $exception, "Got exception" );
76 }
77
81 public function testUploadMissingParams( $session ) {
82 $exception = false;
83 try {
84 $this->doApiRequestWithToken( [
85 'action' => 'upload',
86 ], $session, self::$users['uploader']->getUser() );
87 } catch ( ApiUsageException $e ) {
88 $exception = true;
89 $this->assertEquals(
90 'One of the parameters "filekey", "file" and "url" is required.',
91 $e->getMessage()
92 );
93 }
94 $this->assertTrue( $exception, "Got exception" );
95 }
96
100 public function testUpload( $session ) {
101 $extension = 'png';
102 $mimeType = 'image/png';
103
104 try {
105 $randomImageGenerator = new RandomImageGenerator();
106 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
107 } catch ( Exception $e ) {
108 $this->markTestIncomplete( $e->getMessage() );
109 }
110
112 $filePath = $filePaths[0];
113 $fileSize = filesize( $filePath );
114 $fileName = basename( $filePath );
115
116 $this->deleteFileByFileName( $fileName );
117 $this->deleteFileByContent( $filePath );
118
119 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
120 $this->markTestIncomplete( "Couldn't upload file!\n" );
121 }
122
123 $params = [
124 'action' => 'upload',
125 'filename' => $fileName,
126 'file' => 'dummy content',
127 'comment' => 'dummy comment',
128 'text' => "This is the page text for $fileName",
129 ];
130
131 $exception = false;
132 try {
133 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
134 self::$users['uploader']->getUser() );
135 } catch ( ApiUsageException $e ) {
136 $exception = true;
137 }
138 $this->assertTrue( isset( $result['upload'] ) );
139 $this->assertEquals( 'Success', $result['upload']['result'] );
140 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
141 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
142 $this->assertFalse( $exception );
143
144 // clean up
145 $this->deleteFileByFileName( $fileName );
146 }
147
151 public function testUploadZeroLength( $session ) {
152 $mimeType = 'image/png';
153
154 $filePath = $this->getNewTempFile();
155 $fileName = "apiTestUploadZeroLength.png";
156
157 $this->deleteFileByFileName( $fileName );
158
159 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
160 $this->markTestIncomplete( "Couldn't upload file!\n" );
161 }
162
163 $params = [
164 'action' => 'upload',
165 'filename' => $fileName,
166 'file' => 'dummy content',
167 'comment' => 'dummy comment',
168 'text' => "This is the page text for $fileName",
169 ];
170
171 $exception = false;
172 try {
173 $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->getUser() );
174 } catch ( ApiUsageException $e ) {
175 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
176 $exception = true;
177 }
178 $this->assertTrue( $exception );
179
180 // clean up
181 $this->deleteFileByFileName( $fileName );
182 }
183
187 public function testUploadSameFileName( $session ) {
188 $extension = 'png';
189 $mimeType = 'image/png';
190
191 try {
192 $randomImageGenerator = new RandomImageGenerator();
193 $filePaths = $randomImageGenerator->writeImages( 2, $extension, $this->getNewTempDirectory() );
194 } catch ( Exception $e ) {
195 $this->markTestIncomplete( $e->getMessage() );
196 }
197
198 // we'll reuse this filename
200 $fileName = basename( $filePaths[0] );
201
202 // clear any other files with the same name
203 $this->deleteFileByFileName( $fileName );
204
205 // we reuse these params
206 $params = [
207 'action' => 'upload',
208 'filename' => $fileName,
209 'file' => 'dummy content',
210 'comment' => 'dummy comment',
211 'text' => "This is the page text for $fileName",
212 ];
213
214 // first upload .... should succeed
215
216 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
217 $this->markTestIncomplete( "Couldn't upload file!\n" );
218 }
219
220 $exception = false;
221 try {
222 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
223 self::$users['uploader']->getUser() );
224 } catch ( ApiUsageException $e ) {
225 $exception = true;
226 }
227 $this->assertTrue( isset( $result['upload'] ) );
228 $this->assertEquals( 'Success', $result['upload']['result'] );
229 $this->assertFalse( $exception );
230
231 // second upload with the same name (but different content)
232
233 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
234 $this->markTestIncomplete( "Couldn't upload file!\n" );
235 }
236
237 $exception = false;
238 try {
239 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
240 self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
241 } catch ( ApiUsageException $e ) {
242 $exception = true;
243 }
244 $this->assertTrue( isset( $result['upload'] ) );
245 $this->assertEquals( 'Warning', $result['upload']['result'] );
246 $this->assertTrue( isset( $result['upload']['warnings'] ) );
247 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
248 $this->assertFalse( $exception );
249
250 // clean up
251 $this->deleteFileByFileName( $fileName );
252 }
253
257 public function testUploadSameContent( $session ) {
258 $extension = 'png';
259 $mimeType = 'image/png';
260
261 try {
262 $randomImageGenerator = new RandomImageGenerator();
263 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
264 } catch ( Exception $e ) {
265 $this->markTestIncomplete( $e->getMessage() );
266 }
267
269 $fileNames[0] = basename( $filePaths[0] );
270 $fileNames[1] = "SameContentAs" . $fileNames[0];
271
272 // clear any other files with the same name or content
273 $this->deleteFileByContent( $filePaths[0] );
274 $this->deleteFileByFileName( $fileNames[0] );
275 $this->deleteFileByFileName( $fileNames[1] );
276
277 // first upload .... should succeed
278
279 $params = [
280 'action' => 'upload',
281 'filename' => $fileNames[0],
282 'file' => 'dummy content',
283 'comment' => 'dummy comment',
284 'text' => "This is the page text for " . $fileNames[0],
285 ];
286
287 if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
288 $this->markTestIncomplete( "Couldn't upload file!\n" );
289 }
290
291 $exception = false;
292 try {
293 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
294 self::$users['uploader']->getUser() );
295 } catch ( ApiUsageException $e ) {
296 $exception = true;
297 }
298 $this->assertTrue( isset( $result['upload'] ) );
299 $this->assertEquals( 'Success', $result['upload']['result'] );
300 $this->assertFalse( $exception );
301
302 // second upload with the same content (but different name)
303
304 if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
305 $this->markTestIncomplete( "Couldn't upload file!\n" );
306 }
307
308 $params = [
309 'action' => 'upload',
310 'filename' => $fileNames[1],
311 'file' => 'dummy content',
312 'comment' => 'dummy comment',
313 'text' => "This is the page text for " . $fileNames[1],
314 ];
315
316 $exception = false;
317 try {
318 list( $result ) = $this->doApiRequestWithToken( $params, $session,
319 self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
320 } catch ( ApiUsageException $e ) {
321 $exception = true;
322 }
323 $this->assertTrue( isset( $result['upload'] ) );
324 $this->assertEquals( 'Warning', $result['upload']['result'] );
325 $this->assertTrue( isset( $result['upload']['warnings'] ) );
326 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
327 $this->assertFalse( $exception );
328
329 // clean up
330 $this->deleteFileByFileName( $fileNames[0] );
331 $this->deleteFileByFileName( $fileNames[1] );
332 }
333
337 public function testUploadStash( $session ) {
338 $this->setMwGlobals( [
339 'wgUser' => self::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
340 ] );
341
342 $extension = 'png';
343 $mimeType = 'image/png';
344
345 try {
346 $randomImageGenerator = new RandomImageGenerator();
347 $filePaths = $randomImageGenerator->writeImages( 1, $extension, $this->getNewTempDirectory() );
348 } catch ( Exception $e ) {
349 $this->markTestIncomplete( $e->getMessage() );
350 }
351
353 $filePath = $filePaths[0];
354 $fileSize = filesize( $filePath );
355 $fileName = basename( $filePath );
356
357 $this->deleteFileByFileName( $fileName );
358 $this->deleteFileByContent( $filePath );
359
360 if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
361 $this->markTestIncomplete( "Couldn't upload file!\n" );
362 }
363
364 $params = [
365 'action' => 'upload',
366 'stash' => 1,
367 'filename' => $fileName,
368 'file' => 'dummy content',
369 'comment' => 'dummy comment',
370 'text' => "This is the page text for $fileName",
371 ];
372
373 $exception = false;
374 try {
375 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
376 self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
377 } catch ( ApiUsageException $e ) {
378 $exception = true;
379 }
380 $this->assertFalse( $exception );
381 $this->assertTrue( isset( $result['upload'] ) );
382 $this->assertEquals( 'Success', $result['upload']['result'] );
383 $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
384 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
385 $this->assertTrue( isset( $result['upload']['filekey'] ) );
386 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
387 $filekey = $result['upload']['filekey'];
388
389 // it should be visible from Special:UploadStash
390 // XXX ...but how to test this, with a fake WebRequest with the session?
391
392 // now we should try to release the file from stash
393 $params = [
394 'action' => 'upload',
395 'filekey' => $filekey,
396 'filename' => $fileName,
397 'comment' => 'dummy comment',
398 'text' => "This is the page text for $fileName, altered",
399 ];
400
401 $this->clearFakeUploads();
402 $exception = false;
403 try {
404 list( $result ) = $this->doApiRequestWithToken( $params, $session,
405 self::$users['uploader']->getUser() );
406 } catch ( ApiUsageException $e ) {
407 $exception = true;
408 }
409 $this->assertTrue( isset( $result['upload'] ) );
410 $this->assertEquals( 'Success', $result['upload']['result'] );
411 $this->assertFalse( $exception, "No ApiUsageException exception." );
412
413 // clean up
414 $this->deleteFileByFileName( $fileName );
415 }
416
420 public function testUploadChunks( $session ) {
421 $this->setMwGlobals( [
422 // @todo FIXME: still used somewhere
423 'wgUser' => self::$users['uploader']->getUser(),
424 ] );
425
426 $chunkSize = 1048576;
427 // Download a large image file
428 // (using RandomImageGenerator for large files is not stable)
429 // @todo Don't download files from wikimedia.org
430 $mimeType = 'image/jpeg';
431 $url = 'http://upload.wikimedia.org/wikipedia/commons/'
432 . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
433 $filePath = $this->getNewTempDirectory() . '/Oberaargletscher_from_Oberaar.jpg';
434 try {
435 copy( $url, $filePath );
436 } catch ( Exception $e ) {
437 $this->markTestIncomplete( $e->getMessage() );
438 }
439
440 $fileSize = filesize( $filePath );
441 $fileName = basename( $filePath );
442
443 $this->deleteFileByFileName( $fileName );
444 $this->deleteFileByContent( $filePath );
445
446 // Base upload params:
447 $params = [
448 'action' => 'upload',
449 'stash' => 1,
450 'filename' => $fileName,
451 'filesize' => $fileSize,
452 'offset' => 0,
453 ];
454
455 // Upload chunks
456 $chunkSessionKey = false;
457 $resultOffset = 0;
458 // Open the file:
459 Wikimedia\suppressWarnings();
460 $handle = fopen( $filePath, "r" );
461 Wikimedia\restoreWarnings();
462
463 if ( $handle === false ) {
464 $this->markTestIncomplete( "could not open file: $filePath" );
465 }
466
467 while ( !feof( $handle ) ) {
468 // Get the current chunk
469 Wikimedia\suppressWarnings();
470 $chunkData = fread( $handle, $chunkSize );
471 Wikimedia\restoreWarnings();
472
473 // Upload the current chunk into the $_FILE object:
474 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
475
476 // Check for chunkSessionKey
477 if ( !$chunkSessionKey ) {
478 // Upload fist chunk ( and get the session key )
479 try {
480 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
481 self::$users['uploader']->getUser() );
482 } catch ( ApiUsageException $e ) {
483 $this->markTestIncomplete( $e->getMessage() );
484 }
485 // Make sure we got a valid chunk continue:
486 $this->assertTrue( isset( $result['upload'] ) );
487 $this->assertTrue( isset( $result['upload']['filekey'] ) );
488 // If we don't get a session key mark test incomplete.
489 if ( !isset( $result['upload']['filekey'] ) ) {
490 $this->markTestIncomplete( "no filekey provided" );
491 }
492 $chunkSessionKey = $result['upload']['filekey'];
493 $this->assertEquals( 'Continue', $result['upload']['result'] );
494 // First chunk should have chunkSize == offset
495 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
496 $resultOffset = $result['upload']['offset'];
497 continue;
498 }
499 // Filekey set to chunk session
500 $params['filekey'] = $chunkSessionKey;
501 // Update the offset ( always add chunkSize for subquent chunks
502 // should be in-sync with $result['upload']['offset'] )
503 $params['offset'] += $chunkSize;
504 // Make sure param offset is insync with resultOffset:
505 $this->assertEquals( $resultOffset, $params['offset'] );
506 // Upload current chunk
507 try {
508 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
509 self::$users['uploader']->getUser() );
510 } catch ( ApiUsageException $e ) {
511 $this->markTestIncomplete( $e->getMessage() );
512 }
513 // Make sure we got a valid chunk continue:
514 $this->assertTrue( isset( $result['upload'] ) );
515 $this->assertTrue( isset( $result['upload']['filekey'] ) );
516
517 // Check if we were on the last chunk:
518 if ( $params['offset'] + $chunkSize >= $fileSize ) {
519 $this->assertEquals( 'Success', $result['upload']['result'] );
520 break;
521 } else {
522 $this->assertEquals( 'Continue', $result['upload']['result'] );
523 // update $resultOffset
524 $resultOffset = $result['upload']['offset'];
525 }
526 }
527 fclose( $handle );
528
529 // Check that we got a valid file result:
530 wfDebug( __METHOD__
531 . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
532 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
533 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
534 $this->assertTrue( isset( $result['upload']['filekey'] ) );
535 $filekey = $result['upload']['filekey'];
536
537 // Now we should try to release the file from stash
538 $params = [
539 'action' => 'upload',
540 'filekey' => $filekey,
541 'filename' => $fileName,
542 'comment' => 'dummy comment',
543 'text' => "This is the page text for $fileName, altered",
544 ];
545 $this->clearFakeUploads();
546 $exception = false;
547 try {
548 list( $result ) = $this->doApiRequestWithToken( $params, $session,
549 self::$users['uploader']->getUser() );
550 } catch ( ApiUsageException $e ) {
551 $exception = true;
552 }
553 $this->assertTrue( isset( $result['upload'] ) );
554 $this->assertEquals( 'Success', $result['upload']['result'] );
555 $this->assertFalse( $exception );
556
557 // clean up
558 $this->deleteFileByFileName( $fileName );
559 }
560}
and give any other recipients of the Program a copy of this License along with the Program You may charge a fee for the physical act of transferring a copy
Definition COPYING.txt:87
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
doApiRequestWithToken(array $params, array $session=null, User $user=null, $tokenType='auto')
Convenience function to access the token parameter of doApiRequest() more succinctly.
doApiRequest(array $params, array $session=null, $appendModule=false, User $user=null, $tokenType=null)
Does the API request and returns the result.
Abstract class to support upload tests.
clearFakeUploads()
Remove traces of previous fake uploads.
fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData)
deleteFileByContent( $filePath)
Helper function – given a file on the filesystem, find matching content in the db (and associated art...
deleteFileByFileName( $fileName)
Helper function – remove files and associated articles with a particular filename.
fakeUploadFile( $fieldName, $fileName, $type, $filePath)
Fake an upload by dumping the file into temp space, and adding info to $_FILES.
testUploadZeroLength( $session)
@depends testLogin
testUploadStash( $session)
@depends testLogin
testLogin()
Testing login XXX this is a funny way of getting session context.
testUploadSameContent( $session)
@depends testLogin
testUploadRequiresToken( $session)
@depends testLogin
testUploadMissingParams( $session)
@depends testLogin
testUploadSameFileName( $session)
@depends testLogin
testUpload( $session)
@depends testLogin
testUploadChunks( $session)
@depends testLogin
Exception used to abort API execution with an error.
getNewTempFile()
Obtains a new temporary file name.
setMwGlobals( $pairs, $value=null)
Sets a global, maintaining a stashed version of the previous global to be restored in tearDown.
getNewTempDirectory()
obtains a new temporary directory
RandomImageGenerator: does what it says on the tin.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition deferred.txt:11
returning false will NOT prevent logging $e
Definition hooks.txt:2176
$params