Ori.livneh has uploaded a new change for review.

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

Change subject: Use hashes instead of names in module strings
......................................................................

Use hashes instead of names in module strings

The code that enforces $wgResourceLoaderMaxQueryLength is a good contender for
being the nastiest piece of JavaScript in ResourceLoader. It forces the code
that partitions the list of module dependencies into logical batches to predict
how the modules will eventually be packed in a query string, so that it can
avoid calling doRequest() with input that would cause it to produce a URL that
would exceed the limit. This requires that the caller of doRequest() know
absurdly specific things about the behavior of downstream code, such as the
fact that $.param() will inflate the length of the separator characters used by
buildModuleString() because they will need to be percent-encoded.

This patch blows away all of this cruft by defining a compact scheme for
packing module requirements into a query string. Instead of identifying each
module by name, each module name is converted into an 8-character hash, and the
hashes are concatenated together. PHP code is able to resolve these hashes by
iterating on all known module names and building a reverse-lookup table.

There are no collisions (two distinct module names that hash to the same value)
in the 3,727 module names I could discover by iterating through Wikimedia
wikis. The risk of collisions is very remote, but it does exist, so the code
handles it gracefully.  In case of collision, the backend will not be able to
determine which module the frontend intended to request. The solution is to
simply send both, and let the frontend pick the right one.

Notes:

* The module hash is sent as the value of the 'hash' query parameter. It
  replaces the old 'modules' parameter, except in debug mode. Support for the
  'modules' parameter (and its peculiar encoding) is retained so as to preserve
  backward-compatibility and to make the migration process smooth.
* Since even the default (paranoid) value of 512 for 
suhosin.get.max_value_length
  is enough to accomodate 60 modules, we don't have to check it in the 
installer.

Change-Id: If60f264e9c31fa8a6e24d9faa7e035734a5abb0e
---
M includes/DefaultSettings.php
M includes/OutputPage.php
M includes/Setup.php
M includes/installer/Installer.php
M includes/installer/i18n/en.json
M includes/installer/i18n/qqq.json
M includes/resourceloader/ResourceLoader.php
M includes/resourceloader/ResourceLoaderContext.php
M includes/resourceloader/ResourceLoaderStartUpModule.php
M resources/src/mediawiki/mediawiki.js
M tests/phpunit/includes/OutputPageTest.php
M tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
12 files changed, 70 insertions(+), 140 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/79/296179/1

diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index f176556..1e29e69 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -3669,21 +3669,6 @@
 $wgLegacyJavaScriptGlobals = true;
 
 /**
- * If set to a positive number, ResourceLoader will not generate URLs whose
- * query string is more than this many characters long, and will instead use
- * multiple requests with shorter query strings. This degrades performance,
- * but may be needed if your web server has a low (less than, say 1024)
- * query string length limit or a low value for suhosin.get.max_value_length
- * that you can't increase.
- *
- * If set to a negative number, ResourceLoader will assume there is no query
- * string length limit.
- *
- * Defaults to a value based on php configuration.
- */
-$wgResourceLoaderMaxQueryLength = false;
-
-/**
  * If set to true, JavaScript modules loaded from wiki pages will be parsed
  * prior to minification to validate it.
  *
diff --git a/includes/OutputPage.php b/includes/OutputPage.php
index 53c70d8..1f42b63 100644
--- a/includes/OutputPage.php
+++ b/includes/OutputPage.php
@@ -2875,7 +2875,7 @@
                                        $query['version'] = 
$resourceLoader->getCombinedVersion( $context, array_keys( $grpModules ) );
                                }
 
-                               $query['modules'] = 
ResourceLoader::makePackedModulesString( array_keys( $grpModules ) );
+                               $query['hash'] = 
ResourceLoader::makePackedModulesString( array_keys( $grpModules ) );
                                $moduleContext = new ResourceLoaderContext( 
$resourceLoader, new FauxRequest( $query ) );
                                $url = $resourceLoader->createLoaderURL( 
$source, $moduleContext, $extraQuery );
 
diff --git a/includes/Setup.php b/includes/Setup.php
index 5877932..c1eb7ae 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -349,17 +349,6 @@
        $wgMetaNamespace = str_replace( ' ', '_', $wgSitename );
 }
 
-// Default value is 2000 or the suhosin limit if it is between 1 and 2000
-if ( $wgResourceLoaderMaxQueryLength === false ) {
-       $suhosinMaxValueLength = (int)ini_get( 'suhosin.get.max_value_length' );
-       if ( $suhosinMaxValueLength > 0 && $suhosinMaxValueLength < 2000 ) {
-               $wgResourceLoaderMaxQueryLength = $suhosinMaxValueLength;
-       } else {
-               $wgResourceLoaderMaxQueryLength = 2000;
-       }
-       unset( $suhosinMaxValueLength );
-}
-
 // Ensure the minimum chunk size is less than PHP upload limits or the maximum
 // upload size.
 $wgMinUploadChunkSize = min(
diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php
index 4d5aa7a..c9d9bd5 100644
--- a/includes/installer/Installer.php
+++ b/includes/installer/Installer.php
@@ -133,7 +133,6 @@
                'envCheckShellLocale',
                'envCheckUploadsDirectory',
                'envCheckLibicu',
-               'envCheckSuhosinMaxValueLength',
        ];
 
        /**
@@ -1059,21 +1058,6 @@
 
                if ( !$safe ) {
                        $this->showMessage( 'config-uploads-not-safe', $dir );
-               }
-
-               return true;
-       }
-
-       /**
-        * Checks if suhosin.get.max_value_length is set, and if so generate
-        * a warning because it decreases ResourceLoader performance.
-        * @return bool
-        */
-       protected function envCheckSuhosinMaxValueLength() {
-               $maxValueLength = ini_get( 'suhosin.get.max_value_length' );
-               if ( $maxValueLength > 0 && $maxValueLength < 1024 ) {
-                       // Only warn if the value is below the sane 1024
-                       $this->showMessage( 'config-suhosin-max-value-length', 
$maxValueLength );
                }
 
                return true;
diff --git a/includes/installer/i18n/en.json b/includes/installer/i18n/en.json
index 2b7886a..3c734e5 100644
--- a/includes/installer/i18n/en.json
+++ b/includes/installer/i18n/en.json
@@ -73,7 +73,6 @@
        "config-uploads-not-safe": "<strong>Warning:</strong> Your default 
directory for uploads <code>$1</code> is vulnerable to arbitrary scripts 
execution.\nAlthough MediaWiki checks all uploaded files for security threats, 
it is highly recommended to 
[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security
 close this security vulnerability] before enabling uploads.",
        "config-no-cli-uploads-check": "<strong>Warning:</strong> Your default 
directory for uploads (<code>$1</code>) is not checked for vulnerability\nto 
arbitrary script execution during the CLI install.",
        "config-brokenlibxml": "Your system has a combination of PHP and 
libxml2 versions that is buggy and can cause hidden data corruption in 
MediaWiki and other web applications.\nUpgrade to libxml2 2.7.3 or later 
([https://bugs.php.net/bug.php?id=45996 bug filed with PHP]).\nInstallation 
aborted.",
-       "config-suhosin-max-value-length": "Suhosin is installed and limits the 
GET parameter <code>length</code> to $1 bytes.\nMediaWiki's ResourceLoader 
component will work around this limit, but that will degrade performance.\nIf 
at all possible, you should set <code>suhosin.get.max_value_length</code> to 
1024 or higher in <code>php.ini</code>, and set 
<code>$wgResourceLoaderMaxQueryLength</code> to the same value in 
<code>LocalSettings.php</code>.",
        "config-db-type": "Database type:",
        "config-db-host": "Database host:",
        "config-db-host-help": "If your database server is on different server, 
enter the host name or IP address here.\n\nIf you are using shared web hosting, 
your hosting provider should give you the correct host name in their 
documentation.\n\nIf you are installing on a Windows server and using MySQL, 
using \"localhost\" may not work for the server name. If it does not, try 
\"127.0.0.1\" for the local IP address.\n\nIf you are using PostgreSQL, leave 
this field blank to connect via a Unix socket.",
diff --git a/includes/installer/i18n/qqq.json b/includes/installer/i18n/qqq.json
index 66a24c0..80b4eb7 100644
--- a/includes/installer/i18n/qqq.json
+++ b/includes/installer/i18n/qqq.json
@@ -91,7 +91,6 @@
        "config-uploads-not-safe": "Used as a part of environment check result. 
Parameters:\n* $1 - name of directory for images: <code>$IP/images/</code>",
        "config-no-cli-uploads-check": "CLI = [[w:Command-line 
interface|command-line interface]] (i.e. the installer runs as a command-line 
script, not using HTML interface via an internet browser)",
        "config-brokenlibxml": "Status message in the MediaWiki installer 
environment checks.",
-       "config-suhosin-max-value-length": "{{doc-important|Do not translate 
\"length\", \"suhosin.get.max_value_length\", \"php.ini\", 
\"$wgResourceLoaderMaxQueryLength\" and \"LocalSettings.php\".}}\nMessage shown 
when PHP parameter <code>suhosin.get.max_value_length</code> is between 0 and 
1023 (that max value is hard set in MediaWiki software).",
        "config-db-type": "Field label in the MediaWiki installer followed by 
possible database types.",
        "config-db-host": "Used as label.\n\nAlso used in 
{{msg-mw|Config-missing-db-host}}.",
        "config-db-host-help": "{{doc-singularthey}}",
diff --git a/includes/resourceloader/ResourceLoader.php 
b/includes/resourceloader/ResourceLoader.php
index 633cd49..b457e0f 100644
--- a/includes/resourceloader/ResourceLoader.php
+++ b/includes/resourceloader/ResourceLoader.php
@@ -55,6 +55,12 @@
         */
        protected $moduleInfos = [];
 
+       /**
+        * Associative array mapping module name to info associative array
+        * @var array
+        */
+       protected $moduleNameHashes = [];
+
        /** @var Config $config */
        private $config;
 
@@ -334,6 +340,9 @@
                        }
 
                        // Attach module
