Merge "ApiSandbox: Indicate when login is suppressed"
[lhc/web/wiklou.git] / tests / phpunit / includes / linkeddata / PageDataRequestHandlerTest.php
1 <?php
2
3 /**
4 * @covers PageDataRequestHandler
5 *
6 * @group PageData
7 *
8 * @license GPL-2.0+
9 */
10 class PageDataRequestHandlerTest extends \MediaWikiTestCase {
11
12 /**
13 * @var Title
14 */
15 private $interfaceTitle;
16
17 /**
18 * @var int
19 */
20 private $obLevel;
21
22 protected function setUp() {
23 parent::setUp();
24
25 $this->interfaceTitle = Title::newFromText( "Special:PageDataRequestHandlerTest" );
26
27 $this->obLevel = ob_get_level();
28 }
29
30 protected function tearDown() {
31 $obLevel = ob_get_level();
32
33 while ( ob_get_level() > $this->obLevel ) {
34 ob_end_clean();
35 }
36
37 if ( $obLevel !== $this->obLevel ) {
38 $this->fail( "Test changed output buffer level: was {$this->obLevel}" .
39 "before test, but $obLevel after test."
40 );
41 }
42
43 parent::tearDown();
44 }
45
46 /**
47 * @return PageDataRequestHandler
48 */
49 protected function newHandler() {
50 return new PageDataRequestHandler( 'json' );
51 }
52
53 /**
54 * @param array $params
55 * @param string[] $headers
56 *
57 * @return OutputPage
58 */
59 protected function makeOutputPage( array $params, array $headers ) {
60 // construct request
61 $request = new FauxRequest( $params );
62 $request->response()->header( 'Status: 200 OK', true, 200 ); // init/reset
63
64 foreach ( $headers as $name => $value ) {
65 $request->setHeader( strtoupper( $name ), $value );
66 }
67
68 // construct Context and OutputPage
69 $context = new DerivativeContext( RequestContext::getMain() );
70 $context->setRequest( $request );
71
72 $output = new OutputPage( $context );
73 $output->setTitle( $this->interfaceTitle );
74 $context->setOutput( $output );
75
76 return $output;
77 }
78
79 public function handleRequestProvider() {
80
81 $cases = [];
82
83 $cases[] = [ '', [], [], '!!', 400 ];
84
85 $cases[] = [ '', [ 'target' => 'Helsinki' ], [], '!!', 303, [ 'Location' => '!.+!' ] ];
86
87 $subpageCases = [];
88 foreach ( $cases as $c ) {
89 $case = $c;
90 $case[0] = 'main/';
91
92 if ( isset( $case[1]['target'] ) ) {
93 $case[0] .= $case[1]['target'];
94 unset( $case[1]['target'] );
95 }
96
97 $subpageCases[] = $case;
98 }
99
100 $cases = array_merge( $cases, $subpageCases );
101
102 $cases[] = [
103 '',
104 [ 'target' => 'Helsinki' ],
105 [ 'Accept' => 'text/HTML' ],
106 '!!',
107 303,
108 [ 'Location' => '!Helsinki$!' ]
109 ];
110
111 $cases[] = [
112 '',
113 [
114 'target' => 'Helsinki',
115 'revision' => '4242',
116 ],
117 [ 'Accept' => 'text/HTML' ],
118 '!!',
119 303,
120 [ 'Location' => '!Helsinki(\?|&)oldid=4242!' ]
121 ];
122
123 $cases[] = [
124 '/Helsinki',
125 [],
126 [],
127 '!!',
128 303,
129 [ 'Location' => '!Helsinki&action=raw!' ]
130 ];
131
132 // #31: /Q5 with "Accept: text/foobar" triggers a 406
133 $cases[] = [
134 'main/Helsinki',
135 [],
136 [ 'Accept' => 'text/foobar' ],
137 '!!',
138 406,
139 [],
140 ];
141
142 $cases[] = [
143 'main/Helsinki',
144 [],
145 [ 'Accept' => 'text/HTML' ],
146 '!!',
147 303,
148 [ 'Location' => '!Helsinki$!' ]
149 ];
150
151 $cases[] = [
152 '/Helsinki',
153 [],
154 [ 'Accept' => 'text/HTML' ],
155 '!!',
156 303,
157 [ 'Location' => '!Helsinki$!' ]
158 ];
159
160 $cases[] = [
161 'main/AC/DC',
162 [],
163 [ 'Accept' => 'text/HTML' ],
164 '!!',
165 303,
166 [ 'Location' => '!AC/DC$!' ]
167 ];
168
169 return $cases;
170 }
171
172 /**
173 * @dataProvider handleRequestProvider
174 *
175 * @param string $subpage The subpage to request (or '')
176 * @param array $params Request parameters
177 * @param array $headers Request headers
178 * @param string $expectedOutput Regex to match the output against.
179 * @param int $expectedStatusCode Expected HTTP status code.
180 * @param string[] $expectedHeaders Expected HTTP response headers.
181 */
182 public function testHandleRequest(
183 $subpage,
184 array $params,
185 array $headers,
186 $expectedOutput,
187 $expectedStatusCode = 200,
188 array $expectedHeaders = []
189 ) {
190 $output = $this->makeOutputPage( $params, $headers );
191 $request = $output->getRequest();
192
193 /* @var FauxResponse $response */
194 $response = $request->response();
195
196 // construct handler
197 $handler = $this->newHandler();
198
199 try {
200 ob_start();
201 $handler->handleRequest( $subpage, $request, $output );
202
203 if ( $output->getRedirect() !== '' ) {
204 // hack to apply redirect to web response
205 $output->output();
206 }
207
208 $text = ob_get_contents();
209 ob_end_clean();
210
211 $this->assertEquals( $expectedStatusCode, $response->getStatusCode(), 'status code' );
212 $this->assertRegExp( $expectedOutput, $text, 'output' );
213
214 foreach ( $expectedHeaders as $name => $exp ) {
215 $value = $response->getHeader( $name );
216 $this->assertNotNull( $value, "header: $name" );
217 $this->assertInternalType( 'string', $value, "header: $name" );
218 $this->assertRegExp( $exp, $value, "header: $name" );
219 }
220 } catch ( HttpError $e ) {
221 ob_end_clean();
222 $this->assertEquals( $expectedStatusCode, $e->getStatusCode(), 'status code' );
223 $this->assertRegExp( $expectedOutput, $e->getHTML(), 'error output' );
224 }
225
226 // We always set "Access-Control-Allow-Origin: *"
227 $this->assertSame( '*', $response->getHeader( 'Access-Control-Allow-Origin' ) );
228 }
229
230 public function provideHttpContentNegotiation() {
231 $helsinki = Title::newFromText( 'Helsinki' );
232 return [
233 'Accept Header of HTML' => [
234 $helsinki,
235 [ 'ACCEPT' => 'text/html' ], // headers
236 'Helsinki'
237 ],
238 'Accept Header without weights' => [
239 $helsinki,
240 [ 'ACCEPT' => '*/*, text/html, text/x-wiki' ],
241 'Helsinki&action=raw'
242 ],
243 'Accept Header with weights' => [
244 $helsinki,
245 [ 'ACCEPT' => 'text/*; q=0.5, text/json; q=0.7, application/rdf+xml; q=0.8' ],
246 'Helsinki&action=raw'
247 ],
248 'Accept Header accepting evertyhing and HTML' => [
249 $helsinki,
250 [ 'ACCEPT' => 'text/html, */*' ],
251 'Helsinki&action=raw'
252 ],
253 'No Accept Header' => [
254 $helsinki,
255 [],
256 'Helsinki&action=raw'
257 ],
258 ];
259 }
260
261 /**
262 * @dataProvider provideHttpContentNegotiation
263 *
264 * @param Title $title
265 * @param array $headers Request headers
266 * @param string $expectedRedirectSuffix Expected suffix of the HTTP Location header.
267 *
268 * @throws HttpError
269 */
270 public function testHttpContentNegotiation(
271 Title $title,
272 array $headers,
273 $expectedRedirectSuffix
274 ) {
275 /* @var FauxResponse $response */
276 $output = $this->makeOutputPage( [], $headers );
277 $request = $output->getRequest();
278
279 $handler = $this->newHandler();
280 $handler->httpContentNegotiation( $request, $output, $title );
281
282 $this->assertStringEndsWith(
283 $expectedRedirectSuffix,
284 $output->getRedirect(),
285 'redirect target'
286 );
287 }
288 }