Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / api / ApiUploadTest.php
blob6456e89be35677093e839bdd979b2a1f0498a6c2
1 <?php
3 namespace MediaWiki\Tests\Api;
5 use LocalRepo;
6 use MediaWiki\MainConfigNames;
7 use MediaWiki\Permissions\Authority;
8 use MediaWiki\Title\Title;
9 use MediaWiki\WikiMap\WikiMap;
10 use RepoGroup;
11 use Wikimedia\FileBackend\FSFileBackend;
12 use Wikimedia\Mime\MimeAnalyzer;
14 /**
15 * @group API
16 * @group Database
17 * @group medium
19 * @covers \MediaWiki\Api\ApiUpload
21 class ApiUploadTest extends ApiUploadTestCase {
22 private ?Authority $uploader = null;
24 private function filePath( $fileName ) {
25 return __DIR__ . '/../../data/media/' . $fileName;
28 protected function setUp(): void {
29 parent::setUp();
31 $this->setService( 'RepoGroup', new RepoGroup(
33 'class' => LocalRepo::class,
34 'name' => 'temp',
35 'backend' => new FSFileBackend( [
36 'name' => 'temp-backend',
37 'wikiId' => WikiMap::getCurrentWikiId(),
38 'basePath' => $this->getNewTempDirectory()
39 ] )
41 [],
42 $this->getServiceContainer()->getMainWANObjectCache(),
43 $this->createMock( MimeAnalyzer::class )
44 ) );
46 $this->overrideConfigValue( MainConfigNames::WatchlistExpiry, true );
47 $this->uploader = $this->getTestUser()->getAuthority();
50 public function testUploadRequiresToken() {
51 $this->expectApiErrorCode( 'missingparam' );
52 $this->doApiRequest( [
53 'action' => 'upload'
54 ] );
57 public function testUploadMissingParams() {
58 $this->expectApiErrorCode( 'missingparam' );
59 $this->doApiRequestWithToken( [
60 'action' => 'upload',
61 ], null, $this->uploader );
64 public function testUploadWithWatch() {
65 $mimeType = 'image/jpeg';
66 $filePath = $this->filePath( 'yuv420.jpg' );
67 $title = Title::makeTitle( NS_FILE, 'TestUpload.jpg' );
68 $user = $this->uploader;
70 $this->fakeUploadFile( 'file', $title->getText(), $mimeType, $filePath );
71 [ $result ] = $this->doApiRequestWithToken( [
72 'action' => 'upload',
73 'filename' => $title->getText(),
74 'file' => 'dummy content',
75 'comment' => 'dummy comment',
76 'text' => "This is the page text for {$title->getText()}",
77 'watchlist' => 'watch',
78 'watchlistexpiry' => '99990123000000',
79 ], null, $user );
81 $this->assertArrayHasKey( 'upload', $result );
82 $this->assertEquals( 'Success', $result['upload']['result'] );
83 $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
84 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
85 $this->assertTrue( $this->getServiceContainer()->getWatchlistManager()->isTempWatched( $user, $title ) );
88 public function testUploadZeroLength() {
89 $filePath = $this->getNewTempFile();
90 $mimeType = 'image/jpeg';
91 $fileName = "ApiTestUploadZeroLength.jpg";
93 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
95 $this->expectApiErrorCode( 'empty-file' );
96 $this->doApiRequestWithToken( [
97 'action' => 'upload',
98 'filename' => $fileName,
99 'file' => 'dummy content',
100 'comment' => 'dummy comment',
101 'text' => "This is the page text for $fileName",
102 ], null, $this->uploader );
105 public function testUploadSameFileName() {
106 $fileName = 'TestUploadSameFileName.jpg';
107 $mimeType = 'image/jpeg';
108 $filePaths = [
109 $this->filePath( 'yuv420.jpg' ),
110 $this->filePath( 'yuv444.jpg' )
113 // we reuse these params
114 $params = [
115 'action' => 'upload',
116 'filename' => $fileName,
117 'file' => 'dummy content',
118 'comment' => 'dummy comment',
119 'text' => "This is the page text for $fileName",
122 // first upload .... should succeed
124 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[0] );
125 [ $result ] = $this->doApiRequestWithToken( $params, null,
126 $this->uploader );
127 $this->assertArrayHasKey( 'upload', $result );
128 $this->assertEquals( 'Success', $result['upload']['result'] );
130 // second upload with the same name (but different content)
132 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePaths[1] );
133 [ $result ] = $this->doApiRequestWithToken( $params, null,
134 $this->uploader );
135 $this->assertArrayHasKey( 'upload', $result );
136 $this->assertEquals( 'Warning', $result['upload']['result'] );
137 $this->assertArrayHasKey( 'warnings', $result['upload'] );
138 $this->assertArrayHasKey( 'exists', $result['upload']['warnings'] );
141 public function testUploadSameContent() {
142 $fileNames = [ 'TestUploadSameContent_1.jpg', 'TestUploadSameContent_2.jpg' ];
143 $mimeType = 'image/jpeg';
144 $filePath = $this->filePath( 'yuv420.jpg' );
146 // first upload .... should succeed
147 $this->fakeUploadFile( 'file', $fileNames[0], $mimeType, $filePath );
148 [ $result ] = $this->doApiRequestWithToken( [
149 'action' => 'upload',
150 'filename' => $fileNames[0],
151 'file' => 'dummy content',
152 'comment' => 'dummy comment',
153 'text' => "This is the page text for {$fileNames[0]}",
154 ], null, $this->uploader );
155 $this->assertArrayHasKey( 'upload', $result );
156 $this->assertEquals( 'Success', $result['upload']['result'] );
158 // second upload with the same content (but different name)
159 $this->fakeUploadFile( 'file', $fileNames[1], $mimeType, $filePath );
160 [ $result ] = $this->doApiRequestWithToken( [
161 'action' => 'upload',
162 'filename' => $fileNames[1],
163 'file' => 'dummy content',
164 'comment' => 'dummy comment',
165 'text' => "This is the page text for {$fileNames[1]}",
166 ], null, $this->uploader );
168 $this->assertArrayHasKey( 'upload', $result );
169 $this->assertEquals( 'Warning', $result['upload']['result'] );
170 $this->assertArrayHasKey( 'warnings', $result['upload'] );
171 $this->assertArrayHasKey( 'duplicate', $result['upload']['warnings'] );
172 $this->assertArrayEquals( [ $fileNames[0] ], $result['upload']['warnings']['duplicate'] );
173 $this->assertArrayNotHasKey( 'exists', $result['upload']['warnings'] );
176 public function testUploadStash() {
177 $fileName = 'TestUploadStash.jpg';
178 $mimeType = 'image/jpeg';
179 $filePath = $this->filePath( 'yuv420.jpg' );
181 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
182 [ $result ] = $this->doApiRequestWithToken( [
183 'action' => 'upload',
184 'stash' => 1,
185 'filename' => $fileName,
186 'file' => 'dummy content',
187 'comment' => 'dummy comment',
188 'text' => "This is the page text for $fileName",
189 ], null, $this->uploader );
191 $this->assertArrayHasKey( 'upload', $result );
192 $this->assertEquals( 'Success', $result['upload']['result'] );
193 $this->assertSame( filesize( $filePath ), (int)$result['upload']['imageinfo']['size'] );
194 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
195 $this->assertArrayHasKey( 'filekey', $result['upload'] );
196 $this->assertEquals( $result['upload']['sessionkey'], $result['upload']['filekey'] );
197 $filekey = $result['upload']['filekey'];
199 // it should be visible from Special:UploadStash
200 // XXX ...but how to test this, with a fake WebRequest with the session?
202 // now we should try to release the file from stash
203 $this->clearFakeUploads();
204 [ $result ] = $this->doApiRequestWithToken( [
205 'action' => 'upload',
206 'filekey' => $filekey,
207 'filename' => $fileName,
208 'comment' => 'dummy comment',
209 'text' => "This is the page text for $fileName, altered",
210 ], null, $this->uploader );
211 $this->assertArrayHasKey( 'upload', $result );
212 $this->assertEquals( 'Success', $result['upload']['result'] );
215 public function testUploadChunks() {
216 $fileName = 'TestUploadChunks.jpg';
217 $mimeType = 'image/jpeg';
218 $filePath = $this->filePath( 'yuv420.jpg' );
219 $fileSize = filesize( $filePath );
220 $chunkSize = 20 * 1024; // The file is ~60 KiB, use 20 KiB chunks
222 $this->overrideConfigValue( MainConfigNames::MinUploadChunkSize, $chunkSize );
224 // Base upload params:
225 $params = [
226 'action' => 'upload',
227 'stash' => 1,
228 'filename' => $fileName,
229 'filesize' => $fileSize,
230 'offset' => 0,
233 // Upload chunks
234 $handle = fopen( $filePath, "r" );
235 $resultOffset = 0;
236 $filekey = false;
237 while ( !feof( $handle ) ) {
238 $chunkData = fread( $handle, $chunkSize );
240 // Upload the current chunk into the $_FILE object:
241 $this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
242 if ( !$filekey ) {
243 [ $result ] = $this->doApiRequestWithToken( $params, null,
244 $this->uploader );
245 // Make sure we got a valid chunk continue:
246 $this->assertArrayHasKey( 'upload', $result );
247 $this->assertArrayHasKey( 'filekey', $result['upload'] );
248 $this->assertEquals( 'Continue', $result['upload']['result'] );
249 $this->assertEquals( $chunkSize, $result['upload']['offset'] );
251 $filekey = $result['upload']['filekey'];
252 $resultOffset = $result['upload']['offset'];
253 } else {
254 // Filekey set to chunk session
255 $params['filekey'] = $filekey;
256 // Update the offset ( always add chunkSize for subquent chunks
257 // should be in-sync with $result['upload']['offset'] )
258 $params['offset'] += $chunkSize;
259 // Make sure param offset is insync with resultOffset:
260 $this->assertEquals( $resultOffset, $params['offset'] );
261 // Upload current chunk
262 [ $result ] = $this->doApiRequestWithToken( $params, null,
263 $this->uploader );
264 // Make sure we got a valid chunk continue:
265 $this->assertArrayHasKey( 'upload', $result );
266 $this->assertArrayHasKey( 'filekey', $result['upload'] );
268 // Check if we were on the last chunk:
269 if ( $params['offset'] + $chunkSize >= $fileSize ) {
270 $this->assertEquals( 'Success', $result['upload']['result'] );
271 break;
272 } else {
273 $this->assertEquals( 'Continue', $result['upload']['result'] );
274 $resultOffset = $result['upload']['offset'];
278 fclose( $handle );
280 // Check that we got a valid file result:
281 $this->assertEquals( $fileSize, $result['upload']['imageinfo']['size'] );
282 $this->assertEquals( $mimeType, $result['upload']['imageinfo']['mime'] );
283 $this->assertArrayHasKey( 'filekey', $result['upload'] );
284 $filekey = $result['upload']['filekey'];
286 // Now we should try to release the file from stash
287 $this->clearFakeUploads();
288 [ $result ] = $this->doApiRequestWithToken( [
289 'action' => 'upload',
290 'filekey' => $filekey,
291 'filename' => $fileName,
292 'comment' => 'dummy comment',
293 'text' => "This is the page text for $fileName, altered",
294 ], null, $this->uploader );
295 $this->assertArrayHasKey( 'upload', $result );
296 $this->assertEquals( 'Success', $result['upload']['result'] );