+                       $nameHash = self::makeHash( $name );
+                       $this->moduleNameHashes[ $nameHash ][] = $name;
+
                        if ( $info instanceof ResourceLoaderModule ) {
                                $this->moduleInfos[$name] = [ 'object' => $info 
];
                                $info->setName( $name );
@@ -467,6 +476,23 @@
                }
 
                $this->sources[$id] = $loadUrl;
+       }
+
+       /**
+        * Get a list of module names.
+        *
+        * @return array List of module names
+        */
+       public function resolveModuleHash( $moduleHash ) {
+               $hashLength = strlen( self::makeHash( '' ) );
+               $modules = [];
+               foreach ( str_split( $moduleHash, $hashLength ) as $hash ) {
+                       if ( !isset( $this->moduleNameHashes[ $hash ] ) ) {
+                               continue;
+                       }
+                       $modules = array_merge( $modules, 
$this->moduleNameHashes[ $hash ] );
+               }
+               return $modules;
        }
 
        /**
@@ -1398,29 +1424,19 @@
        }
 
        /**
-        * Convert an array of module names to a packed query string.
+        * Construct a hash string from an array of module names.
         *
-        * For example, array( 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' )
-        * becomes 'foo.bar,baz|bar.baz,quux'
+        * Each module name is hashed, and then the hashes are concatenated
+        * to a single string. Since the hashes have a uniform width, there
+        * are no separators.
+        *
         * @param array $modules List of module names (strings)
         * @return string Packed query string
         */
        public static function makePackedModulesString( $modules ) {
-               $groups = []; // array( prefix => array( suffixes ) )
-               foreach ( $modules as $module ) {
-                       $pos = strrpos( $module, '.' );
-                       $prefix = $pos === false ? '' : substr( $module, 0, 
$pos );
-                       $suffix = $pos === false ? $module : substr( $module, 
$pos + 1 );
-                       $groups[$prefix][] = $suffix;
-               }
-
-               $arr = [];
-               foreach ( $groups as $prefix => $suffixes ) {
-                       $p = $prefix === '' ? '' : $prefix . '.';
-                       $arr[] = $p . implode( ',', $suffixes );
-               }
-               $str = implode( '|', $arr );
-               return $str;
+               return array_reduce( $modules, function ( $hash, $module ) {
+                       return $hash . self::makeHash( $module );
+               }, '' );
        }
 
        /**
@@ -1541,11 +1557,17 @@
                $handheld = false, $extraQuery = []
        ) {
                $query = [
-                       'modules' => self::makePackedModulesString( $modules ),
                        'lang' => $lang,
                        'skin' => $skin,
                        'debug' => $debug ? 'true' : 'false',
                ];
+
+               if ( $debug ) {
+                       $query['modules'] = implode( '|', $modules );
+               } else {
+                       $query['hash'] = self::makePackedModulesString( 
$modules );
+               }
+
                if ( $user !== null ) {
                        $query['user'] = $user;
                }
diff --git a/includes/resourceloader/ResourceLoaderContext.php 
b/includes/resourceloader/ResourceLoaderContext.php
index 85fc53d..d7403f5 100644
--- a/includes/resourceloader/ResourceLoaderContext.php
+++ b/includes/resourceloader/ResourceLoaderContext.php
@@ -63,8 +63,13 @@
                $this->logger = $resourceLoader->getLogger();
 
                // List of modules
-               $modules = $request->getVal( 'modules' );
-               $this->modules = $modules ? self::expandModuleNames( $modules ) 
: [];
+               $moduleHash = $request->getVal( 'hash' );
+               if ( $moduleHash ) {
+                       $this->modules = $resourceLoader->resolveModuleHash( 
$moduleHash );
+               } else {
+                       $modules = $request->getVal( 'modules' );
+                       $this->modules = $modules ? self::expandModuleNames( 
$modules ) : [];
+               }
 
                // Various parameters
                $this->user = $request->getVal( 'user' );
diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php 
b/includes/resourceloader/ResourceLoaderStartUpModule.php
index 34866f3..a5b6084 100644
--- a/includes/resourceloader/ResourceLoaderStartUpModule.php
+++ b/includes/resourceloader/ResourceLoaderStartUpModule.php
@@ -104,7 +104,6 @@
                        'wgCookieDomain' => $conf->get( 'CookieDomain' ),
                        'wgCookiePath' => $conf->get( 'CookiePath' ),
                        'wgCookieExpiration' => $conf->get( 'CookieExpiration' 
),
-                       'wgResourceLoaderMaxQueryLength' => $conf->get( 
'ResourceLoaderMaxQueryLength' ),
                        'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces,
                        'wgLegalTitleChars' => 
Title::convertByteClassToUnicodeClass( Title::legalChars() ),
                        'wgResourceLoaderStorageVersion' => $conf->get( 
'ResourceLoaderStorageVersion' ),
@@ -311,7 +310,7 @@
                $moduleNames = self::getStartupModules();
 
                $query = [
-                       'modules' => ResourceLoader::makePackedModulesString( 
$moduleNames ),
+                       'hash' => ResourceLoader::makePackedModulesString( 
$moduleNames ),
                        'only' => 'scripts',
                        'lang' => $context->getLanguage(),
                        'skin' => $context->getSkin(),
diff --git a/resources/src/mediawiki/mediawiki.js 
b/resources/src/mediawiki/mediawiki.js
index c859deb..6f11e2f 100644
--- a/resources/src/mediawiki/mediawiki.js
+++ b/resources/src/mediawiki/mediawiki.js
@@ -1472,33 +1472,16 @@
                        }
 
                        /**
-                        * Converts a module map of the form { foo: [ 'bar', 
'baz' ], bar: [ 'baz, 'quux' ] }
-                        * to a query string of the form 
foo.bar,baz|bar.baz,quux
-                        *
-                        * @private
-                        */
-                       function buildModulesString( moduleMap ) {
-                               var p, prefix,
-                                       arr = [];
-
-                               for ( prefix in moduleMap ) {
-                                       p = prefix === '' ? '' : prefix + '.';
-                                       arr.push( p + moduleMap[ prefix ].join( 
',' ) );
-                               }
-                               return arr.join( '|' );
-                       }
-
-                       /**
                         * Load modules from load.php
                         *
                         * @private
-                        * @param {Object} moduleMap Module map, see 
#buildModulesString
+                        * @param {Array} modules Modules array
                         * @param {Object} currReqBase Object with other 
parameters (other than 'modules') to use in the request
                         * @param {string} sourceLoadScript URL of load.php
                         */
