Krinkle has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/190154

Change subject: mediawiki.jqueryMsg: Refactor "Match PHP parser" test suite
......................................................................

mediawiki.jqueryMsg: Refactor "Match PHP parser" test suite

Previously it was doing quite a few things wrong:

* Tests could potentially run in parallel. This was somewhat
  obscured by the asynchronous getMwLanguage() call being inside
  the synchronous each() loop. As such it basically first fired off
  the requests, and then handled them as they came back. They
  pretty much always come back in order (lucky) so the tests pass,
  but it was fragile.

* By default, jQuery.ajax() appends a cache buster ("&_{random}" query string)
  to requests with dataType 'script'. Disable this by setting cache=true.

Also:
* Store Promise objects instead of a low-level Callbacks list so that we don't
  have to wrap it. Instead, we simply chain from the $.ajax() promise, and use
  then() to feed the value instead of calling resolve() or fire().
* Use hasOwn() as extra sanity check (in case a random browser's non-standard
  Object.prototype methods match one of our non-standard language codes).
* Remove dead code "mw.messages.set( test.message )". This object has no message
  property (or anything else that it could be mistaken for). It just performs
  15 no-op in a loop. Follows-up 261aac63ec0777d6.

While the requests happen to (almost) always arrive in order, them running in
parallel put a lot of pressure on slow VMs using SQLite databases (which are 
I/O bound).
This can cause a lock when queries from different processes overlap.

Change-Id: I0c5064780f80e1ddcc58ce32c390b2639b1f1ab6
---
M tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
1 file changed, 90 insertions(+), 62 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/54/190154/1

diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js 
b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
index 28d6d92..2ff808e 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js
@@ -1,6 +1,7 @@
 ( function ( mw, $ ) {
-       var mwLanguageCache = {}, formatText, formatParse, formatnumTests, 
specialCharactersPageName,
-               expectedListUsers, expectedEntrypoints;
+       var formatText, formatParse, formatnumTests, specialCharactersPageName, 
expectedListUsers, expectedEntrypoints,
+               mwLanguageCache = {},
+               hasOwn = Object.hasOwnProperty;
 
        // When the expected result is the same in both modes
        function assertBothModes( assert, parserArguments, expectedResult, 
assertMessage ) {
@@ -60,31 +61,52 @@
                }
        } ) );
 
