API: Validate API error codes
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiMainTest.php
index f06d97e..3299e73 100644 (file)
@@ -967,8 +967,7 @@ class ApiMainTest extends ApiTestCase {
                $context->setLanguage( 'en' );
                $context->setConfig( new MultiConfig( [
                        new HashConfig( [
-                               'ShowHostnames' => true, 'ShowSQLErrors' => false,
-                               'ShowExceptionDetails' => true, 'ShowDBErrorBacktrace' => true,
+                               'ShowHostnames' => true, 'ShowExceptionDetails' => true,
                        ] ),
                        $context->getConfig()
                ] ) );
@@ -1011,9 +1010,14 @@ class ApiMainTest extends ApiTestCase {
                        MWExceptionHandler::getRedactedTraceAsString( $dbex )
                )->inLanguage( 'en' )->useDatabase( false )->text();
 
-               Wikimedia\suppressWarnings();
-               $usageEx = new UsageException( 'Usage exception!', 'ue', 0, [ 'foo' => 'bar' ] );
-               Wikimedia\restoreWarnings();
+               // The specific exception doesn't matter, as long as it's namespaced.
+               $nsex = new MediaWiki\ShellDisabledError();
+               $nstrace = wfMessage( 'api-exception-trace',
+                       get_class( $nsex ),
+                       $nsex->getFile(),
+                       $nsex->getLine(),
+                       MWExceptionHandler::getRedactedTraceAsString( $nsex )
+               )->inLanguage( 'en' )->useDatabase( false )->text();
 
                $apiEx1 = new ApiUsageException( null,
                        StatusValue::newFatal( new ApiRawMessage( 'An error', 'sv-error1' ) ) );
@@ -1022,6 +1026,13 @@ class ApiMainTest extends ApiTestCase {
                $apiEx1->getStatusValue()->warning( new ApiRawMessage( 'Another warning', 'sv-warn2' ) );
                $apiEx1->getStatusValue()->fatal( new ApiRawMessage( 'Another error', 'sv-error2' ) );
 
+               $badMsg = $this->getMockBuilder( ApiRawMessage::class )
+                        ->setConstructorArgs( [ 'An error', 'ignored' ] )
+                        ->setMethods( [ 'getApiCode' ] )
+                        ->getMock();
+               $badMsg->method( 'getApiCode' )->willReturn( "bad\nvalue" );
+               $apiEx2 = new ApiUsageException( null, StatusValue::newFatal( $badMsg ) );
+
                return [
                        [
                                $ex,
@@ -1052,7 +1063,8 @@ class ApiMainTest extends ApiTestCase {
                                                [ 'code' => 'existing-error', 'text' => 'existing error', 'module' => 'main' ],
                                                [
                                                        'code' => 'internal_api_error_DBQueryError',
-                                                       'text' => "[$reqId] Database query error.",
+                                                       'text' => "[$reqId] Exception caught: A database query error has occurred. " .
+                                                               "This may indicate a bug in the software.",
                                                ]
                                        ],
                                        'trace' => $dbtrace,
@@ -1060,19 +1072,20 @@ class ApiMainTest extends ApiTestCase {
                                ]
                        ],
                        [
-                               $usageEx,
-                               [ 'existing-error', 'ue' ],
+                               $nsex,
+                               [ 'existing-error', 'internal_api_error_MediaWiki\ShellDisabledError' ],
                                [
                                        'warnings' => [
                                                [ 'code' => 'existing-warning', 'text' => 'existing warning', 'module' => 'main' ],
                                        ],
                                        'errors' => [
                                                [ 'code' => 'existing-error', 'text' => 'existing error', 'module' => 'main' ],
-                                               [ 'code' => 'ue', 'text' => "Usage exception!", 'data' => [ 'foo' => 'bar' ] ]
+                                               [
+                                                       'code' => 'internal_api_error_MediaWiki\ShellDisabledError',
+                                                       'text' => "[$reqId] Exception caught: " . $nsex->getMessage(),
+                                               ]
                                        ],
-                                       'docref' => "See $doclink for API usage. Subscribe to the mediawiki-api-announce mailing " .
-                                               "list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> " .
-                                               "for notice of API deprecations and breaking changes.",
+                                       'trace' => $nstrace,
                                        'servedby' => wfHostname(),
                                ]
                        ],
@@ -1096,6 +1109,40 @@ class ApiMainTest extends ApiTestCase {
                                        'servedby' => wfHostname(),
                                ]
                        ],
+                       [
+                               $apiEx2,
+                               [ 'existing-error', '<invalid-code>' ],
+                               [
+                                       'warnings' => [
+                                               [ 'code' => 'existing-warning', 'text' => 'existing warning', 'module' => 'main' ],
+                                       ],
+                                       'errors' => [
+                                               [ 'code' => 'existing-error', 'text' => 'existing error', 'module' => 'main' ],
+                                               [ 'code' => "bad\nvalue", 'text' => 'An error' ],
+                                       ],
+                                       'docref' => "See $doclink for API usage. Subscribe to the mediawiki-api-announce mailing " .
+                                               "list at &lt;https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce&gt; " .
+                                               "for notice of API deprecations and breaking changes.",
+                                       'servedby' => wfHostname(),
+                               ]
+                       ]
                ];
        }
+
+       public function testPrinterParameterValidationError() {
+               $api = $this->getNonInternalApiMain( [
+                       'action' => 'query', 'meta' => 'siteinfo', 'format' => 'json', 'formatversion' => 'bogus',
+               ] );
+
+               ob_start();
+               $api->execute();
+               $txt = ob_get_clean();
+
+               // Test that the actual output is valid JSON, not just the format of the ApiResult.
+               $data = FormatJson::decode( $txt, true );
+               $this->assertInternalType( 'array', $data );
+               $this->assertArrayHasKey( 'error', $data );
+               $this->assertArrayHasKey( 'code', $data['error'] );
+               $this->assertSame( 'unknown_formatversion', $data['error']['code'] );
+       }
 }