-                       function doRequest( moduleMap, currReqBase, 
sourceLoadScript ) {
+                       function doRequest( modules, currReqBase, 
sourceLoadScript ) {
                                var request = $.extend(
-                                       { modules: buildModulesString( 
moduleMap ) },
+                                       { hash: modules.map( fnv132 ).join( '' 
) },
                                        currReqBase
                                );
                                request = sortQuery( request );
@@ -1548,10 +1531,9 @@
                                 * Batch-request queued dependencies from the 
server.
                                 */
                                work: function () {
-                                       var     reqBase, splits, 
maxQueryLength, q, b, bSource, bGroup, bSourceGroup,
-                                               source, concatSource, 
origBatch, group, i, modules, sourceLoadScript,
-                                               currReqBase, currReqBaseLength, 
moduleMap, l,
-                                               lastDotIndex, prefix, suffix, 
bytesAdded;
+                                       var     reqBase, splits, q, b, bSource, 
bGroup, bSourceGroup,
+                                               source, concatSource, 
origBatch, group, modules,
+                                               sourceLoadScript, currReqBase;
 
                                        // Build a list of request parameters 
common to all requests.
                                        reqBase = {
@@ -1561,7 +1543,6 @@
                                        };
                                        // Split module batch by source and by 
group.
                                        splits = {};
-                                       maxQueryLength = mw.config.get( 
'wgResourceLoaderMaxQueryLength', 2000 );
 
                                        // Appends a list of modules from the 
queue to the batch
                                        for ( q = 0; q < queue.length; q++ ) {
@@ -1663,45 +1644,8 @@
                                                        if ( group === 'user' 
&& mw.config.get( 'wgUserName' ) !== null ) {
                                                                
currReqBase.user = mw.config.get( 'wgUserName' );
                                                        }
-                                                       currReqBaseLength = 
$.param( currReqBase ).length;
-                                                       // We may need to split 
up the request to honor the query string length limit,
-                                                       // so build it piece by 
piece.
-                                                       l = currReqBaseLength + 
9; // '&modules='.length == 9
 
-                                                       moduleMap = {}; // { 
prefix: [ suffixes ] }
-
-                                                       for ( i = 0; i < 
modules.length; i++ ) {
-                                                               // Determine 
how many bytes this module would add to the query string
-                                                               lastDotIndex = 
modules[ i ].lastIndexOf( '.' );
-
-                                                               // If 
lastDotIndex is -1, substr() returns an empty string
-                                                               prefix = 
modules[ i ].substr( 0, lastDotIndex );
-                                                               suffix = 
modules[ i ].slice( lastDotIndex + 1 );
-
-                                                               bytesAdded = 
hasOwn.call( moduleMap, prefix )
-                                                                       ? 
suffix.length + 3 // '%2C'.length == 3
-                                                                       : 
modules[ i ].length + 3; // '%7C'.length == 3
-
-                                                               // If the 
request would become too long, create a new one,
-                                                               // but don't 
create empty requests
-                                                               if ( 
maxQueryLength > 0 && !$.isEmptyObject( moduleMap ) && l + bytesAdded > 
maxQueryLength ) {
-                                                                       // This 
request would become too long, create a new one
-                                                                       // and 
fire off the old one
-                                                                       
doRequest( moduleMap, currReqBase, sourceLoadScript );
-                                                                       
moduleMap = {};
-                                                                       l = 
currReqBaseLength + 9;
-                                                                       
mw.track( 'resourceloader.splitRequest', { maxQueryLength: maxQueryLength } );
-                                                               }
-                                                               if ( 
!hasOwn.call( moduleMap, prefix ) ) {
-                                                                       
moduleMap[ prefix ] = [];
-                                                               }
-                                                               moduleMap[ 
prefix ].push( suffix );
-                                                               l += bytesAdded;
-                                                       }
-                                                       // If there's anything 
left in moduleMap, request that too
-                                                       if ( !$.isEmptyObject( 
moduleMap ) ) {
-                                                               doRequest( 
moduleMap, currReqBase, sourceLoadScript );
-                                                       }
+                                                       doRequest( modules, 
currReqBase, sourceLoadScript );
                                                }
                                        }
                                },
