2016-08-29 23:35:55 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* See also:
|
|
|
|
|
* - ResourceLoaderImageModuleTest::testContext
|
|
|
|
|
*
|
2019-04-11 20:28:53 +00:00
|
|
|
* @group ResourceLoader
|
2016-08-29 23:35:55 +00:00
|
|
|
* @covers ResourceLoaderContext
|
|
|
|
|
*/
|
2018-02-17 12:29:13 +00:00
|
|
|
class ResourceLoaderContextTest extends PHPUnit\Framework\TestCase {
|
2017-12-29 23:22:37 +00:00
|
|
|
|
|
|
|
|
use MediaWikiCoversValidator;
|
|
|
|
|
|
2016-08-29 23:35:55 +00:00
|
|
|
protected static function getResourceLoader() {
|
|
|
|
|
return new EmptyResourceLoader( new HashConfig( [
|
|
|
|
|
'ResourceLoaderDebug' => false,
|
resourceloader: Don't let module exception break startup
When getScript (or some other method used in a module response)
throws an error, only that module fails (by outputting mw.loader.state
instead of mw.loader.implement). Other modules will work.
This has always been the case and is working fine. For example,
"load.php?modules=foo|bar", where 'foo' throws, will return:
```js
/* exception message: .. */
mw.loader.implement('bar', ..)
mw.loader.state('foo', 'error')
```
The problem, however, is that during the generation of the startup
module, we iterate over all other modules. In 2011, the
getVersionHash method (then: getModifiedTime) was fairly simple
and unlikely to throw errors.
Nowadays, some modules use enableModuleContentVersion which will
involve the same code path as for regular module responses.
The try/catch in ResourceLoader::makeModuleResponse() suffices
for the case of loading modules other than startup. But when
loading the startup module, and an exception happens in getVersionHash,
then the entire startup response is replaced with an exception comment.
Example case:
* A file not existing for a FileModule subclass that uses
enableModuleContentVersion.
* A database error from a data module, like CiteDataModule or
CNChoiceData.
Changes:
* Ensure E-Tag is still useful while an error happens in production
because we respond with 200 OK and one error isn't the same as
another.
Fixed by try/catch in getCombinedVersion.
* Ensure start manifest isn't disrupted by one broken module.
Fixed by try/catch in StartupModule::getModuleRegistrations().
Tests:
* testMakeModuleResponseError: The case that already worked fined.
* testMakeModuleResponseStartupError: The case fixed in this commit.
* testGetCombinedVersion: The case fixed in this commit for E-Tag.
Bug: T152266
Change-Id: Ice4ede5ea594bf3fa591134bc9382bd9c24e2f39
2016-12-03 00:48:14 +00:00
|
|
|
'LoadScript' => '/w/load.php',
|
2016-08-29 23:35:55 +00:00
|
|
|
] ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testEmpty() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [] ) );
|
|
|
|
|
|
|
|
|
|
// Request parameters
|
|
|
|
|
$this->assertEquals( [], $ctx->getModules() );
|
2019-04-11 22:17:00 +00:00
|
|
|
$this->assertEquals( 'qqx', $ctx->getLanguage() );
|
2020-05-22 02:01:42 +00:00
|
|
|
$this->assertSame( 0, $ctx->getDebug() );
|
2019-09-17 14:03:28 +00:00
|
|
|
$this->assertNull( $ctx->getOnly() );
|
2016-08-29 23:35:55 +00:00
|
|
|
$this->assertEquals( 'fallback', $ctx->getSkin() );
|
2019-09-17 14:03:28 +00:00
|
|
|
$this->assertNull( $ctx->getUser() );
|
2017-02-28 20:52:17 +00:00
|
|
|
$this->assertNull( $ctx->getContentOverrideCallback() );
|
2016-08-29 23:35:55 +00:00
|
|
|
|
|
|
|
|
// Misc
|
|
|
|
|
$this->assertEquals( 'ltr', $ctx->getDirection() );
|
2020-05-22 02:01:42 +00:00
|
|
|
$this->assertEquals( 'qqx|fallback|0|||||||', $ctx->getHash() );
|
2019-08-25 18:01:48 +00:00
|
|
|
$this->assertSame( [], $ctx->getReqBase() );
|
2016-08-29 23:35:55 +00:00
|
|
|
$this->assertInstanceOf( User::class, $ctx->getUserObj() );
|
2021-10-26 20:34:00 +00:00
|
|
|
$this->assertNull( $ctx->getUserIdentity() );
|
2016-08-29 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testDummy() {
|
|
|
|
|
$this->assertInstanceOf(
|
|
|
|
|
ResourceLoaderContext::class,
|
|
|
|
|
ResourceLoaderContext::newDummyContext()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAccessors() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [] ) );
|
2019-04-11 22:22:08 +00:00
|
|
|
$this->assertInstanceOf( ResourceLoader::class, $ctx->getResourceLoader() );
|
2016-08-29 23:35:55 +00:00
|
|
|
$this->assertInstanceOf( WebRequest::class, $ctx->getRequest() );
|
2019-04-11 22:22:08 +00:00
|
|
|
$this->assertInstanceOf( Psr\Log\LoggerInterface::class, $ctx->getLogger() );
|
2016-08-29 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testTypicalRequest() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [
|
|
|
|
|
'debug' => 'false',
|
|
|
|
|
'lang' => 'zh',
|
|
|
|
|
'modules' => 'foo|foo.quux,baz,bar|baz.quux',
|
|
|
|
|
'only' => 'styles',
|
|
|
|
|
'skin' => 'fallback',
|
|
|
|
|
] ) );
|
|
|
|
|
|
|
|
|
|
// Request parameters
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
$ctx->getModules(),
|
|
|
|
|
[ 'foo', 'foo.quux', 'foo.baz', 'foo.bar', 'baz.quux' ]
|
|
|
|
|
);
|
2020-05-22 02:01:42 +00:00
|
|
|
$this->assertSame( 0, $ctx->getDebug() );
|
2016-08-29 23:35:55 +00:00
|
|
|
$this->assertEquals( 'zh', $ctx->getLanguage() );
|
|
|
|
|
$this->assertEquals( 'styles', $ctx->getOnly() );
|
|
|
|
|
$this->assertEquals( 'fallback', $ctx->getSkin() );
|
2019-09-17 14:03:28 +00:00
|
|
|
$this->assertNull( $ctx->getUser() );
|
2016-08-29 23:35:55 +00:00
|
|
|
|
|
|
|
|
// Misc
|
|
|
|
|
$this->assertEquals( 'ltr', $ctx->getDirection() );
|
2020-05-22 02:01:42 +00:00
|
|
|
$this->assertEquals( 'zh|fallback|0||styles|||||', $ctx->getHash() );
|
2019-08-25 18:01:48 +00:00
|
|
|
$this->assertSame( [ 'lang' => 'zh' ], $ctx->getReqBase() );
|
2016-08-29 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
2019-06-11 19:54:57 +00:00
|
|
|
public static function provideDirection() {
|
|
|
|
|
yield 'LTR language' => [
|
|
|
|
|
[ 'lang' => 'en' ],
|
|
|
|
|
'ltr',
|
|
|
|
|
];
|
|
|
|
|
yield 'RTL language' => [
|
|
|
|
|
[ 'lang' => 'he' ],
|
|
|
|
|
'rtl',
|
|
|
|
|
];
|
|
|
|
|
yield 'explicit LTR' => [
|
|
|
|
|
[ 'lang' => 'he', 'dir' => 'ltr' ],
|
|
|
|
|
'ltr',
|
|
|
|
|
];
|
|
|
|
|
yield 'explicit RTL' => [
|
|
|
|
|
[ 'lang' => 'en', 'dir' => 'rtl' ],
|
|
|
|
|
'rtl',
|
|
|
|
|
];
|
|
|
|
|
// Not supported, but tested to cover the case and detect change
|
|
|
|
|
yield 'invalid dir' => [
|
|
|
|
|
[ 'lang' => 'he', 'dir' => 'xyz' ],
|
|
|
|
|
'rtl',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @dataProvider provideDirection
|
|
|
|
|
*/
|
|
|
|
|
public function testDirection( array $params, $expected ) {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( $params ) );
|
|
|
|
|
$this->assertEquals( $expected, $ctx->getDirection() );
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-29 23:35:55 +00:00
|
|
|
public function testShouldInclude() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [] ) );
|
|
|
|
|
$this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in combined' );
|
|
|
|
|
$this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in combined' );
|
|
|
|
|
$this->assertTrue( $ctx->shouldIncludeMessages(), 'Messages in combined' );
|
|
|
|
|
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [
|
|
|
|
|
'only' => 'styles'
|
|
|
|
|
] ) );
|
|
|
|
|
$this->assertFalse( $ctx->shouldIncludeScripts(), 'Scripts not in styles-only' );
|
|
|
|
|
$this->assertTrue( $ctx->shouldIncludeStyles(), 'Styles in styles-only' );
|
|
|
|
|
$this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in styles-only' );
|
|
|
|
|
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [
|
|
|
|
|
'only' => 'scripts'
|
|
|
|
|
] ) );
|
|
|
|
|
$this->assertTrue( $ctx->shouldIncludeScripts(), 'Scripts in scripts-only' );
|
|
|
|
|
$this->assertFalse( $ctx->shouldIncludeStyles(), 'Styles not in scripts-only' );
|
|
|
|
|
$this->assertFalse( $ctx->shouldIncludeMessages(), 'Messages not in scripts-only' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGetUser() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [] ) );
|
|
|
|
|
$this->assertSame( null, $ctx->getUser() );
|
2021-10-23 19:27:44 +00:00
|
|
|
$this->assertFalse( $ctx->getUserObj()->isRegistered() );
|
2021-10-26 20:34:00 +00:00
|
|
|
$this->assertNull( $ctx->getUserIdentity() );
|
2016-08-29 23:35:55 +00:00
|
|
|
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [
|
|
|
|
|
'user' => 'Example'
|
|
|
|
|
] ) );
|
|
|
|
|
$this->assertSame( 'Example', $ctx->getUser() );
|
|
|
|
|
$this->assertEquals( 'Example', $ctx->getUserObj()->getName() );
|
2021-10-26 20:34:00 +00:00
|
|
|
$this->assertEquals( 'Example', $ctx->getUserIdentity()->getName() );
|
2016-08-29 23:35:55 +00:00
|
|
|
}
|
2016-12-02 04:47:05 +00:00
|
|
|
|
|
|
|
|
public function testMsg() {
|
|
|
|
|
$ctx = new ResourceLoaderContext( $this->getResourceLoader(), new FauxRequest( [
|
|
|
|
|
'lang' => 'en'
|
|
|
|
|
] ) );
|
|
|
|
|
$msg = $ctx->msg( 'mainpage' );
|
|
|
|
|
$this->assertInstanceOf( Message::class, $msg );
|
|
|
|
|
$this->assertSame( 'Main Page', $msg->useDatabase( false )->plain() );
|
|
|
|
|
}
|
2016-08-29 23:35:55 +00:00
|
|
|
}
|