10 class ApiUploadTest
extends ApiUploadTestCase
{
11 private function filePath( $fileName ) {
12 return __DIR__
. '/../../data/media/' . $fileName;
15 public function setUp() {
17 $this->tablesUsed
[] = 'watchlist'; // This test might interfere with watchlists test.
18 $this->tablesUsed
= array_merge( $this->tablesUsed
, LocalFile
::getQueryInfo()['tables'] );
19 $this->setService( 'RepoGroup', new RepoGroup(
21 'class' => LocalRepo
::class,
23 'backend' => new FSFileBackend( [
24 'name' => 'temp-backend',
25 'wikiId' => wfWikiID(),
26 'basePath' => $this->getNewTempDirectory()
32 $this->resetServices();
35 public function testUploadRequiresToken() {
36 $this->setExpectedException(
37 ApiUsageException
::class,
38 'The "token" parameter must be set'
40 $this->doApiRequest( [
45 public function testUploadMissingParams() {
46 $this->setExpectedException(
47 ApiUsageException
::class,
48 'One of the parameters "filekey", "file" and "url" is required'
50 $this->doApiRequestWithToken( [
52 ], null, self
::$users['uploader']->getUser() );
55 public function testUpload() {
56 $fileName = 'TestUpload.jpg';
57 $mimeType = 'image/jpeg';
58 $filePath = $this->filePath( 'yuv420.jpg' );
60 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
61 list( $result ) = $this->doApiRequestWithToken( [
63 'filename' => $fileName,
64 'file' => 'dummy content',
65 'comment' => 'dummy comment',
66 'text' => "This is the page text for $fileName",
67 ], null, self
::$users['uploader']->getUser() );
69 $this->assertArrayHasKey( 'upload', $result );
70 $this->assertEquals( 'Success', $result['upload']['result'] );
71 $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
72 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
75 public function testUploadZeroLength() {
76 $filePath = $this->getNewTempFile();
77 $mimeType = 'image/jpeg';
78 $fileName = "ApiTestUploadZeroLength.jpg";
80 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
82 $this->setExpectedException(
83 ApiUsageException
::class,
84 'The file you submitted was empty'
86 $this->doApiRequestWithToken( [
88 'filename' => $fileName,
89 'file' => 'dummy content',
90 'comment' => 'dummy comment',
91 'text' => "This is the page text for $fileName",
92 ], null, self
::$users['uploader']->getUser() );
95 public function testUploadSameFileName() {
96 $fileName = 'TestUploadSameFileName.jpg';
97 $mimeType = 'image/jpeg';
99 $this->filePath( 'yuv420.jpg' ),
100 $this->filePath( 'yuv444.jpg' )
103 // we reuse these params
105 'action' => 'upload',
106 'filename' => $fileName,
107 'file' => 'dummy content',
108 'comment' => 'dummy comment',
109 'text' => "This is the page text for $fileName",
112 // first upload .... should succeed
114 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] );
115 list( $result ) = $this->doApiRequestWithToken( $params, null,
116 self
::$users['uploader']->getUser() );
117 $this->assertArrayHasKey( 'upload', $result );
118 $this->assertEquals( 'Success', $result['upload']['result'] );
120 // second upload with the same name (but different content)
122 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] );
123 list( $result ) = $this->doApiRequestWithToken( $params, null,
124 self
::$users['uploader']->getUser() );
125 $this->assertArrayHasKey( 'upload', $result );
126 $this->assertEquals( 'Warning', $result['upload']['result'] );
127 $this->assertArrayHasKey( 'warnings', $result['upload'] );
128 $this->assertArrayHasKey( 'exists', $result['upload']['warnings'] );
131 public function testUploadSameContent() {
132 $fileNames = [ 'TestUploadSameContent_1.jpg', 'TestUploadSameContent_2.jpg' ];
133 $mimeType = 'image/jpeg';
134 $filePath = $this->filePath( 'yuv420.jpg' );
136 // first upload .... should succeed
137 $this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePath );
138 list( $result ) = $this->doApiRequestWithToken( [
139 'action' => 'upload',
140 'filename' => $fileNames[0],
141 'file' => 'dummy content',
142 'comment' => 'dummy comment',
143 'text' => "This is the page text for {$fileNames[0]}",
144 ], null, self
::$users['uploader']->getUser() );
145 $this->assertArrayHasKey( 'upload', $result );
146 $this->assertEquals( 'Success', $result['upload']['result'] );
148 // second upload with the same content (but different name)
149 $this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePath );
150 list( $result ) = $this->doApiRequestWithToken( [
151 'action' => 'upload',
152 'filename' => $fileNames[1],
153 'file' => 'dummy content',
154 'comment' => 'dummy comment',
155 'text' => "This is the page text for {$fileNames[1]}",
156 ], null, self
::$users['uploader']->getUser() );
158 $this->assertArrayHasKey( 'upload', $result );
159 $this->assertEquals( 'Warning', $result['upload']['result'] );
160 $this->assertArrayHasKey( 'warnings', $result['upload'] );
161 $this->assertArrayHasKey( 'duplicate', $result['upload']['warnings'] );
162 $this->assertArrayEquals( [ $fileNames[0] ], $result['upload']['warnings']['duplicate'] );
163 $this->assertArrayNotHasKey( 'exists', $result['upload']['warnings'] );
166 public function testUploadStash() {
167 $fileName = 'TestUploadStash.jpg';
168 $mimeType = 'image/jpeg';
169 $filePath = $this->filePath( 'yuv420.jpg' );
171 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
172 list( $result ) = $this->doApiRequestWithToken( [
173 'action' => 'upload',
175 'filename' => $fileName,
176 'file' => 'dummy content',
177 'comment' => 'dummy comment',
178 'text' => "This is the page text for $fileName",
179 ], null, self
::$users['uploader']->getUser() );
181 $this->assertArrayHasKey( 'upload', $result );
182 $this->assertEquals( 'Success', $result['upload']['result'] );
183 $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
184 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
185 $this->assertArrayHasKey( 'filekey', $result['upload'] );
186 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
187 $filekey = $result['upload']['filekey'];
189 // it should be visible from Special:UploadStash
190 // XXX ...but how to test this, with a fake WebRequest with the session?
192 // now we should try to release the file from stash
193 $this->clearFakeUploads();
194 list( $result ) = $this->doApiRequestWithToken( [
195 'action' => 'upload',
196 'filekey' => $filekey,
197 'filename' => $fileName,
198 'comment' => 'dummy comment',
199 'text' => "This is the page text for $fileName, altered",
200 ], null, self
::$users['uploader']->getUser() );
201 $this->assertArrayHasKey( 'upload', $result );
202 $this->assertEquals( 'Success', $result['upload']['result'] );
205 public function testUploadChunks() {
206 $fileName = 'TestUploadChunks.jpg';
207 $mimeType = 'image/jpeg';
208 $filePath = $this->filePath( 'yuv420.jpg' );
209 $fileSize = filesize( $filePath );
210 $chunkSize = 20 * 1024; // The file is ~60kB, use 20kB chunks
212 $this->setMwGlobals( [
213 'wgMinUploadChunkSize' => $chunkSize
216 // Base upload params:
218 'action' => 'upload',
220 'filename' => $fileName,
221 'filesize' => $fileSize,
226 $handle = fopen( $filePath, "r" );
229 while ( !feof( $handle ) ) {
230 $chunkData = fread( $handle, $chunkSize );
232 // Upload the current chunk into the $_FILE object:
233 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
235 list( $result ) = $this->doApiRequestWithToken( $params, null,
236 self
::$users['uploader']->getUser() );
237 // Make sure we got a valid chunk continue:
238 $this->assertArrayHasKey( 'upload', $result );
239 $this->assertArrayHasKey( 'filekey', $result['upload'] );
240 $this->assertEquals( 'Continue', $result['upload']['result'] );
241 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
243 $filekey = $result['upload']['filekey'];
244 $resultOffset = $result['upload']['offset'];
246 // Filekey set to chunk session
247 $params['filekey'] = $filekey;
248 // Update the offset ( always add chunkSize for subquent chunks
249 // should be in-sync with $result['upload']['offset'] )
250 $params['offset'] +
= $chunkSize;
251 // Make sure param offset is insync with resultOffset:
252 $this->assertEquals( $resultOffset, $params['offset'] );
253 // Upload current chunk
254 list( $result ) = $this->doApiRequestWithToken( $params, null,
255 self
::$users['uploader']->getUser() );
256 // Make sure we got a valid chunk continue:
257 $this->assertArrayHasKey( 'upload', $result );
258 $this->assertArrayHasKey( 'filekey', $result['upload'] );
260 // Check if we were on the last chunk:
261 if ( $params['offset'] +
$chunkSize >= $fileSize ) {
262 $this->assertEquals( 'Success', $result['upload']['result'] );
265 $this->assertEquals( 'Continue', $result['upload']['result'] );
266 $resultOffset = $result['upload']['offset'];
272 // Check that we got a valid file result:
273 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
274 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
275 $this->assertArrayHasKey( 'filekey', $result['upload'] );
276 $filekey = $result['upload']['filekey'];
278 // Now we should try to release the file from stash
279 $this->clearFakeUploads();
280 list( $result ) = $this->doApiRequestWithToken( [
281 'action' => 'upload',
282 'filekey' => $filekey,
283 'filename' => $fileName,
284 'comment' => 'dummy comment',
285 'text' => "This is the page text for $fileName, altered",
286 ], null, self
::$users['uploader']->getUser() );
287 $this->assertArrayHasKey( 'upload', $result );
288 $this->assertEquals( 'Success', $result['upload']['result'] );