Import: Handle uploads with sha1 starting with 0 properly
[mediawiki.git] / tests / phpunit / includes / api / ApiMainTest.php
blobaef48158a0991e7326e8a1c7efe37b9aafbbae6b
1 <?php
3 /**
4 * @group API
5 * @group medium
7 * @covers ApiMain
8 */
9 class ApiMainTest extends ApiTestCase {
11 /**
12 * Test that the API will accept a FauxRequest and execute.
14 public function testApi() {
15 $api = new ApiMain(
16 new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
18 $api->execute();
19 $data = $api->getResult()->getResultData();
20 $this->assertInternalType( 'array', $data );
21 $this->assertArrayHasKey( 'query', $data );
24 public static function provideAssert() {
25 return array(
26 array( false, array(), 'user', 'assertuserfailed' ),
27 array( true, array(), 'user', false ),
28 array( true, array(), 'bot', 'assertbotfailed' ),
29 array( true, array( 'bot' ), 'user', false ),
30 array( true, array( 'bot' ), 'bot', false ),
34 /**
35 * Tests the assert={user|bot} functionality
37 * @covers ApiMain::checkAsserts
38 * @dataProvider provideAssert
39 * @param bool $registered
40 * @param array $rights
41 * @param string $assert
42 * @param string|bool $error False if no error expected
44 public function testAssert( $registered, $rights, $assert, $error ) {
45 $user = new User();
46 if ( $registered ) {
47 $user->setId( 1 );
49 $user->mRights = $rights;
50 try {
51 $this->doApiRequest( array(
52 'action' => 'query',
53 'assert' => $assert,
54 ), null, null, $user );
55 $this->assertFalse( $error ); // That no error was expected
56 } catch ( UsageException $e ) {
57 $this->assertEquals( $e->getCodeString(), $error );
61 /**
62 * Test if all classes in the main module manager exists
64 public function testClassNamesInModuleManager() {
65 global $wgAutoloadLocalClasses, $wgAutoloadClasses;
67 // wgAutoloadLocalClasses has precedence, just like in includes/AutoLoader.php
68 $classes = $wgAutoloadLocalClasses + $wgAutoloadClasses;
70 $api = new ApiMain(
71 new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
73 $modules = $api->getModuleManager()->getNamesWithClasses();
74 foreach ( $modules as $name => $class ) {
75 $this->assertArrayHasKey(
76 $class,
77 $classes,
78 'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)'
83 /**
84 * Test HTTP precondition headers
86 * @covers ApiMain::checkConditionalRequestHeaders
87 * @dataProvider provideCheckConditionalRequestHeaders
88 * @param array $headers HTTP headers
89 * @param array $conditions Return data for ApiBase::getConditionalRequestData
90 * @param int $status Expected response status
91 * @param bool $post Request is a POST
93 public function testCheckConditionalRequestHeaders(
94 $headers, $conditions, $status, $post = false
95 ) {
96 $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
97 $request->setHeaders( $headers );
98 $request->response()->statusHeader( 200 ); // Why doesn't it default?
100 $api = new ApiMain( $request );
101 $priv = TestingAccessWrapper::newFromObject( $api );
102 $priv->mInternalMode = false;
104 $module = $this->getMockBuilder( 'ApiBase' )
105 ->setConstructorArgs( array( $api, 'mock' ) )
106 ->setMethods( array( 'getConditionalRequestData' ) )
107 ->getMockForAbstractClass();
108 $module->expects( $this->any() )
109 ->method( 'getConditionalRequestData' )
110 ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
111 return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
112 } ) );
114 $ret = $priv->checkConditionalRequestHeaders( $module );
116 $this->assertSame( $status, $request->response()->getStatusCode() );
117 $this->assertSame( $status === 200, $ret );
120 public static function provideCheckConditionalRequestHeaders() {
121 $now = time();
123 return array(
124 // Non-existing from module is ignored
125 array( array( 'If-None-Match' => '"foo", "bar"' ), array(), 200 ),
126 array( array( 'If-Modified-Since' => 'Tue, 18 Aug 2015 00:00:00 GMT' ), array(), 200 ),
128 // No headers
129 array(
130 array(),
131 array(
132 'etag' => '""',
133 'last-modified' => '20150815000000',
138 // Basic If-None-Match
139 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 304 ),
140 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"baz"' ), 200 ),
141 array( array( 'If-None-Match' => '"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
142 array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => '"foo"' ), 304 ),
143 array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
145 // Pointless, but supported
146 array( array( 'If-None-Match' => '*' ), array(), 304 ),
148 // Basic If-Modified-Since
149 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
150 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
151 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
152 array( 'last-modified' => wfTimestamp( TS_MW, $now ) ), 304 ),
153 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
154 array( 'last-modified' => wfTimestamp( TS_MW, $now + 1 ) ), 200 ),
156 // If-Modified-Since ignored when If-None-Match is given too
157 array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
158 array( 'etag' => '"x"', 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
159 array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
160 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
162 // Ignored for POST
163 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 200, true ),
164 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
165 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200, true ),
167 // Other date formats allowed by the RFC
168 array( array( 'If-Modified-Since' => gmdate( 'l, d-M-y H:i:s', $now ) . ' GMT' ),
169 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
170 array( array( 'If-Modified-Since' => gmdate( 'D M j H:i:s Y', $now ) ),
171 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
173 // Old browser extension to HTTP/1.0
174 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) . '; length=123' ),
175 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
177 // Invalid date formats should be ignored
178 array( array( 'If-Modified-Since' => gmdate( 'Y-m-d H:i:s', $now ) . ' GMT' ),
179 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
184 * Test conditional headers output
185 * @dataProvider provideConditionalRequestHeadersOutput
186 * @param array $conditions Return data for ApiBase::getConditionalRequestData
187 * @param array $headers Expected output headers
188 * @param bool $isError $isError flag
189 * @param bool $post Request is a POST
191 public function testConditionalRequestHeadersOutput(
192 $conditions, $headers, $isError = false, $post = false
194 $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
195 $response = $request->response();
197 $api = new ApiMain( $request );
198 $priv = TestingAccessWrapper::newFromObject( $api );
199 $priv->mInternalMode = false;
201 $module = $this->getMockBuilder( 'ApiBase' )
202 ->setConstructorArgs( array( $api, 'mock' ) )
203 ->setMethods( array( 'getConditionalRequestData' ) )
204 ->getMockForAbstractClass();
205 $module->expects( $this->any() )
206 ->method( 'getConditionalRequestData' )
207 ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
208 return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
209 } ) );
210 $priv->mModule = $module;
212 $priv->sendCacheHeaders( $isError );
214 foreach ( array( 'Last-Modified', 'ETag' ) as $header ) {
215 $this->assertEquals(
216 isset( $headers[$header] ) ? $headers[$header] : null,
217 $response->getHeader( $header ),
218 $header
223 public static function provideConditionalRequestHeadersOutput() {
224 return array(
225 array(
226 array(),
227 array()
229 array(
230 array( 'etag' => '"foo"' ),
231 array( 'ETag' => '"foo"' )
233 array(
234 array( 'last-modified' => '20150818000102' ),
235 array( 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
237 array(
238 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
239 array( 'ETag' => '"foo"', 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
241 array(
242 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
243 array(),
244 true,
246 array(
247 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
248 array(),
249 false,
250 true,