3 use Wikimedia\TestingAccessWrapper;
19 new FauxRequest( [
'action' =>
'query',
'meta' =>
'siteinfo' ] )
22 $data = $api->getResult()->getResultData();
23 $this->assertInternalType(
'array', $data );
24 $this->assertArrayHasKey(
'query', $data );
29 [
false, [],
'user',
'assertuserfailed' ],
30 [
true, [],
'user',
false ],
31 [
true, [],
'bot',
'assertbotfailed' ],
32 [
true, [
'bot' ],
'user',
false ],
33 [
true, [
'bot' ],
'bot',
false ],
47 public function testAssert( $registered, $rights, $assert, $error ) {
52 $user->mRights = $rights;
57 ],
null,
null,
$user );
58 $this->assertFalse( $error );
60 $this->assertTrue( self::apiExceptionHasCode(
$e, $error ) );
73 'assertuser' =>
$user->getName(),
74 ],
null,
null,
$user );
79 'assertuser' =>
$user->getName() .
'X',
80 ],
null,
null,
$user );
81 $this->fail(
'Expected exception not thrown' );
83 $this->assertTrue( self::apiExceptionHasCode(
$e,
'assertnameduserfailed' ) );
92 new FauxRequest( [
'action' =>
'query',
'meta' =>
'siteinfo' ] )
94 $modules = $api->getModuleManager()->getNamesWithClasses();
98 class_exists( $class ),
99 'Class ' . $class .
' for api module ' .
$name .
' does not exist (with exact case)'
115 $headers, $conditions,
$status, $post =
false
119 $request->response()->statusHeader( 200 );
123 $priv = TestingAccessWrapper::newFromObject( $api );
124 $priv->mInternalMode =
false;
126 $module = $this->getMockBuilder(
'ApiBase' )
127 ->setConstructorArgs( [ $api,
'mock' ] )
128 ->setMethods( [
'getConditionalRequestData' ] )
129 ->getMockForAbstractClass();
130 $module->expects( $this->
any() )
131 ->method(
'getConditionalRequestData' )
132 ->will( $this->returnCallback(
function ( $condition )
use ( $conditions ) {
133 return isset( $conditions[$condition] ) ? $conditions[$condition] :
null;
136 $ret = $priv->checkConditionalRequestHeaders( $module );
147 [ [
'If-None-Match' =>
'"foo", "bar"' ], [], 200 ],
148 [ [
'If-Modified-Since' =>
'Tue, 18 Aug 2015 00:00:00 GMT' ], [], 200 ],
155 'last-modified' =>
'20150815000000',
161 [ [
'If-None-Match' =>
'"foo", "bar"' ], [
'etag' =>
'"bar"' ], 304 ],
162 [ [
'If-None-Match' =>
'"foo", "bar"' ], [
'etag' =>
'"baz"' ], 200 ],
163 [ [
'If-None-Match' =>
'"foo"' ], [
'etag' =>
'W/"foo"' ], 304 ],
164 [ [
'If-None-Match' =>
'W/"foo"' ], [
'etag' =>
'"foo"' ], 304 ],
165 [ [
'If-None-Match' =>
'W/"foo"' ], [
'etag' =>
'W/"foo"' ], 304 ],
168 [ [
'If-None-Match' =>
'*' ], [], 304 ],
171 [ [
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
172 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 304 ],
173 [ [
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
174 [
'last-modified' =>
wfTimestamp( TS_MW, $now ) ], 304 ],
175 [ [
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
176 [
'last-modified' =>
wfTimestamp( TS_MW, $now + 1 ) ], 200 ],
179 [ [
'If-None-Match' =>
'""',
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
180 [
'etag' =>
'"x"',
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 200 ],
181 [ [
'If-None-Match' =>
'""',
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
182 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 304 ],
185 [ [
'If-None-Match' =>
'"foo", "bar"' ], [
'etag' =>
'"bar"' ], 200,
true ],
186 [ [
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) ],
190 [ [
'If-Modified-Since' => gmdate(
'l, d-M-y H:i:s', $now ) .
' GMT' ],
191 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 304 ],
192 [ [
'If-Modified-Since' => gmdate(
'D M j H:i:s Y', $now ) ],
193 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 304 ],
196 [ [
'If-Modified-Since' =>
wfTimestamp( TS_RFC2822, $now ) .
'; length=123' ],
197 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 304 ],
200 [ [
'If-Modified-Since' => gmdate(
'Y-m-d H:i:s', $now ) .
' GMT' ],
201 [
'last-modified' =>
wfTimestamp( TS_MW, $now - 1 ) ], 200 ],
214 $conditions, $headers, $isError =
false, $post =
false
220 $priv = TestingAccessWrapper::newFromObject( $api );
221 $priv->mInternalMode =
false;
223 $module = $this->getMockBuilder(
'ApiBase' )
224 ->setConstructorArgs( [ $api,
'mock' ] )
225 ->setMethods( [
'getConditionalRequestData' ] )
226 ->getMockForAbstractClass();
227 $module->expects( $this->
any() )
228 ->method(
'getConditionalRequestData' )
229 ->will( $this->returnCallback(
function ( $condition )
use ( $conditions ) {
230 return isset( $conditions[$condition] ) ? $conditions[$condition] :
null;
232 $priv->mModule = $module;
234 $priv->sendCacheHeaders( $isError );
236 foreach ( [
'Last-Modified',
'ETag' ]
as $header ) {
252 [
'etag' =>
'"foo"' ],
253 [
'ETag' =>
'"foo"' ]
256 [
'last-modified' =>
'20150818000102' ],
257 [
'Last-Modified' =>
'Tue, 18 Aug 2015 00:01:02 GMT' ]
260 [
'etag' =>
'"foo"',
'last-modified' =>
'20150818000102' ],
261 [
'ETag' =>
'"foo"',
'Last-Modified' =>
'Tue, 18 Aug 2015 00:01:02 GMT' ]
264 [
'etag' =>
'"foo"',
'last-modified' =>
'20150818000102' ],
269 [
'etag' =>
'"foo"',
'last-modified' =>
'20150818000102' ],
282 $main =
new ApiMain(
new FauxRequest( [
'action' =>
'query',
'meta' =>
'siteinfo' ] ) );
283 $this->assertFalse( $main->lacksSameOriginSecurity(),
'Basic test, should have security' );
287 new FauxRequest( [
'action' =>
'query',
'format' =>
'xml',
'callback' =>
'foo' ] )
289 $this->assertTrue( $main->lacksSameOriginSecurity(),
'JSONp, should lack security' );
293 $request->setHeader(
'TrEaT-As-UnTrUsTeD',
'' );
295 $this->assertTrue( $main->lacksSameOriginSecurity(),
'Header supplied, should lack security' );
299 'RequestHasSameOriginSecurity' => [
function () {
303 $main =
new ApiMain(
new FauxRequest( [
'action' =>
'query',
'meta' =>
'siteinfo' ] ) );
304 $this->assertTrue( $main->lacksSameOriginSecurity(),
'Hook, should lack security' );
325 $formatter = $main->getErrorFormatter();
326 $wrappedFormatter = TestingAccessWrapper::newFromObject( $formatter );
328 $this->assertSame( $expect[
'uselang'], $main->getLanguage()->getCode() );
329 $this->assertInstanceOf( $expect[
'class'], $formatter );
330 $this->assertSame( $expect[
'lang'], $formatter->getLanguage()->getCode() );
331 $this->assertSame( $expect[
'format'], $wrappedFormatter->format );
332 $this->assertSame( $expect[
'usedb'], $wrappedFormatter->useDB );
337 'Default (BC)' => [ [], [
344 'BC ignores fields' => [ [
'errorlang' =>
'de',
'errorsuselocal' => 1 ], [
351 'Explicit BC' => [ [
'errorformat' =>
'bc' ], [
358 'Basic' => [ [
'errorformat' =>
'wikitext' ], [
362 'format' =>
'wikitext',
365 'Follows uselang' => [ [
'uselang' =>
'fr',
'errorformat' =>
'plaintext' ], [
369 'format' =>
'plaintext',
372 'Explicitly follows uselang' => [
373 [
'uselang' =>
'fr',
'errorlang' =>
'uselang',
'errorformat' =>
'plaintext' ],
378 'format' =>
'plaintext',
382 'uselang=content' => [
383 [
'uselang' =>
'content',
'errorformat' =>
'plaintext' ],
388 'format' =>
'plaintext',
392 'errorlang=content' => [
393 [
'errorlang' =>
'content',
'errorformat' =>
'plaintext' ],
398 'format' =>
'plaintext',
402 'Explicit parameters' => [
403 [
'errorlang' =>
'de',
'errorformat' =>
'html',
'errorsuselocal' => 1 ],
412 'Explicit parameters override uselang' => [
413 [
'errorlang' =>
'de',
'uselang' =>
'fr',
'errorformat' =>
'raw' ],
422 'Bogus language doesn\'t explode' => [
423 [
'errorlang' =>
'<bogus1>',
'uselang' =>
'<bogus2>',
'errorformat' =>
'none' ],
432 'Bogus format doesn\'t explode' => [ [
'errorformat' =>
'bogus' ], [
456 'ShowHostnames' =>
true,
'ShowSQLErrors' =>
false,
457 'ShowExceptionDetails' =>
true,
'ShowDBErrorBacktrace' =>
true,
463 $main->addWarning(
new RawMessage(
'existing warning' ),
'existing-warning' );
464 $main->addError(
new RawMessage(
'existing error' ),
'existing-error' );
466 $ret = TestingAccessWrapper::newFromObject( $main )->substituteResultWithError( $error );
467 $this->assertSame( $expectReturn,
$ret );
473 $main->getResult()->getResultData( [], [
'Strip' =>
'all' ] )
482 $ex =
new InvalidArgumentException(
'Random exception' );
483 $trace =
wfMessage(
'api-exception-trace',
488 )->inLanguage(
'en' )->useDatabase(
false )->text();
490 $dbex =
new DBQueryError(
491 $this->createMock(
'IDatabase' ),
492 'error', 1234,
'SELECT 1', __METHOD__ );
493 $dbtrace =
wfMessage(
'api-exception-trace',
498 )->inLanguage(
'en' )->useDatabase(
false )->text();
502 TestingAccessWrapper::newFromObject( $apiEx1 )->modulePath =
'foo+bar';
503 $apiEx1->getStatusValue()->warning(
new ApiRawMessage(
'A warning',
'sv-warn1' ) );
504 $apiEx1->getStatusValue()->warning(
new ApiRawMessage(
'Another warning',
'sv-warn2' ) );
505 $apiEx1->getStatusValue()->fatal(
new ApiRawMessage(
'Another error',
'sv-error2' ) );
510 [
'existing-error',
'internal_api_error_InvalidArgumentException' ],
513 [
'code' =>
'existing-warning',
'text' =>
'existing warning',
'module' =>
'main' ],
516 [
'code' =>
'existing-error',
'text' =>
'existing error',
'module' =>
'main' ],
518 'code' =>
'internal_api_error_InvalidArgumentException',
519 'text' =>
"[$reqId] Exception caught: Random exception",
528 [
'existing-error',
'internal_api_error_DBQueryError' ],
531 [
'code' =>
'existing-warning',
'text' =>
'existing warning',
'module' =>
'main' ],
534 [
'code' =>
'existing-error',
'text' =>
'existing error',
'module' =>
'main' ],
536 'code' =>
'internal_api_error_DBQueryError',
537 'text' =>
"[$reqId] Database query error.",
545 new UsageException(
'Usage exception!',
'ue', 0, [
'foo' =>
'bar' ] ),
546 [
'existing-error',
'ue' ],
549 [
'code' =>
'existing-warning',
'text' =>
'existing warning',
'module' =>
'main' ],
552 [
'code' =>
'existing-error',
'text' =>
'existing error',
'module' =>
'main' ],
553 [
'code' =>
'ue',
'text' =>
"Usage exception!",
'data' => [
'foo' =>
'bar' ] ]
555 'docref' =>
"See $doclink for API usage. Subscribe to the mediawiki-api-announce mailing " .
556 "list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> " .
557 "for notice of API deprecations and breaking changes.",
563 [
'existing-error',
'sv-error1',
'sv-error2' ],
566 [
'code' =>
'existing-warning',
'text' =>
'existing warning',
'module' =>
'main' ],
567 [
'code' =>
'sv-warn1',
'text' =>
'A warning',
'module' =>
'foo+bar' ],
568 [
'code' =>
'sv-warn2',
'text' =>
'Another warning',
'module' =>
'foo+bar' ],
571 [
'code' =>
'existing-error',
'text' =>
'existing error',
'module' =>
'main' ],
572 [
'code' =>
'sv-error1',
'text' =>
'An error',
'module' =>
'foo+bar' ],
573 [
'code' =>
'sv-error2',
'text' =>
'Another error',
'module' =>
'foo+bar' ],
575 'docref' =>
"See $doclink for API usage. Subscribe to the mediawiki-api-announce mailing " .
576 "list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> " .
577 "for notice of API deprecations and breaking changes.",