Stop doing $that = $this in Tests
[mediawiki.git] / tests / phpunit / includes / api / ApiMainTest.php
blobf02f7dfdadd29585091c8be633a7e902f2e0a5e7
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 $context = $this->apiContext->newTestContext( $request, null );
101 $api = new ApiMain( $context );
102 $priv = TestingAccessWrapper::newFromObject( $api );
103 $priv->mInternalMode = false;
105 $module = $this->getMockBuilder( 'ApiBase' )
106 ->setConstructorArgs( array( $api, 'mock' ) )
107 ->setMethods( array( 'getConditionalRequestData' ) )
108 ->getMockForAbstractClass();
109 $module->expects( $this->any() )
110 ->method( 'getConditionalRequestData' )
111 ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
112 return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
113 } ) );
115 $ret = $priv->checkConditionalRequestHeaders( $module );
117 $this->assertSame( $status, $request->response()->getStatusCode() );
118 $this->assertSame( $status === 200, $ret );
121 public static function provideCheckConditionalRequestHeaders() {
122 $now = time();
124 return array(
125 // Non-existing from module is ignored
126 array( array( 'If-None-Match' => '"foo", "bar"' ), array(), 200 ),
127 array( array( 'If-Modified-Since' => 'Tue, 18 Aug 2015 00:00:00 GMT' ), array(), 200 ),
129 // No headers
130 array(
131 array(),
132 array(
133 'etag' => '""',
134 'last-modified' => '20150815000000',
139 // Basic If-None-Match
140 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 304 ),
141 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"baz"' ), 200 ),
142 array( array( 'If-None-Match' => '"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
143 array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => '"foo"' ), 304 ),
144 array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
146 // Pointless, but supported
147 array( array( 'If-None-Match' => '*' ), array(), 304 ),
149 // Basic If-Modified-Since
150 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
151 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
152 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
153 array( 'last-modified' => wfTimestamp( TS_MW, $now ) ), 304 ),
154 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
155 array( 'last-modified' => wfTimestamp( TS_MW, $now + 1 ) ), 200 ),
157 // If-Modified-Since ignored when If-None-Match is given too
158 array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
159 array( 'etag' => '"x"', 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
160 array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
161 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
163 // Ignored for POST
164 array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 200, true ),
165 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
166 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200, true ),
168 // Other date formats allowed by the RFC
169 array( array( 'If-Modified-Since' => gmdate( 'l, d-M-y H:i:s', $now ) . ' GMT' ),
170 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
171 array( array( 'If-Modified-Since' => gmdate( 'D M j H:i:s Y', $now ) ),
172 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
174 // Old browser extension to HTTP/1.0
175 array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) . '; length=123' ),
176 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
178 // Invalid date formats should be ignored
179 array( array( 'If-Modified-Since' => gmdate( 'Y-m-d H:i:s', $now ) . ' GMT' ),
180 array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
185 * Test conditional headers output
186 * @dataProvider provideConditionalRequestHeadersOutput
187 * @param array $conditions Return data for ApiBase::getConditionalRequestData
188 * @param array $headers Expected output headers
189 * @param bool $isError $isError flag
190 * @param bool $post Request is a POST
192 public function testConditionalRequestHeadersOutput(
193 $conditions, $headers, $isError = false, $post = false
195 $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
196 $response = $request->response();
198 $api = new ApiMain( $request );
199 $priv = TestingAccessWrapper::newFromObject( $api );
200 $priv->mInternalMode = false;
202 $module = $this->getMockBuilder( 'ApiBase' )
203 ->setConstructorArgs( array( $api, 'mock' ) )
204 ->setMethods( array( 'getConditionalRequestData' ) )
205 ->getMockForAbstractClass();
206 $module->expects( $this->any() )
207 ->method( 'getConditionalRequestData' )
208 ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
209 return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
210 } ) );
211 $priv->mModule = $module;
213 $priv->sendCacheHeaders( $isError );
215 foreach ( array( 'Last-Modified', 'ETag' ) as $header ) {
216 $this->assertEquals(
217 isset( $headers[$header] ) ? $headers[$header] : null,
218 $response->getHeader( $header ),
219 $header
224 public static function provideConditionalRequestHeadersOutput() {
225 return array(
226 array(
227 array(),
228 array()
230 array(
231 array( 'etag' => '"foo"' ),
232 array( 'ETag' => '"foo"' )
234 array(
235 array( 'last-modified' => '20150818000102' ),
236 array( 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
238 array(
239 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
240 array( 'ETag' => '"foo"', 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
242 array(
243 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
244 array(),
245 true,
247 array(
248 array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
249 array(),
250 false,
251 true,