diff --git a/tests/phpunit/includes/OutputPageTest.php 
b/tests/phpunit/includes/OutputPageTest.php
index 9934749..4a7e31c 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -143,20 +143,20 @@
                        [
                                [ 'test.foo', 
ResourceLoaderModule::TYPE_SCRIPTS ],
                                
"<script>(window.RLQ=window.RLQ||[]).push(function(){"
-                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback";);'
+                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026hash=495853b3\u0026lang=en\u0026only=scripts\u0026skin=fallback";);'
                                        . "});</script>"
                        ],
                        [
                                // Don't condition wrap raw modules (like the 
startup module)
                                [ 'test.raw', 
ResourceLoaderModule::TYPE_SCRIPTS ],
-                               '<script async="" 
src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback";></script>'
+                               '<script async="" 
src="http://127.0.0.1:8080/w/load.php?debug=false&amp;hash=473a3bd5&amp;lang=en&amp;only=scripts&amp;skin=fallback";></script>'
                        ],
                        // Load module styles only
                        // This also tests the order the modules are put into 
the url
                        [
                                [ [ 'test.baz', 'test.foo', 'test.bar' ], 
ResourceLoaderModule::TYPE_STYLES ],
 
-                               '<link rel="stylesheet" 
href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.bar%2Cbaz%2Cfoo&amp;only=styles&amp;skin=fallback"/>'
+                               '<link rel="stylesheet" 
href="http://127.0.0.1:8080/w/load.php?debug=false&amp;hash=2762abc02762abc8495853b3&amp;lang=en&amp;only=styles&amp;skin=fallback"/>'
                        ],
                        // Load private module (only=scripts)
                        [
@@ -181,16 +181,16 @@
                        // noscript group
                        [
                                [ 'test.noscript', 
ResourceLoaderModule::TYPE_STYLES ],
-                               '<noscript><link rel="stylesheet" 
href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.noscript&amp;only=styles&amp;skin=fallback"/></noscript>'
+                               '<noscript><link rel="stylesheet" 
href="http://127.0.0.1:8080/w/load.php?debug=false&amp;hash=e1d2a625&amp;lang=en&amp;only=styles&amp;skin=fallback"/></noscript>'
                        ],
                        // Load two modules in separate groups
                        [
                                [ [ 'test.group.foo', 'test.group.bar' ], 
ResourceLoaderModule::TYPE_COMBINED ],
                                
"<script>(window.RLQ=window.RLQ||[]).push(function(){"
-                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback";);'
+                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026hash=c20c404f\u0026lang=en\u0026skin=fallback";);'
                                        . "});</script>\n"
                                        . 
"<script>(window.RLQ=window.RLQ||[]).push(function(){"
-                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback";);'
+                                       . 
'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026hash=d4155680\u0026lang=en\u0026skin=fallback";);'
                                        . "});</script>"
                        ],
                ];
