Merge "(bug 44459) Ensure jqueryMsg treats plain messages as plain, with tests."
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiUploadTest.php
1 <?php
2
3 /**
4 * @group API
5 * @group Database
6 */
7
8 /**
9 * n.b. Ensure that you can write to the images/ directory as the
10 * user that will run tests.
11 */
12
13 // Note for reviewers: this intentionally duplicates functionality already in "ApiSetup" and so on.
14 // This framework works better IMO and has less strangeness (such as test cases inheriting from "ApiSetup"...)
15 // (and in the case of the other Upload tests, this flat out just actually works... )
16
17 // TODO: port the other Upload tests, and other API tests to this framework
18
19 require_once( 'ApiTestCaseUpload.php' );
20
21 /**
22 * @group Database
23 * @group Broken
24 * Broken test, reports false errors from time to time.
25 * See https://bugzilla.wikimedia.org/26169
26 *
27 * This is pretty sucky... needs to be prettified.
28 */
29 class ApiUploadTest extends ApiTestCaseUpload {
30
31 /**
32 * Testing login
33 * XXX this is a funny way of getting session context
34 */
35 function testLogin() {
36 $user = self::$users['uploader'];
37
38 $params = array(
39 'action' => 'login',
40 'lgname' => $user->username,
41 'lgpassword' => $user->password
42 );
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'];
48
49 $params = array(
50 'action' => 'login',
51 'lgtoken' => $token,
52 'lgname' => $user->username,
53 'lgpassword' => $user->password
54 );
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'] );
60
61 $this->assertNotEmpty( $session, 'API Login must return a session' );
62 return $session;
63
64 }
65
66 /**
67 * @depends testLogin
68 */
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() );
78 }
79 $this->assertTrue( $exception, "Got exception" );
80 }
81
82 /**
83 * @depends testLogin
84 */
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() );
95 }
96 $this->assertTrue( $exception, "Got exception" );
97 }
98
99
100 /**
101 * @depends testLogin
102 */
103 public function testUpload( $session ) {
104 $extension = 'png';
105 $mimeType = 'image/png';
106
107 try {
108 $randomImageGenerator = new RandomImageGenerator();
109 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
110 }
111 catch ( Exception $e ) {
112 $this->markTestIncomplete( $e->getMessage() );
113 }
114
115 $filePath = $filePaths[0];
116 $fileSize = filesize( $filePath );
117 $fileName = basename( $filePath );
118
119 $this->deleteFileByFileName( $fileName );
120 $this->deleteFileByContent( $filePath );
121
122
123 if (! $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
124 $this->markTestIncomplete( "Couldn't upload file!\n" );
125 }
126
127 $params = array(
128 'action' => 'upload',
129 'filename' => $fileName,
130 'file' => 'dummy content',
131 'comment' => 'dummy comment',
132 'text' => "This is the page text for $fileName",
133 );
134
135 $exception = false;
136 try {
137 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
138 self::$users['uploader']->user );
139 } catch ( UsageException $e ) {
140 $exception = true;
141 }
142 $this->assertTrue( isset( $result['upload'] ) );
143 $this->assertEquals( 'Success', $result['upload']['result'] );
144 $this->assertEquals( $fileSize, ( int )$result['upload']['imageinfo']['size'] );
145 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
146 $this->assertFalse( $exception );
147
148 // clean up
149 $this->deleteFileByFilename( $fileName );
150 unlink( $filePath );
151 }
152
153
154 /**
155 * @depends testLogin
156 */
157 public function testUploadZeroLength( $session ) {
158 $mimeType = 'image/png';
159
160 $filePath = tempnam( wfTempDir(), "" );
161 $fileName = "apiTestUploadZeroLength.png";
162
163 $this->deleteFileByFileName( $fileName );
164
165 if (! $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
166 $this->markTestIncomplete( "Couldn't upload file!\n" );
167 }
168
169 $params = array(
170 'action' => 'upload',
171 'filename' => $fileName,
172 'file' => 'dummy content',
173 'comment' => 'dummy comment',
174 'text' => "This is the page text for $fileName",
175 );
176
177 $exception = false;
178 try {
179 $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
180 } catch ( UsageException $e ) {
181 $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
182 $exception = true;
183 }
184 $this->assertTrue( $exception );
185
186 // clean up
187 $this->deleteFileByFilename( $fileName );
188 unlink( $filePath );
189 }
190
191
192 /**
193 * @depends testLogin
194 */
195 public function testUploadSameFileName( $session ) {
196 $extension = 'png';
197 $mimeType = 'image/png';
198
199 try {
200 $randomImageGenerator = new RandomImageGenerator();
201 $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
202 }
203 catch ( Exception $e ) {
204 $this->markTestIncomplete( $e->getMessage() );
205 }
206
207 // we'll reuse this filename
208 $fileName = basename( $filePaths[0] );
209
210 // clear any other files with the same name
211 $this->deleteFileByFileName( $fileName );
212
213 // we reuse these params
214 $params = array(
215 'action' => 'upload',
216 'filename' => $fileName,
217 'file' => 'dummy content',
218 'comment' => 'dummy comment',
219 'text' => "This is the page text for $fileName",
220 );
221
222 // first upload .... should succeed
223
224 if (! $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
225 $this->markTestIncomplete( "Couldn't upload file!\n" );
226 }
227
228 $exception = false;
229 try {
230 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
231 self::$users['uploader']->user );
232 } catch ( UsageException $e ) {
233 $exception = true;
234 }
235 $this->assertTrue( isset( $result['upload'] ) );
236 $this->assertEquals( 'Success', $result['upload']['result'] );
237 $this->assertFalse( $exception );
238
239 // second upload with the same name (but different content)
240
241 if (! $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
242 $this->markTestIncomplete( "Couldn't upload file!\n" );
243 }
244
245 $exception = false;
246 try {
247 list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
248 self::$users['uploader']->user ); // FIXME: leaks a temporary file
249 } catch ( UsageException $e ) {
250 $exception = true;
251 }
252 $this->assertTrue( isset( $result['upload'] ) );
253 $this->assertEquals( 'Warning', $result['upload']['result'] );
254 $this->assertTrue( isset( $result['upload']['warnings'] ) );
255 $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
256 $this->assertFalse( $exception );
257
258 // clean up
259 $this->deleteFileByFilename( $fileName );
260 unlink( $filePaths[0] );
261 unlink( $filePaths[1] );
262 }
263
264
265 /**
266 * @depends testLogin
267 */
268 public function testUploadSameContent( $session ) {
269 $extension = 'png';
270 $mimeType = 'image/png';
271
272 try {
273 $randomImageGenerator = new RandomImageGenerator();
274 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
275 }
276 catch ( Exception $e ) {
277 $this->markTestIncomplete( $e->getMessage() );
278 }
279
280 $fileNames[0] = basename( $filePaths[0] );
281 $fileNames[1] = "SameContentAs" . $fileNames[0];
282
283 // clear any other files with the same name or content
284 $this->deleteFileByContent( $filePaths[0] );
285 $this->deleteFileByFileName( $fileNames[0] );
286 $this->deleteFileByFileName( $fileNames[1] );
287
288 // first upload .... should succeed
289
290 $params = array(
291 'action' => 'upload',
292 'filename' => $fileNames[0],
293 'file' => 'dummy content',
294 'comment' => 'dummy comment',
295 'text' => "This is the page text for " . $fileNames[0],
296 );
297
298 if (! $this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
299 $this->markTestIncomplete( "Couldn't upload file!\n" );
300 }
301
302 $exception = false;
303 try {
304 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
305 self::$users['uploader']->user );
306 } catch ( UsageException $e ) {
307 $exception = true;
308 }
309 $this->assertTrue( isset( $result['upload'] ) );
310 $this->assertEquals( 'Success', $result['upload']['result'] );
311 $this->assertFalse( $exception );
312
313
314 // second upload with the same content (but different name)
315
316 if (! $this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
317 $this->markTestIncomplete( "Couldn't upload file!\n" );
318 }
319
320 $params = array(
321 'action' => 'upload',
322 'filename' => $fileNames[1],
323 'file' => 'dummy content',
324 'comment' => 'dummy comment',
325 'text' => "This is the page text for " . $fileNames[1],
326 );
327
328 $exception = false;
329 try {
330 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
331 self::$users['uploader']->user ); // FIXME: leaks a temporary file
332 } catch ( UsageException $e ) {
333 $exception = true;
334 }
335 $this->assertTrue( isset( $result['upload'] ) );
336 $this->assertEquals( 'Warning', $result['upload']['result'] );
337 $this->assertTrue( isset( $result['upload']['warnings'] ) );
338 $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
339 $this->assertFalse( $exception );
340
341 // clean up
342 $this->deleteFileByFilename( $fileNames[0] );
343 $this->deleteFileByFilename( $fileNames[1] );
344 unlink( $filePaths[0] );
345 }
346
347
348 /**
349 * @depends testLogin
350 */
351 public function testUploadStash( $session ) {
352 $this->setMwGlobals( array(
353 'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
354 ) );
355
356 $extension = 'png';
357 $mimeType = 'image/png';
358
359 try {
360 $randomImageGenerator = new RandomImageGenerator();
361 $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
362 }
363 catch ( Exception $e ) {
364 $this->markTestIncomplete( $e->getMessage() );
365 }
366
367 $filePath = $filePaths[0];
368 $fileSize = filesize( $filePath );
369 $fileName = basename( $filePath );
370
371 $this->deleteFileByFileName( $fileName );
372 $this->deleteFileByContent( $filePath );
373
374 if (! $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
375 $this->markTestIncomplete( "Couldn't upload file!\n" );
376 }
377
378 $params = array(
379 'action' => 'upload',
380 'stash' => 1,
381 'filename' => $fileName,
382 'file' => 'dummy content',
383 'comment' => 'dummy comment',
384 'text' => "This is the page text for $fileName",
385 );
386
387 $exception = false;
388 try {
389 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
390 self::$users['uploader']->user ); // FIXME: leaks a temporary file
391 } catch ( UsageException $e ) {
392 $exception = true;
393 }
394 $this->assertFalse( $exception );
395 $this->assertTrue( isset( $result['upload'] ) );
396 $this->assertEquals( 'Success', $result['upload']['result'] );
397 $this->assertEquals( $fileSize, ( int )$result['upload']['imageinfo']['size'] );
398 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
399 $this->assertTrue( isset( $result['upload']['filekey'] ) );
400 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
401 $filekey = $result['upload']['filekey'];
402
403 // it should be visible from Special:UploadStash
404 // XXX ...but how to test this, with a fake WebRequest with the session?
405
406 // now we should try to release the file from stash
407 $params = array(
408 'action' => 'upload',
409 'filekey' => $filekey,
410 'filename' => $fileName,
411 'comment' => 'dummy comment',
412 'text' => "This is the page text for $fileName, altered",
413 );
414
415 $this->clearFakeUploads();
416 $exception = false;
417 try {
418 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
419 self::$users['uploader']->user );
420 } catch ( UsageException $e ) {
421 $exception = true;
422 }
423 $this->assertTrue( isset( $result['upload'] ) );
424 $this->assertEquals( 'Success', $result['upload']['result'] );
425 $this->assertFalse( $exception, "No UsageException exception." );
426
427 // clean up
428 $this->deleteFileByFilename( $fileName );
429 unlink( $filePath );
430 }
431
432
433 /**
434 * @depends testLogin
435 */
436 public function testUploadChunks( $session ) {
437 $this->setMwGlobals( array(
438 'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
439 ) );
440
441 $chunkSize = 1048576;
442 // Download a large image file
443 // ( using RandomImageGenerator for large files is not stable )
444 $mimeType = 'image/jpeg';
445 $url = 'http://upload.wikimedia.org/wikipedia/commons/e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
446 $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg';
447 try {
448 // Only download if the file is not avaliable in the temp location:
449 if( !is_file( $filePath ) ){
450 copy($url, $filePath);
451 }
452 }
453 catch ( Exception $e ) {
454 $this->markTestIncomplete( $e->getMessage() );
455 }
456
457 $fileSize = filesize( $filePath );
458 $fileName = basename( $filePath );
459
460 $this->deleteFileByFileName( $fileName );
461 $this->deleteFileByContent( $filePath );
462
463 // Base upload params:
464 $params = array(
465 'action' => 'upload',
466 'stash' => 1,
467 'filename' => $fileName,
468 'filesize' => $fileSize,
469 'offset' => 0,
470 );
471
472 // Upload chunks
473 $chunkSessionKey = false;
474 $resultOffset = 0;
475 // Open the file:
476 $handle = @fopen ($filePath, "r");
477 if( $handle === false ){
478 $this->markTestIncomplete( "could not open file: $filePath" );
479 }
480 while (!feof ($handle)) {
481 // Get the current chunk
482 $chunkData = @fread( $handle, $chunkSize );
483
484 // Upload the current chunk into the $_FILE object:
485 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
486
487 // Check for chunkSessionKey
488 if( !$chunkSessionKey ){
489 // Upload fist chunk ( and get the session key )
490 try {
491 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
492 self::$users['uploader']->user );
493 } catch ( UsageException $e ) {
494 $this->markTestIncomplete( $e->getMessage() );
495 }
496 // Make sure we got a valid chunk continue:
497 $this->assertTrue( isset( $result['upload'] ) );
498 $this->assertTrue( isset( $result['upload']['filekey'] ) );
499 // If we don't get a session key mark test incomplete.
500 if( ! isset( $result['upload']['filekey'] ) ){
501 $this->markTestIncomplete( "no filekey provided" );
502 }
503 $chunkSessionKey = $result['upload']['filekey'];
504 $this->assertEquals( 'Continue', $result['upload']['result'] );
505 // First chunk should have chunkSize == offset
506 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
507 $resultOffset = $result['upload']['offset'];
508 continue;
509 }
510 // Filekey set to chunk session
511 $params['filekey'] = $chunkSessionKey;
512 // Update the offset ( always add chunkSize for subquent chunks 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, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
519 self::$users['uploader']->user );
520 } catch ( UsageException $e ) {
521 $this->markTestIncomplete( $e->getMessage() );
522 }
523 // Make sure we got a valid chunk continue:
524 $this->assertTrue( isset( $result['upload'] ) );
525 $this->assertTrue( isset( $result['upload']['filekey'] ) );
526
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'];
535 }
536 }
537 fclose ($handle);
538
539 // Check that we got a valid file result:
540 wfDebug( __METHOD__ . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n");
541 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
542 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
543 $this->assertTrue( isset( $result['upload']['filekey'] ) );
544 $filekey = $result['upload']['filekey'];
545
546 // Now we should try to release the file from stash
547 $params = array(
548 'action' => 'upload',
549 'filekey' => $filekey,
550 'filename' => $fileName,
551 'comment' => 'dummy comment',
552 'text' => "This is the page text for $fileName, altered",
553 );
554 $this->clearFakeUploads();
555 $exception = false;
556 try {
557 list( $result, $request, $session ) = $this->doApiRequestWithToken( $params, $session,
558 self::$users['uploader']->user );
559 } catch ( UsageException $e ) {
560 $exception = true;
561 }
562 $this->assertTrue( isset( $result['upload'] ) );
563 $this->assertEquals( 'Success', $result['upload']['result'] );
564 $this->assertFalse( $exception );
565
566 // clean up
567 $this->deleteFileByFilename( $fileName );
568 // don't remove downloaded temporary file for fast subquent tests.
569 //unlink( $filePath );
570 }
571 }