Merge "Upgrade QUnit from 2.4.0 to 2.6.0"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 2 May 2018 16:18:22 +0000 (16:18 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 2 May 2018 16:18:23 +0000 (16:18 +0000)
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/logging/LogFormatter.php
includes/parser/BlockLevelPass.php
includes/specials/SpecialEditWatchlist.php
resources/src/mediawiki/api.js
tests/phpunit/includes/logging/LogFormatterTest.php
tests/phpunit/includes/specials/SpecialEditWatchlistTest.php
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js
tests/selenium/wdio.conf.js

index f44b7cb..8da1ca9 100644 (file)
@@ -722,12 +722,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        /**
-        * Get the list of method names that have pending write queries or that
-        * have transaction callbacks that have yet to run
+        * List the methods that have write queries or callbacks for the current transaction
         *
-        * @return array
+        * This method should not be used outside of Database/LoadBalancer
+        *
+        * @return string[]
+        * @since 1.32
         */
-       protected function pendingWriteAndCallbackCallers() {
+       public function pendingWriteAndCallbackCallers() {
                $fnames = $this->pendingWriteCallers();
                foreach ( [
                        $this->trxIdleCallbacks,
index e70d49e..ddc4277 100644 (file)
@@ -1424,6 +1424,14 @@ class LoadBalancer implements ILoadBalancer {
                                if ( $conn->writesPending() ) {
                                        // A callback from another handle wrote to this one and DBO_TRX is set
                                        $this->queryLogger->warning( __METHOD__ . ": found writes pending." );
+                                       $fnames = implode( ', ', $conn->pendingWriteAndCallbackCallers() );
+                                       $this->queryLogger->warning(
+                                               __METHOD__ . ": found writes pending ($fnames).",
+                                               [
+                                                       'db_server' => $conn->getServer(),
+                                                       'db_name' => $conn->getDBname()
+                                               ]
+                                       );
                                } elseif ( $conn->trxLevel() ) {
                                        // A callback from another handle read from this one and DBO_TRX is set,
                                        // which can easily happen if there is only one DB (no replicas)
index bc0491f..0ffe691 100644 (file)
@@ -108,6 +108,12 @@ class LogFormatter {
         */
        private $linkRenderer;
 
+       /**
+        * @see LogFormatter::getMessageParameters
+        * @var array
+        */
+       protected $parsedParameters;
+
        protected function __construct( LogEntry $entry ) {
                $this->entry = $entry;
                $this->context = RequestContext::getMain();
index 1173dd2..c366903 100644 (file)
@@ -291,19 +291,34 @@ class BlockLevelPass {
                        if ( 0 == $prefixLength ) {
                                # No prefix (not in list)--go to paragraph mode
                                # @todo consider using a stack for nestable elements like span, table and div
+
+                               // P-wrapping and indent-pre are suppressed inside, not outside
+                               $blockElems = 'table|h1|h2|h3|h4|h5|h6|pre|p|ul|ol|dl|li';
+                               // P-wrapping and indent-pre are suppressed outside, not inside
+                               $antiBlockElems = 'td|th';
+
                                $openMatch = preg_match(
-                                       '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
-                                               . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)\\b/iS',
+                                       '/<('
+                                               . "({$blockElems})|\\/({$antiBlockElems})|"
+                                               // Always suppresses
+                                               . '\\/?(tr)'
+                                               . ')\\b/iS',
                                        $t
                                );
                                $closeMatch = preg_match(
-                                       '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
-                                               . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
-                                               . Parser::MARKER_PREFIX
-                                               . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)\\b/iS',
+                                       '/<('
+                                               . "\\/({$blockElems})|({$antiBlockElems})|"
+                                               // Never suppresses
+                                               . '\\/?(center|blockquote|div|hr|mw:)'
+                                               . ')\\b/iS',
                                        $t
                                );
 
+                               // Any match closes the paragraph, but only when `!$closeMatch`
+                               // do we enter block mode.  The oddities with table rows and
+                               // cells are to avoid paragraph wrapping in interstitial spaces
+                               // leading to fostered content.
+
                                if ( $openMatch || $closeMatch ) {
                                        $pendingPTag = false;
                                        // Only close the paragraph if we're not inside a <pre> tag, or if
index f702bc0..5e04d8d 100644 (file)
@@ -667,7 +667,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                ];
                $context = new DerivativeContext( $this->getContext() );
                $context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
-               $form = new HTMLForm( $fields, $context );
+               $form = new OOUIHTMLForm( $fields, $context );
                $form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
                # Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
                $form->setSubmitTooltip( 'watchlistedit-raw-submit' );
@@ -686,7 +686,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        protected function getClearForm() {
                $context = new DerivativeContext( $this->getContext() );
                $context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
-               $form = new HTMLForm( [], $context );
+               $form = new OOUIHTMLForm( [], $context );
                $form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
                # Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
                $form->setSubmitTooltip( 'watchlistedit-clear-submit' );
index 2e5a92e..0038ed8 100644 (file)
                 * @return {jQuery.Promise} Received token.
                 */
                getToken: function ( type, assert ) {
-                       var apiPromise, promiseGroup, d;
+                       var apiPromise, promiseGroup, d, reject;
                        type = mapLegacyToken( type );
                        promiseGroup = promises[ this.defaults.ajax.url ];
                        d = promiseGroup && promiseGroup[ type + 'Token' ];
                                        type: type,
                                        assert: assert
                                } );
+                               reject = function () {
+                                       // Clear promise. Do not cache errors.
+                                       delete promiseGroup[ type + 'Token' ];
+
+                                       // Let caller handle the error code
+                                       return $.Deferred().rejectWith( this, arguments );
+                               };
                                d = apiPromise
                                        .then( function ( res ) {
+                                               if ( !res.query ) {
+                                                       return reject( 'query-missing', res );
+                                               }
                                                // If token type is unknown, it is omitted from the response
                                                if ( !res.query.tokens[ type + 'token' ] ) {
                                                        return $.Deferred().reject( 'token-missing', res );
                                                }
-
                                                return res.query.tokens[ type + 'token' ];
-                                       }, function () {
-                                               // Clear promise. Do not cache errors.
-                                               delete promiseGroup[ type + 'Token' ];
-
-                                               // Let caller handle the error code
-                                               return $.Deferred().rejectWith( this, arguments );
-                                       } )
+                                       }, reject )
                                        // Attach abort handler
                                        .promise( { abort: apiPromise.abort } );
 
index e523a31..91ce9ea 100644 (file)
@@ -91,10 +91,11 @@ class LogFormatterTest extends MediaWikiLangTestCase {
 
                $formatter->setShowUserToolLinks( false );
                $paramsWithoutTools = $formatter->getMessageParametersForTesting();
-               unset( $formatter->parsedParameters );
 
-               $formatter->setShowUserToolLinks( true );
-               $paramsWithTools = $formatter->getMessageParametersForTesting();
+               $formatter2 = LogFormatter::newFromEntry( $entry );
+               $formatter2->setContext( $this->context );
+               $formatter2->setShowUserToolLinks( true );
+               $paramsWithTools = $formatter2->getMessageParametersForTesting();
 
                $userLink = Linker::userLink(
                        $this->user->getId(),
index 05a63db..69fa0dd 100644 (file)
@@ -33,7 +33,7 @@ class SpecialEditWatchlistTest extends SpecialPageTestBase {
                $user = new TestUser( __METHOD__ );
                list( $html, ) = $this->executeSpecialPage( 'clear', null, 'qqx', $user->getUser() );
                $this->assertRegExp(
-                       '/<form class="mw-htmlform" action=".*?Special:EditWatchlist\/clear" method="post">/',
+                       '/<form action=\'.*?Special:EditWatchlist\/clear\'/',
                        $html
                );
        }
@@ -42,7 +42,7 @@ class SpecialEditWatchlistTest extends SpecialPageTestBase {
                $user = new TestUser( __METHOD__ );
                list( $html, ) = $this->executeSpecialPage( 'raw', null, 'qqx', $user->getUser() );
                $this->assertContains(
-                       '<textarea id="mw-input-wpTitles"',
+                       '<div id=\'mw-input-wpTitles\'',
                        $html
                );
        }
index 417ad3d..7431b29 100644 (file)
                        } );
        } );
 
+       QUnit.test( 'getToken() - no query', function ( assert ) {
+               var api = new mw.Api(),
+                       // Same-origin warning and missing query in response.
+                       serverRsp = {
+                               warnings: {
+                                       tokens: {
+                                               '*': 'Tokens may not be obtained when the same-origin policy is not applied.'
+                                       }
+                               }
+                       };
+
+               this.server.respondWith( /type=testnoquery/, [ 200, { 'Content-Type': 'application/json' },
+                       JSON.stringify( serverRsp )
+               ] );
+
+               return api.getToken( 'testnoquery' )
+                       .then( function () { assert.fail( 'Expected response missing a query to be rejected' ); } )
+                       .catch( function ( err, rsp ) {
+                               assert.equal( err, 'query-missing', 'Expected no query error code' );
+                               assert.deepEqual( rsp, serverRsp );
+                       } );
+       } );
+
        QUnit.test( 'getToken() - deprecated', function ( assert ) {
                // Cache API endpoint from default to avoid cachehit in mw.user.tokens
                var api = new mw.Api( { ajax: { url: '/postWithToken/api.php' } } ),
index 024801a..00fce66 100644 (file)
@@ -175,7 +175,7 @@ exports.config = {
        // See the full list at http://mochajs.org/
        mochaOpts: {
                ui: 'bdd',
-               timeout: 20000
+               timeout: 60000
        },
 
        // =====