diff --git a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php 
b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
index 65cd6ed..373c97c 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderTest.php
@@ -89,15 +89,15 @@
         * @dataProvider providePackedModules
         * @covers ResourceLoader::makePackedModulesString
         */
-       public function testMakePackedModulesString( $desc, $modules, $packed ) 
{
-               $this->assertEquals( $packed, 
ResourceLoader::makePackedModulesString( $modules ), $desc );
+       public function testMakePackedModulesString( $desc, $modules, $packed, 
$hash ) {
+               $this->assertEquals( $hash, 
ResourceLoader::makePackedModulesString( $modules ), $desc );
        }
 
        /**
         * @dataProvider providePackedModules
         * @covers ResourceLoaderContext::expandModuleNames
         */
-       public function testexpandModuleNames( $desc, $modules, $packed ) {
+       public function testexpandModuleNames( $desc, $modules, $packed, $hash 
) {
                $this->assertEquals( $modules, 
ResourceLoaderContext::expandModuleNames( $packed ), $desc );
        }
 
@@ -107,21 +107,25 @@
                                'Example from makePackedModulesString doc 
comment',
                                [ 'foo.bar', 'foo.baz', 'bar.baz', 'bar.quux' ],
                                'foo.bar,baz|bar.baz,quux',
+                               '7d012b3e7d012b3651f985214b182353',
                        ],
                        [
                                'Example from expandModuleNames doc comment',
                                [ 'jquery.foo', 'jquery.bar', 'jquery.ui.baz', 
'jquery.ui.quux' ],
                                'jquery.foo,bar|jquery.ui.baz,quux',
+                               '870bb391a9015c5a1f6bec5c7521758c',
                        ],
                        [
                                'Regression fixed in r88706 with dotless names',
                                [ 'foo', 'bar', 'baz' ],
                                'foo,bar,baz',
+                               '408f5e131e99b6201e99b628',
                        ],
                        [
                                'Prefixless modules after a prefixed module',
                                [ 'single.module', 'foobar', 'foobaz' ],
                                'single.module|foobar,foobaz',
+                               '58b8faad31f0b26231f0b26a',
                        ],
                ];
        }

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: If60f264e9c31fa8a6e24d9faa7e035734a5abb0e
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Ori.livneh <o...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to