-       function getMwLanguage( langCode, cb ) {
-               if ( mwLanguageCache[langCode] !== undefined ) {
-                       mwLanguageCache[langCode].add( cb );
-                       return;
-               }
-               mwLanguageCache[langCode] = $.Callbacks( 'once memory' );
-               mwLanguageCache[langCode].add( cb );
-               $.ajax( {
-                       url: mw.util.wikiScript( 'load' ),
-                       data: {
-                               skin: mw.config.get( 'skin' ),
-                               lang: langCode,
-                               debug: mw.config.get( 'debug' ),
-                               modules: [
-                                       'mediawiki.language.data',
-                                       'mediawiki.language'
-                               ].join( '|' ),
-                               only: 'scripts'
-                       },
-                       dataType: 'script'
-               } ).done( function () {
-                               mwLanguageCache[langCode].fire( mw.language );
-                       } ).fail( function () {
-                               mwLanguageCache[langCode].fire( false );
+       /**
+        * Be careful not to run this in parallel as it uses a global 
identifier (mw.language)
+        * to transport the module back to the test. It musn't be overwritten 
concurrentely.
+        *
+        * This function caches the mw.language data to avoid having to request 
the same data
+        * multiple times. There is more than one test cases for one language.
+        */
+       function getMwLanguage( langCode ) {
+               if ( !hasOwn.call( mwLanguageCache, langCode ) ) {
+                       mwLanguageCache[langCode] = $.ajax( {
+                               url: mw.util.wikiScript( 'load' ),
+                               data: {
+                                       skin: mw.config.get( 'skin' ),
+                                       lang: langCode,
+                                       debug: mw.config.get( 'debug' ),
+                                       modules: [
+                                               'mediawiki.language.data',
+                                               'mediawiki.language'
+                                       ].join( '|' ),
+                                       only: 'scripts'
+                               },
+                               dataType: 'script',
+                               cache: true
+                       } ).then( function () {
+                               return mw.language;
                        } );
+               }
+               return mwLanguageCache[langCode];
+       }
+
+       /**
+        * @param {Function[]} tasks List of functions that perform tasks
+        *  that may be asynchronous. Invoke the callback parameter when done.
+        * @param {Function} done When all tasks are done.
+        * @return
+        */
+       function process( tasks, done ) {
+               function run() {
+                       var task = tasks.shift();
+                       if ( task ) {
+                               task( run );
+                       } else {
+                               done();
+                       }
+               }
+               run();
        }
 
        QUnit.test( 'Replace', 16, function ( assert ) {
@@ -283,23 +305,27 @@
 
        QUnit.test( 'Match PHP parser', mw.libs.phpParserData.tests.length, 
function ( assert ) {
                mw.messages.set( mw.libs.phpParserData.messages );
-               $.each( mw.libs.phpParserData.tests, function ( i, test ) {
-                       QUnit.stop();
-                       getMwLanguage( test.lang, function ( langClass ) {
-                               QUnit.start();
-                               if ( !langClass ) {
-                                       assert.ok( false, 'Language "' + 
test.lang + '" failed to load' );
-                                       return;
-                               }
-                               mw.config.set( 'wgUserLanguage', test.lang );
-                               var parser = new mw.jqueryMsg.parser( { 
language: langClass } );
-                               assert.equal(
-                                       parser.parse( test.key, test.args 
).html(),
-                                       test.result,
-                                       test.name
-                               );
-                       } );
+               var tasks = $.map( mw.libs.phpParserData.tests, function ( test 
) {
+                       return function ( next ) {
+                               getMwLanguage( test.lang )
+                                       .done( function ( langClass ) {
+                                               mw.config.set( 
'wgUserLanguage', test.lang );
+                                               var parser = new 
mw.jqueryMsg.parser( { language: langClass } );
+                                               assert.equal(
+                                                       parser.parse( test.key, 
test.args ).html(),
+                                                       test.result,
+                                                       test.name
+                                               );
+                                       } )
+                                       .fail( function () {
+                                               assert.ok( false, 'Language "' 
+ test.lang + '" failed to load.' );
+                                       } )
+                                       .always( next );
+                       };
                } );
+
+               QUnit.stop();
+               process( tasks, QUnit.start );
        } );
 
        QUnit.test( 'Links', 6, function ( assert ) {
@@ -466,8 +492,8 @@
                );
        } );
 
-// Tests that getMessageFunction is used for non-plain messages with curly 
braces or
-// square brackets, but not otherwise.
+       // Tests that getMessageFunction is used for non-plain messages with 
curly braces or
+       // square brackets, but not otherwise.
        QUnit.test( 'mw.Message.prototype.parser monkey-patch', 22, function ( 
assert ) {
                var oldGMF, outerCalled, innerCalled;
 
@@ -618,25 +644,27 @@
 QUnit.test( 'formatnum', formatnumTests.length, function ( assert ) {
        mw.messages.set( 'formatnum-msg', '{{formatnum:$1}}' );
        mw.messages.set( 'formatnum-msg-int', '{{formatnum:$1|R}}' );
-       $.each( formatnumTests, function ( i, test ) {
-               QUnit.stop();
-               getMwLanguage( test.lang, function ( langClass ) {
-                       QUnit.start();
-                       if ( !langClass ) {
-                               assert.ok( false, 'Language "' + test.lang + '" 
failed to load' );
-                               return;
-                       }
-                       mw.messages.set(test.message );
-                       mw.config.set( 'wgUserLanguage', test.lang );
-                       var parser = new mw.jqueryMsg.parser( { language: 
langClass } );
-                       assert.equal(
-                               parser.parse( test.integer ? 
'formatnum-msg-int' : 'formatnum-msg',
-                                       [ test.number ] ).html(),
-                               test.result,
-                               test.description
-                       );
-               } );
+       var queue = $.map( formatnumTests, function ( test ) {
+               return function ( next ) {
+                       getMwLanguage( test.lang )
+                               .done( function ( langClass ) {
+                                       mw.config.set( 'wgUserLanguage', 
test.lang );
+                                       var parser = new mw.jqueryMsg.parser( { 
language: langClass } );
+                                       assert.equal(
+                                               parser.parse( test.integer ? 
'formatnum-msg-int' : 'formatnum-msg',
+                                                       [ test.number ] 
).html(),
+                                               test.result,
+                                               test.description
+                                       );
+                               } )
+                               .fail( function () {
+                                       assert.ok( false, 'Language "' + 
test.lang + '" failed to load' );
+                               } )
+                               .always( next );
+               };
        } );
+       QUnit.stop();
+       process( queue, QUnit.start );
 } );
 
 // HTML in wikitext

-- 
To view, visit https://gerrit.wikimedia.org/r/190154
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0c5064780f80e1ddcc58ce32c390b2639b1f1ab6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Krinkle <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to