MediaWiki  REL1_24
ApiUploadTest.php
Go to the documentation of this file.
00001 <?php
00013 // Note for reviewers: this intentionally duplicates functionality already in
00014 // "ApiSetup" and so on. This framework works better IMO and has less
00015 // strangeness (such as test cases inheriting from "ApiSetup"...) (and in the
00016 // case of the other Upload tests, this flat out just actually works... )
00017 
00018 // @todo Port the other Upload tests, and other API tests to this framework
00019 
00020 require_once 'ApiTestCaseUpload.php';
00021 
00030 class ApiUploadTest extends ApiTestCaseUpload {
00035     public function testLogin() {
00036         $user = self::$users['uploader'];
00037 
00038         $params = array(
00039             'action' => 'login',
00040             'lgname' => $user->username,
00041             'lgpassword' => $user->password
00042         );
00043         list( $result, , $session ) = $this->doApiRequest( $params );
00044         $this->assertArrayHasKey( "login", $result );
00045         $this->assertArrayHasKey( "result", $result['login'] );
00046         $this->assertEquals( "NeedToken", $result['login']['result'] );
00047         $token = $result['login']['token'];
00048 
00049         $params = array(
00050             'action' => 'login',
00051             'lgtoken' => $token,
00052             'lgname' => $user->username,
00053             'lgpassword' => $user->password
00054         );
00055         list( $result, , $session ) = $this->doApiRequest( $params, $session );
00056         $this->assertArrayHasKey( "login", $result );
00057         $this->assertArrayHasKey( "result", $result['login'] );
00058         $this->assertEquals( "Success", $result['login']['result'] );
00059         $this->assertArrayHasKey( 'lgtoken', $result['login'] );
00060 
00061         $this->assertNotEmpty( $session, 'API Login must return a session' );
00062 
00063         return $session;
00064     }
00065 
00069     public function testUploadRequiresToken( $session ) {
00070         $exception = false;
00071         try {
00072             $this->doApiRequest( array(
00073                 'action' => 'upload'
00074             ) );
00075         } catch ( UsageException $e ) {
00076             $exception = true;
00077             $this->assertEquals( "The token parameter must be set", $e->getMessage() );
00078         }
00079         $this->assertTrue( $exception, "Got exception" );
00080     }
00081 
00085     public function testUploadMissingParams( $session ) {
00086         $exception = false;
00087         try {
00088             $this->doApiRequestWithToken( array(
00089                 'action' => 'upload',
00090             ), $session, self::$users['uploader']->user );
00091         } catch ( UsageException $e ) {
00092             $exception = true;
00093             $this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
00094                 $e->getMessage() );
00095         }
00096         $this->assertTrue( $exception, "Got exception" );
00097     }
00098 
00102     public function testUpload( $session ) {
00103         $extension = 'png';
00104         $mimeType = 'image/png';
00105 
00106         try {
00107             $randomImageGenerator = new RandomImageGenerator();
00108             $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
00109         } catch ( Exception $e ) {
00110             $this->markTestIncomplete( $e->getMessage() );
00111         }
00112 
00114         $filePath = $filePaths[0];
00115         $fileSize = filesize( $filePath );
00116         $fileName = basename( $filePath );
00117 
00118         $this->deleteFileByFileName( $fileName );
00119         $this->deleteFileByContent( $filePath );
00120 
00121         if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
00122             $this->markTestIncomplete( "Couldn't upload file!\n" );
00123         }
00124 
00125         $params = array(
00126             'action' => 'upload',
00127             'filename' => $fileName,
00128             'file' => 'dummy content',
00129             'comment' => 'dummy comment',
00130             'text' => "This is the page text for $fileName",
00131         );
00132 
00133         $exception = false;
00134         try {
00135             list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
00136                 self::$users['uploader']->user );
00137         } catch ( UsageException $e ) {
00138             $exception = true;
00139         }
00140         $this->assertTrue( isset( $result['upload'] ) );
00141         $this->assertEquals( 'Success', $result['upload']['result'] );
00142         $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
00143         $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
00144         $this->assertFalse( $exception );
00145 
00146         // clean up
00147         $this->deleteFileByFilename( $fileName );
00148         unlink( $filePath );
00149     }
00150 
00154     public function testUploadZeroLength( $session ) {
00155         $mimeType = 'image/png';
00156 
00157         $filePath = tempnam( wfTempDir(), "" );
00158         $fileName = "apiTestUploadZeroLength.png";
00159 
00160         $this->deleteFileByFileName( $fileName );
00161 
00162         if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
00163             $this->markTestIncomplete( "Couldn't upload file!\n" );
00164         }
00165 
00166         $params = array(
00167             'action' => 'upload',
00168             'filename' => $fileName,
00169             'file' => 'dummy content',
00170             'comment' => 'dummy comment',
00171             'text' => "This is the page text for $fileName",
00172         );
00173 
00174         $exception = false;
00175         try {
00176             $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
00177         } catch ( UsageException $e ) {
00178             $this->assertContains( 'The file you submitted was empty', $e->getMessage() );
00179             $exception = true;
00180         }
00181         $this->assertTrue( $exception );
00182 
00183         // clean up
00184         $this->deleteFileByFilename( $fileName );
00185         unlink( $filePath );
00186     }
00187 
00191     public function testUploadSameFileName( $session ) {
00192         $extension = 'png';
00193         $mimeType = 'image/png';
00194 
00195         try {
00196             $randomImageGenerator = new RandomImageGenerator();
00197             $filePaths = $randomImageGenerator->writeImages( 2, $extension, wfTempDir() );
00198         } catch ( Exception $e ) {
00199             $this->markTestIncomplete( $e->getMessage() );
00200         }
00201 
00202         // we'll reuse this filename
00204         $fileName = basename( $filePaths[0] );
00205 
00206         // clear any other files with the same name
00207         $this->deleteFileByFileName( $fileName );
00208 
00209         // we reuse these params
00210         $params = array(
00211             'action' => 'upload',
00212             'filename' => $fileName,
00213             'file' => 'dummy content',
00214             'comment' => 'dummy comment',
00215             'text' => "This is the page text for $fileName",
00216         );
00217 
00218         // first upload .... should succeed
00219 
00220         if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] ) ) {
00221             $this->markTestIncomplete( "Couldn't upload file!\n" );
00222         }
00223 
00224         $exception = false;
00225         try {
00226             list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
00227                 self::$users['uploader']->user );
00228         } catch ( UsageException $e ) {
00229             $exception = true;
00230         }
00231         $this->assertTrue( isset( $result['upload'] ) );
00232         $this->assertEquals( 'Success', $result['upload']['result'] );
00233         $this->assertFalse( $exception );
00234 
00235         // second upload with the same name (but different content)
00236 
00237         if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] ) ) {
00238             $this->markTestIncomplete( "Couldn't upload file!\n" );
00239         }
00240 
00241         $exception = false;
00242         try {
00243             list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
00244                 self::$users['uploader']->user ); // FIXME: leaks a temporary file
00245         } catch ( UsageException $e ) {
00246             $exception = true;
00247         }
00248         $this->assertTrue( isset( $result['upload'] ) );
00249         $this->assertEquals( 'Warning', $result['upload']['result'] );
00250         $this->assertTrue( isset( $result['upload']['warnings'] ) );
00251         $this->assertTrue( isset( $result['upload']['warnings']['exists'] ) );
00252         $this->assertFalse( $exception );
00253 
00254         // clean up
00255         $this->deleteFileByFilename( $fileName );
00256         unlink( $filePaths[0] );
00257         unlink( $filePaths[1] );
00258     }
00259 
00263     public function testUploadSameContent( $session ) {
00264         $extension = 'png';
00265         $mimeType = 'image/png';
00266 
00267         try {
00268             $randomImageGenerator = new RandomImageGenerator();
00269             $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
00270         } catch ( Exception $e ) {
00271             $this->markTestIncomplete( $e->getMessage() );
00272         }
00273 
00275         $fileNames[0] = basename( $filePaths[0] );
00276         $fileNames[1] = "SameContentAs" . $fileNames[0];
00277 
00278         // clear any other files with the same name or content
00279         $this->deleteFileByContent( $filePaths[0] );
00280         $this->deleteFileByFileName( $fileNames[0] );
00281         $this->deleteFileByFileName( $fileNames[1] );
00282 
00283         // first upload .... should succeed
00284 
00285         $params = array(
00286             'action' => 'upload',
00287             'filename' => $fileNames[0],
00288             'file' => 'dummy content',
00289             'comment' => 'dummy comment',
00290             'text' => "This is the page text for " . $fileNames[0],
00291         );
00292 
00293         if ( !$this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePaths[0] ) ) {
00294             $this->markTestIncomplete( "Couldn't upload file!\n" );
00295         }
00296 
00297         $exception = false;
00298         try {
00299             list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
00300                 self::$users['uploader']->user );
00301         } catch ( UsageException $e ) {
00302             $exception = true;
00303         }
00304         $this->assertTrue( isset( $result['upload'] ) );
00305         $this->assertEquals( 'Success', $result['upload']['result'] );
00306         $this->assertFalse( $exception );
00307 
00308         // second upload with the same content (but different name)
00309 
00310         if ( !$this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePaths[0] ) ) {
00311             $this->markTestIncomplete( "Couldn't upload file!\n" );
00312         }
00313 
00314         $params = array(
00315             'action' => 'upload',
00316             'filename' => $fileNames[1],
00317             'file' => 'dummy content',
00318             'comment' => 'dummy comment',
00319             'text' => "This is the page text for " . $fileNames[1],
00320         );
00321 
00322         $exception = false;
00323         try {
00324             list( $result ) = $this->doApiRequestWithToken( $params, $session,
00325                 self::$users['uploader']->user ); // FIXME: leaks a temporary file
00326         } catch ( UsageException $e ) {
00327             $exception = true;
00328         }
00329         $this->assertTrue( isset( $result['upload'] ) );
00330         $this->assertEquals( 'Warning', $result['upload']['result'] );
00331         $this->assertTrue( isset( $result['upload']['warnings'] ) );
00332         $this->assertTrue( isset( $result['upload']['warnings']['duplicate'] ) );
00333         $this->assertFalse( $exception );
00334 
00335         // clean up
00336         $this->deleteFileByFilename( $fileNames[0] );
00337         $this->deleteFileByFilename( $fileNames[1] );
00338         unlink( $filePaths[0] );
00339     }
00340 
00344     public function testUploadStash( $session ) {
00345         $this->setMwGlobals( array(
00346             'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
00347         ) );
00348 
00349         $extension = 'png';
00350         $mimeType = 'image/png';
00351 
00352         try {
00353             $randomImageGenerator = new RandomImageGenerator();
00354             $filePaths = $randomImageGenerator->writeImages( 1, $extension, wfTempDir() );
00355         } catch ( Exception $e ) {
00356             $this->markTestIncomplete( $e->getMessage() );
00357         }
00358 
00360         $filePath = $filePaths[0];
00361         $fileSize = filesize( $filePath );
00362         $fileName = basename( $filePath );
00363 
00364         $this->deleteFileByFileName( $fileName );
00365         $this->deleteFileByContent( $filePath );
00366 
00367         if ( !$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath ) ) {
00368             $this->markTestIncomplete( "Couldn't upload file!\n" );
00369         }
00370 
00371         $params = array(
00372             'action' => 'upload',
00373             'stash' => 1,
00374             'filename' => $fileName,
00375             'file' => 'dummy content',
00376             'comment' => 'dummy comment',
00377             'text' => "This is the page text for $fileName",
00378         );
00379 
00380         $exception = false;
00381         try {
00382             list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
00383                 self::$users['uploader']->user ); // FIXME: leaks a temporary file
00384         } catch ( UsageException $e ) {
00385             $exception = true;
00386         }
00387         $this->assertFalse( $exception );
00388         $this->assertTrue( isset( $result['upload'] ) );
00389         $this->assertEquals( 'Success', $result['upload']['result'] );
00390         $this->assertEquals( $fileSize, (int)$result['upload']['imageinfo']['size'] );
00391         $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
00392         $this->assertTrue( isset( $result['upload']['filekey'] ) );
00393         $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
00394         $filekey = $result['upload']['filekey'];
00395 
00396         // it should be visible from Special:UploadStash
00397         // XXX ...but how to test this, with a fake WebRequest with the session?
00398 
00399         // now we should try to release the file from stash
00400         $params = array(
00401             'action' => 'upload',
00402             'filekey' => $filekey,
00403             'filename' => $fileName,
00404             'comment' => 'dummy comment',
00405             'text' => "This is the page text for $fileName, altered",
00406         );
00407 
00408         $this->clearFakeUploads();
00409         $exception = false;
00410         try {
00411             list( $result ) = $this->doApiRequestWithToken( $params, $session,
00412                 self::$users['uploader']->user );
00413         } catch ( UsageException $e ) {
00414             $exception = true;
00415         }
00416         $this->assertTrue( isset( $result['upload'] ) );
00417         $this->assertEquals( 'Success', $result['upload']['result'] );
00418         $this->assertFalse( $exception, "No UsageException exception." );
00419 
00420         // clean up
00421         $this->deleteFileByFilename( $fileName );
00422         unlink( $filePath );
00423     }
00424 
00428     public function testUploadChunks( $session ) {
00429         $this->setMwGlobals( array(
00430             // @todo FIXME: still used somewhere
00431             'wgUser' => self::$users['uploader']->user,
00432         ) );
00433 
00434         $chunkSize = 1048576;
00435         // Download a large image file
00436         // ( using RandomImageGenerator for large files is not stable )
00437         $mimeType = 'image/jpeg';
00438         $url = 'http://upload.wikimedia.org/wikipedia/commons/'
00439             . 'e/ed/Oberaargletscher_from_Oberaar%2C_2010_07.JPG';
00440         $filePath = wfTempDir() . '/Oberaargletscher_from_Oberaar.jpg';
00441         try {
00442             // Only download if the file is not avaliable in the temp location:
00443             if ( !is_file( $filePath ) ) {
00444                 copy( $url, $filePath );
00445             }
00446         } catch ( Exception $e ) {
00447             $this->markTestIncomplete( $e->getMessage() );
00448         }
00449 
00450         $fileSize = filesize( $filePath );
00451         $fileName = basename( $filePath );
00452 
00453         $this->deleteFileByFileName( $fileName );
00454         $this->deleteFileByContent( $filePath );
00455 
00456         // Base upload params:
00457         $params = array(
00458             'action' => 'upload',
00459             'stash' => 1,
00460             'filename' => $fileName,
00461             'filesize' => $fileSize,
00462             'offset' => 0,
00463         );
00464 
00465         // Upload chunks
00466         $chunkSessionKey = false;
00467         $resultOffset = 0;
00468         // Open the file:
00469         wfSuppressWarnings();
00470         $handle = fopen( $filePath, "r" );
00471         wfRestoreWarnings();
00472 
00473         if ( $handle === false ) {
00474             $this->markTestIncomplete( "could not open file: $filePath" );
00475         }
00476 
00477         while ( !feof( $handle ) ) {
00478             // Get the current chunk
00479             wfSuppressWarnings();
00480             $chunkData = fread( $handle, $chunkSize );
00481             wfRestoreWarnings();
00482 
00483             // Upload the current chunk into the $_FILE object:
00484             $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
00485 
00486             // Check for chunkSessionKey
00487             if ( !$chunkSessionKey ) {
00488                 // Upload fist chunk ( and get the session key )
00489                 try {
00490                     list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
00491                         self::$users['uploader']->user );
00492                 } catch ( UsageException $e ) {
00493                     $this->markTestIncomplete( $e->getMessage() );
00494                 }
00495                 // Make sure we got a valid chunk continue:
00496                 $this->assertTrue( isset( $result['upload'] ) );
00497                 $this->assertTrue( isset( $result['upload']['filekey'] ) );
00498                 // If we don't get a session key mark test incomplete.
00499                 if ( !isset( $result['upload']['filekey'] ) ) {
00500                     $this->markTestIncomplete( "no filekey provided" );
00501                 }
00502                 $chunkSessionKey = $result['upload']['filekey'];
00503                 $this->assertEquals( 'Continue', $result['upload']['result'] );
00504                 // First chunk should have chunkSize == offset
00505                 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
00506                 $resultOffset = $result['upload']['offset'];
00507                 continue;
00508             }
00509             // Filekey set to chunk session
00510             $params['filekey'] = $chunkSessionKey;
00511             // Update the offset ( always add chunkSize for subquent chunks
00512             // should be in-sync with $result['upload']['offset'] )
00513             $params['offset'] += $chunkSize;
00514             // Make sure param offset is insync with resultOffset:
00515             $this->assertEquals( $resultOffset, $params['offset'] );
00516             // Upload current chunk
00517             try {
00518                 list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
00519                     self::$users['uploader']->user );
00520             } catch ( UsageException $e ) {
00521                 $this->markTestIncomplete( $e->getMessage() );
00522             }
00523             // Make sure we got a valid chunk continue:
00524             $this->assertTrue( isset( $result['upload'] ) );
00525             $this->assertTrue( isset( $result['upload']['filekey'] ) );
00526 
00527             // Check if we were on the last chunk:
00528             if ( $params['offset'] + $chunkSize >= $fileSize ) {
00529                 $this->assertEquals( 'Success', $result['upload']['result'] );
00530                 break;
00531             } else {
00532                 $this->assertEquals( 'Continue', $result['upload']['result'] );
00533                 // update $resultOffset
00534                 $resultOffset = $result['upload']['offset'];
00535             }
00536         }
00537         fclose( $handle );
00538 
00539         // Check that we got a valid file result:
00540         wfDebug( __METHOD__
00541             . " hohoh filesize {$fileSize} info {$result['upload']['imageinfo']['size']}\n\n" );
00542         $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
00543         $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
00544         $this->assertTrue( isset( $result['upload']['filekey'] ) );
00545         $filekey = $result['upload']['filekey'];
00546 
00547         // Now we should try to release the file from stash
00548         $params = array(
00549             'action' => 'upload',
00550             'filekey' => $filekey,
00551             'filename' => $fileName,
00552             'comment' => 'dummy comment',
00553             'text' => "This is the page text for $fileName, altered",
00554         );
00555         $this->clearFakeUploads();
00556         $exception = false;
00557         try {
00558             list( $result ) = $this->doApiRequestWithToken( $params, $session,
00559                 self::$users['uploader']->user );
00560         } catch ( UsageException $e ) {
00561             $exception = true;
00562         }
00563         $this->assertTrue( isset( $result['upload'] ) );
00564         $this->assertEquals( 'Success', $result['upload']['result'] );
00565         $this->assertFalse( $exception );
00566 
00567         // clean up
00568         $this->deleteFileByFilename( $fileName );
00569         // don't remove downloaded temporary file for fast subquent tests.
00570         //unlink( $filePath );
00571     }
00572 }