2012-10-24 14:32:46 +00:00
|
|
|
<?php
|
|
|
|
|
|
context: Add a cached RequestContext::getActionName method
This method is dependent on, and inherently must depend on, all of
Title, WikiPage, and WebRequest. And, like Title and WikiPage,
which also have getters in RequestContext, Action is also derived
from a query parameter that is widely recognised in almost all
web requests to index.php.
The status quo in core and extensions, is to obtain this value
via Action::getActionName(), which as a static method that bypasses
dependency injection and also has the problem of not being cached.
Caching it within ActionFactory seems hard and awkward, due to
varying by context.
In change I61d66211bd (22f9a32853f) a cached wrapper method was added
internally to the Skin class. In change I8cbc4bba4d248d9 (235820d631)
another cached wrapper was added in the Gadgets extension.
This change takes this approach further by making it a stable public
method on RequestContext.
To facilitate testing and to offer basic confidence in this working
correctly, this commit also adopts the new method in two place that
are considered "safe" (Skin, and OutputPage). Both of these are
called relatively late in the PHP proccess and well after any Setup
code and overrides (such as in MediaWiki.php), during which it is
more complex to call this. I'll audit and update those in a subsequent
change.
Change-Id: I1e259b54dca48a32be5a8c6cbb8eb69aec2da115
2021-11-06 00:28:23 +00:00
|
|
|
use MediaWiki\Actions\ActionFactory;
|
2021-01-08 01:01:28 +00:00
|
|
|
use MediaWiki\Permissions\UltimateAuthority;
|
2022-10-28 10:04:25 +00:00
|
|
|
use MediaWiki\Request\FauxRequest;
|
2021-01-08 01:01:28 +00:00
|
|
|
use MediaWiki\User\UserIdentityValue;
|
|
|
|
|
|
2013-03-14 22:43:42 +00:00
|
|
|
/**
|
context: Add a cached RequestContext::getActionName method
This method is dependent on, and inherently must depend on, all of
Title, WikiPage, and WebRequest. And, like Title and WikiPage,
which also have getters in RequestContext, Action is also derived
from a query parameter that is widely recognised in almost all
web requests to index.php.
The status quo in core and extensions, is to obtain this value
via Action::getActionName(), which as a static method that bypasses
dependency injection and also has the problem of not being cached.
Caching it within ActionFactory seems hard and awkward, due to
varying by context.
In change I61d66211bd (22f9a32853f) a cached wrapper method was added
internally to the Skin class. In change I8cbc4bba4d248d9 (235820d631)
another cached wrapper was added in the Gadgets extension.
This change takes this approach further by making it a stable public
method on RequestContext.
To facilitate testing and to offer basic confidence in this working
correctly, this commit also adopts the new method in two place that
are considered "safe" (Skin, and OutputPage). Both of these are
called relatively late in the PHP proccess and well after any Setup
code and overrides (such as in MediaWiki.php), during which it is
more complex to call this. I'll audit and update those in a subsequent
change.
Change-Id: I1e259b54dca48a32be5a8c6cbb8eb69aec2da115
2021-11-06 00:28:23 +00:00
|
|
|
* @covers RequestContext
|
2013-03-14 22:43:42 +00:00
|
|
|
* @group Database
|
2014-06-27 21:18:07 +00:00
|
|
|
* @group RequestContext
|
2013-03-14 22:43:42 +00:00
|
|
|
*/
|
2020-06-30 15:09:24 +00:00
|
|
|
class RequestContextTest extends MediaWikiIntegrationTestCase {
|
2012-10-24 14:32:46 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test the relationship between title and wikipage in RequestContext
|
2013-10-21 21:09:13 +00:00
|
|
|
* @covers RequestContext::getWikiPage
|
|
|
|
|
* @covers RequestContext::getTitle
|
2012-10-24 14:32:46 +00:00
|
|
|
*/
|
|
|
|
|
public function testWikiPageTitle() {
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
|
2022-07-05 22:21:30 +00:00
|
|
|
$curTitle = Title::makeTitle( NS_MAIN, "A" );
|
2012-10-24 14:32:46 +00:00
|
|
|
$context->setTitle( $curTitle );
|
2021-12-14 20:34:46 +00:00
|
|
|
$this->assertTrue( $curTitle->equals( $context->getWikiPage()->getTitle() ),
|
2012-10-24 14:32:46 +00:00
|
|
|
"When a title is first set WikiPage should be created on-demand for that title." );
|
|
|
|
|
|
2022-07-05 22:21:30 +00:00
|
|
|
$curTitle = Title::makeTitle( NS_MAIN, "B" );
|
2022-09-01 21:18:41 +00:00
|
|
|
$context->setWikiPage( $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $curTitle ) );
|
2012-10-24 14:32:46 +00:00
|
|
|
$this->assertTrue( $curTitle->equals( $context->getTitle() ),
|
|
|
|
|
"Title must be updated when a new WikiPage is provided." );
|
|
|
|
|
|
2022-07-05 22:21:30 +00:00
|
|
|
$curTitle = Title::makeTitle( NS_MAIN, "C" );
|
2012-10-24 14:32:46 +00:00
|
|
|
$context->setTitle( $curTitle );
|
2014-04-24 12:35:05 +00:00
|
|
|
$this->assertTrue(
|
2021-12-14 20:34:46 +00:00
|
|
|
$curTitle->equals( $context->getWikiPage()->getTitle() ),
|
2014-04-24 12:35:05 +00:00
|
|
|
"When a title is updated the WikiPage should be purged "
|
|
|
|
|
. "and recreated on-demand with the new title."
|
|
|
|
|
);
|
2012-10-24 14:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-21 21:09:13 +00:00
|
|
|
/**
|
|
|
|
|
* @covers RequestContext::importScopedSession
|
|
|
|
|
*/
|
2013-03-14 22:43:42 +00:00
|
|
|
public function testImportScopedSession() {
|
2016-02-01 20:44:03 +00:00
|
|
|
// Make sure session handling is started
|
|
|
|
|
if ( !MediaWiki\Session\PHPSessionHandler::isInstalled() ) {
|
|
|
|
|
MediaWiki\Session\PHPSessionHandler::install(
|
|
|
|
|
MediaWiki\Session\SessionManager::singleton()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
$oldSessionId = session_id();
|
|
|
|
|
|
2013-03-14 22:43:42 +00:00
|
|
|
$context = RequestContext::getMain();
|
|
|
|
|
|
|
|
|
|
$oInfo = $context->exportSession();
|
|
|
|
|
$this->assertEquals( '127.0.0.1', $oInfo['ip'], "Correct initial IP address." );
|
2019-09-17 14:31:49 +00:00
|
|
|
$this->assertSame( 0, $oInfo['userId'], "Correct initial user ID." );
|
2016-02-01 20:44:03 +00:00
|
|
|
$this->assertFalse( MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent(),
|
|
|
|
|
'Global session isn\'t persistent to start' );
|
2013-03-14 22:43:42 +00:00
|
|
|
|
|
|
|
|
$user = User::newFromName( 'UnitTestContextUser' );
|
|
|
|
|
$user->addToDatabase();
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$sinfo = [
|
2013-03-14 22:43:42 +00:00
|
|
|
'sessionId' => 'd612ee607c87e749ef14da4983a702cd',
|
|
|
|
|
'userId' => $user->getId(),
|
|
|
|
|
'ip' => '192.0.2.0',
|
2016-02-17 09:09:32 +00:00
|
|
|
'headers' => [
|
2014-04-24 12:35:05 +00:00
|
|
|
'USER-AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:18.0) Gecko/20100101 Firefox/18.0'
|
2016-02-17 09:09:32 +00:00
|
|
|
]
|
|
|
|
|
];
|
2014-06-27 21:18:07 +00:00
|
|
|
// importScopedSession() sets these variables
|
2016-02-17 09:09:32 +00:00
|
|
|
$this->setMwGlobals( [
|
2014-06-27 21:18:07 +00:00
|
|
|
'wgRequest' => new FauxRequest,
|
2016-02-17 09:09:32 +00:00
|
|
|
] );
|
2013-03-14 22:43:42 +00:00
|
|
|
$sc = RequestContext::importScopedSession( $sinfo ); // load new context
|
|
|
|
|
|
|
|
|
|
$info = $context->exportSession();
|
|
|
|
|
$this->assertEquals( $sinfo['ip'], $info['ip'], "Correct IP address." );
|
|
|
|
|
$this->assertEquals( $sinfo['headers'], $info['headers'], "Correct headers." );
|
|
|
|
|
$this->assertEquals( $sinfo['sessionId'], $info['sessionId'], "Correct session ID." );
|
|
|
|
|
$this->assertEquals( $sinfo['userId'], $info['userId'], "Correct user ID." );
|
2014-04-24 12:35:05 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
$sinfo['ip'],
|
|
|
|
|
$context->getRequest()->getIP(),
|
|
|
|
|
"Correct context IP address."
|
|
|
|
|
);
|
|
|
|
|
$this->assertEquals(
|
|
|
|
|
$sinfo['headers'],
|
|
|
|
|
$context->getRequest()->getAllHeaders(),
|
|
|
|
|
"Correct context headers."
|
|
|
|
|
);
|
2016-02-01 20:44:03 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
$sinfo['sessionId'],
|
|
|
|
|
MediaWiki\Session\SessionManager::getGlobalSession()->getId(),
|
|
|
|
|
"Correct context session ID."
|
|
|
|
|
);
|
2016-03-18 13:55:54 +00:00
|
|
|
if ( \MediaWiki\Session\PHPSessionHandler::isEnabled() ) {
|
2016-02-01 20:44:03 +00:00
|
|
|
$this->assertEquals( $sinfo['sessionId'], session_id(), "Correct context session ID." );
|
|
|
|
|
} else {
|
|
|
|
|
$this->assertEquals( $oldSessionId, session_id(), "Unchanged PHP session ID." );
|
|
|
|
|
}
|
2020-12-17 23:10:11 +00:00
|
|
|
$this->assertTrue( $context->getUser()->isRegistered(), "Correct context user." );
|
2013-03-14 22:43:42 +00:00
|
|
|
$this->assertEquals( $sinfo['userId'], $context->getUser()->getId(), "Correct context user ID." );
|
2014-04-24 12:35:05 +00:00
|
|
|
$this->assertEquals(
|
|
|
|
|
'UnitTestContextUser',
|
|
|
|
|
$context->getUser()->getName(),
|
|
|
|
|
"Correct context user name."
|
|
|
|
|
);
|
2013-03-14 22:43:42 +00:00
|
|
|
|
2013-04-26 14:42:31 +00:00
|
|
|
unset( $sc ); // restore previous context
|
2013-03-14 22:43:42 +00:00
|
|
|
|
|
|
|
|
$info = $context->exportSession();
|
2014-10-15 01:45:51 +00:00
|
|
|
$this->assertEquals( $oInfo['ip'], $info['ip'], "Correct restored IP address." );
|
|
|
|
|
$this->assertEquals( $oInfo['headers'], $info['headers'], "Correct restored headers." );
|
|
|
|
|
$this->assertEquals( $oInfo['sessionId'], $info['sessionId'], "Correct restored session ID." );
|
|
|
|
|
$this->assertEquals( $oInfo['userId'], $info['userId'], "Correct restored user ID." );
|
2016-02-01 20:44:03 +00:00
|
|
|
$this->assertFalse( MediaWiki\Session\SessionManager::getGlobalSession()->isPersistent(),
|
|
|
|
|
'Global session isn\'t persistent after restoring the context' );
|
2013-03-14 22:43:42 +00:00
|
|
|
}
|
2021-01-08 01:01:28 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RequestContext::getUser
|
|
|
|
|
* @covers RequestContext::setUser
|
|
|
|
|
* @covers RequestContext::getAuthority
|
|
|
|
|
* @covers RequestContext::setAuthority
|
|
|
|
|
*/
|
|
|
|
|
public function testTestGetSetAuthority() {
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
|
|
|
|
|
$user = $this->getTestUser()->getUser();
|
|
|
|
|
|
|
|
|
|
$context->setUser( $user );
|
2021-03-04 19:45:28 +00:00
|
|
|
$this->assertTrue( $user->equals( $context->getAuthority()->getUser() ) );
|
2021-01-08 01:01:28 +00:00
|
|
|
$this->assertTrue( $user->equals( $context->getUser() ) );
|
|
|
|
|
|
2021-02-15 18:58:09 +00:00
|
|
|
$authorityActor = new UserIdentityValue( 42, 'Test' );
|
2021-01-08 01:01:28 +00:00
|
|
|
$authority = new UltimateAuthority( $authorityActor );
|
|
|
|
|
|
|
|
|
|
$context->setAuthority( $authority );
|
|
|
|
|
$this->assertTrue( $context->getUser()->equals( $authorityActor ) );
|
2021-03-04 19:45:28 +00:00
|
|
|
$this->assertTrue( $context->getAuthority()->getUser()->equals( $authorityActor ) );
|
2021-01-08 01:01:28 +00:00
|
|
|
}
|
context: Add a cached RequestContext::getActionName method
This method is dependent on, and inherently must depend on, all of
Title, WikiPage, and WebRequest. And, like Title and WikiPage,
which also have getters in RequestContext, Action is also derived
from a query parameter that is widely recognised in almost all
web requests to index.php.
The status quo in core and extensions, is to obtain this value
via Action::getActionName(), which as a static method that bypasses
dependency injection and also has the problem of not being cached.
Caching it within ActionFactory seems hard and awkward, due to
varying by context.
In change I61d66211bd (22f9a32853f) a cached wrapper method was added
internally to the Skin class. In change I8cbc4bba4d248d9 (235820d631)
another cached wrapper was added in the Gadgets extension.
This change takes this approach further by making it a stable public
method on RequestContext.
To facilitate testing and to offer basic confidence in this working
correctly, this commit also adopts the new method in two place that
are considered "safe" (Skin, and OutputPage). Both of these are
called relatively late in the PHP proccess and well after any Setup
code and overrides (such as in MediaWiki.php), during which it is
more complex to call this. I'll audit and update those in a subsequent
change.
Change-Id: I1e259b54dca48a32be5a8c6cbb8eb69aec2da115
2021-11-06 00:28:23 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RequestContext
|
|
|
|
|
*/
|
|
|
|
|
public function testGetActionName() {
|
|
|
|
|
$factory = $this->createMock( ActionFactory::class );
|
|
|
|
|
$factory
|
|
|
|
|
// Assert calling only once.
|
|
|
|
|
// Determining the action name is an expensive operation that
|
|
|
|
|
// must be cached by the context, as it involved database and hooks.
|
|
|
|
|
->expects( $this->once() )
|
|
|
|
|
->method( 'getActionName' )
|
|
|
|
|
->willReturn( 'foo' );
|
|
|
|
|
$this->setService( 'ActionFactory', $factory );
|
|
|
|
|
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$this->assertSame( 'foo', $context->getActionName(), 'value from factory' );
|
|
|
|
|
$this->assertSame( 'foo', $context->getActionName(), 'cached' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RequestContext
|
|
|
|
|
*/
|
|
|
|
|
public function testSetActionName() {
|
|
|
|
|
$factory = $this->createMock( ActionFactory::class );
|
|
|
|
|
$factory
|
|
|
|
|
->expects( $this->never() )
|
|
|
|
|
->method( 'getActionName' );
|
|
|
|
|
$this->setService( 'ActionFactory', $factory );
|
|
|
|
|
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$context->setActionName( 'fixed' );
|
|
|
|
|
$this->assertSame( 'fixed', $context->getActionName() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @covers RequestContext
|
|
|
|
|
*/
|
|
|
|
|
public function testOverideActionName() {
|
|
|
|
|
$factory = $this->createMock( ActionFactory::class );
|
|
|
|
|
$factory
|
|
|
|
|
->method( 'getActionName' )
|
|
|
|
|
->willReturnOnConsecutiveCalls( 'aaa', 'bbb' );
|
|
|
|
|
$this->setService( 'ActionFactory', $factory );
|
|
|
|
|
|
|
|
|
|
$context = new RequestContext();
|
|
|
|
|
$this->assertSame( 'aaa', $context->getActionName(), 'first from factory' );
|
|
|
|
|
$this->assertSame( 'aaa', $context->getActionName(), 'cached first' );
|
|
|
|
|
|
2022-09-26 16:58:05 +00:00
|
|
|
// Ignore warning from clearActionName
|
|
|
|
|
@$context->setTitle( $this->createMock( Title::class ) );
|
context: Add a cached RequestContext::getActionName method
This method is dependent on, and inherently must depend on, all of
Title, WikiPage, and WebRequest. And, like Title and WikiPage,
which also have getters in RequestContext, Action is also derived
from a query parameter that is widely recognised in almost all
web requests to index.php.
The status quo in core and extensions, is to obtain this value
via Action::getActionName(), which as a static method that bypasses
dependency injection and also has the problem of not being cached.
Caching it within ActionFactory seems hard and awkward, due to
varying by context.
In change I61d66211bd (22f9a32853f) a cached wrapper method was added
internally to the Skin class. In change I8cbc4bba4d248d9 (235820d631)
another cached wrapper was added in the Gadgets extension.
This change takes this approach further by making it a stable public
method on RequestContext.
To facilitate testing and to offer basic confidence in this working
correctly, this commit also adopts the new method in two place that
are considered "safe" (Skin, and OutputPage). Both of these are
called relatively late in the PHP proccess and well after any Setup
code and overrides (such as in MediaWiki.php), during which it is
more complex to call this. I'll audit and update those in a subsequent
change.
Change-Id: I1e259b54dca48a32be5a8c6cbb8eb69aec2da115
2021-11-06 00:28:23 +00:00
|
|
|
$this->assertSame( 'bbb', $context->getActionName(), 'second from factory' );
|
|
|
|
|
$this->assertSame( 'bbb', $context->getActionName(), 'cached second' );
|
|
|
|
|
}
|
2012-10-24 14:32:46 +00:00
|
|
|
}
|