Unit tests should never access the global service locator, as that's a pretty evident sign that the test isn't testing something in isolation. HttpRequestFactoryTest fails with this restriction, because it uses the UrlUtils service for parsing URLs. Make it an integration test and add a TODO about injecting UrlUtils. Bug: T227900 Change-Id: I5117eab95f57297eb02bed0a964c32d887de3226
269 lines
7.2 KiB
PHP
269 lines
7.2 KiB
PHP
<?php
|
|
|
|
use MediaWiki\Config\ServiceOptions;
|
|
use MediaWiki\Http\HttpRequestFactory;
|
|
use MediaWiki\MainConfigNames;
|
|
use Psr\Log\NullLogger;
|
|
use Wikimedia\TestingAccessWrapper;
|
|
|
|
/**
|
|
* @covers MediaWiki\Http\HttpRequestFactory
|
|
* @todo Inject UrlUtils into MWHttpRequest and make this a unit test.
|
|
*/
|
|
class HttpRequestFactoryTest extends MediaWikiIntegrationTestCase {
|
|
|
|
/**
|
|
* @param array|null $options
|
|
* @return HttpRequestFactory
|
|
*/
|
|
private function newFactory( $options = null ) {
|
|
if ( !$options ) {
|
|
$options = [
|
|
MainConfigNames::HTTPTimeout => 1,
|
|
MainConfigNames::HTTPConnectTimeout => 1,
|
|
MainConfigNames::HTTPMaxTimeout => INF,
|
|
MainConfigNames::HTTPMaxConnectTimeout => INF
|
|
];
|
|
}
|
|
$options += [
|
|
MainConfigNames::LocalVirtualHosts => [],
|
|
MainConfigNames::LocalHTTPProxy => false,
|
|
];
|
|
return new HttpRequestFactory(
|
|
new ServiceOptions( HttpRequestFactory::CONSTRUCTOR_OPTIONS, $options ),
|
|
new NullLogger
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param MWHttpRequest $req
|
|
* @param string $expectedUrl
|
|
* @param array $expectedOptions
|
|
* @return HttpRequestFactory
|
|
*/
|
|
private function newFactoryWithFakeRequest(
|
|
MWHttpRequest $req,
|
|
$expectedUrl,
|
|
$expectedOptions = []
|
|
) {
|
|
$factory = $this->getMockBuilder( HttpRequestFactory::class )
|
|
->onlyMethods( [ 'create' ] )
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
|
|
$factory->method( 'create' )
|
|
->willReturnCallback(
|
|
function ( $url, array $options = [], $caller = __METHOD__ )
|
|
use ( $req, $expectedUrl, $expectedOptions )
|
|
{
|
|
$this->assertSame( $expectedUrl, $url );
|
|
|
|
foreach ( $expectedOptions as $opt => $exp ) {
|
|
$this->assertArrayHasKey( $opt, $options );
|
|
$this->assertSame( $exp, $options[$opt] );
|
|
}
|
|
|
|
return $req;
|
|
}
|
|
);
|
|
|
|
return $factory;
|
|
}
|
|
|
|
/**
|
|
* @param Status|string $result
|
|
* @return MWHttpRequest
|
|
*/
|
|
private function newFakeRequest( $result ) {
|
|
if ( !( $result instanceof Status ) ) {
|
|
$result = Status::newGood( $result );
|
|
}
|
|
|
|
$req = $this->getMockBuilder( MWHttpRequest::class )
|
|
->disableOriginalConstructor()
|
|
->onlyMethods( [ 'getContent', 'execute' ] )
|
|
->getMock();
|
|
|
|
$req->method( 'getContent' )
|
|
->willReturn( $result->getValue() );
|
|
$req->method( 'execute' )
|
|
->willReturn( $result );
|
|
|
|
return $req;
|
|
}
|
|
|
|
public function testCreate() {
|
|
$factory = $this->newFactory();
|
|
$this->assertInstanceOf( MWHttpRequest::class, $factory->create( 'http://example.test' ) );
|
|
}
|
|
|
|
public function testGetUserAgent() {
|
|
$factory = $this->newFactory();
|
|
$this->assertStringStartsWith( 'MediaWiki/', $factory->getUserAgent() );
|
|
}
|
|
|
|
public function testGet() {
|
|
$req = $this->newFakeRequest( __METHOD__ );
|
|
$factory = $this->newFactoryWithFakeRequest(
|
|
$req, 'https://example.test', [ 'method' => 'GET' ]
|
|
);
|
|
|
|
$this->assertSame( __METHOD__, $factory->get( 'https://example.test' ) );
|
|
}
|
|
|
|
public function testPost() {
|
|
$req = $this->newFakeRequest( __METHOD__ );
|
|
$factory = $this->newFactoryWithFakeRequest(
|
|
$req, 'https://example.test', [ 'method' => 'POST' ]
|
|
);
|
|
|
|
$this->assertSame( __METHOD__, $factory->post( 'https://example.test' ) );
|
|
}
|
|
|
|
public function testRequest() {
|
|
$req = $this->newFakeRequest( __METHOD__ );
|
|
$factory = $this->newFactoryWithFakeRequest(
|
|
$req, 'https://example.test', [ 'method' => 'GET' ]
|
|
);
|
|
|
|
$this->assertSame( __METHOD__, $factory->request( 'GET', 'https://example.test' ) );
|
|
}
|
|
|
|
public function testRequest_failed() {
|
|
$status = new class extends Status {
|
|
public function getWikiText( $shortContext = false, $longContext = false, $lang = null ) {
|
|
// Status::getWikiText doesn't work in unit tests
|
|
return '';
|
|
}
|
|
};
|
|
$status->fatal( 'testing' );
|
|
|
|
$req = $this->newFakeRequest( $status );
|
|
$factory = $this->newFactoryWithFakeRequest(
|
|
$req, 'https://example.test', [ 'method' => 'POST' ]
|
|
);
|
|
|
|
$this->assertNull( $factory->request( 'POST', 'https://example.test' ) );
|
|
}
|
|
|
|
public static function provideCreateTimeouts() {
|
|
return [
|
|
'normal config defaults' => [
|
|
[
|
|
MainConfigNames::HTTPTimeout => 10,
|
|
MainConfigNames::HTTPConnectTimeout => 20,
|
|
MainConfigNames::HTTPMaxTimeout => INF,
|
|
MainConfigNames::HTTPMaxConnectTimeout => INF
|
|
],
|
|
[],
|
|
[
|
|
'timeout' => 10,
|
|
'connectTimeout' => 20
|
|
]
|
|
],
|
|
'config defaults overridden by max' => [
|
|
[
|
|
MainConfigNames::HTTPTimeout => 10,
|
|
MainConfigNames::HTTPConnectTimeout => 20,
|
|
MainConfigNames::HTTPMaxTimeout => 9,
|
|
MainConfigNames::HTTPMaxConnectTimeout => 11
|
|
],
|
|
[],
|
|
[
|
|
'timeout' => 9,
|
|
'connectTimeout' => 11
|
|
]
|
|
],
|
|
'create option overridden by max config' => [
|
|
[
|
|
MainConfigNames::HTTPTimeout => 1,
|
|
MainConfigNames::HTTPConnectTimeout => 2,
|
|
MainConfigNames::HTTPMaxTimeout => 9,
|
|
MainConfigNames::HTTPMaxConnectTimeout => 11
|
|
],
|
|
[
|
|
'timeout' => 100,
|
|
'connectTimeout' => 200
|
|
],
|
|
[
|
|
'timeout' => 9,
|
|
'connectTimeout' => 11
|
|
]
|
|
],
|
|
'create option below max config' => [
|
|
[
|
|
MainConfigNames::HTTPTimeout => 1,
|
|
MainConfigNames::HTTPConnectTimeout => 2,
|
|
MainConfigNames::HTTPMaxTimeout => 9,
|
|
MainConfigNames::HTTPMaxConnectTimeout => 11
|
|
],
|
|
[
|
|
'timeout' => 7,
|
|
'connectTimeout' => 8
|
|
],
|
|
[
|
|
'timeout' => 7,
|
|
'connectTimeout' => 8
|
|
]
|
|
],
|
|
'max config overridden by max create option ' => [
|
|
[
|
|
MainConfigNames::HTTPTimeout => 1,
|
|
MainConfigNames::HTTPConnectTimeout => 2,
|
|
MainConfigNames::HTTPMaxTimeout => 9,
|
|
MainConfigNames::HTTPMaxConnectTimeout => 11
|
|
],
|
|
[
|
|
'timeout' => 100,
|
|
'connectTimeout' => 200,
|
|
'maxTimeout' => 100,
|
|
'maxConnectTimeout' => 200
|
|
],
|
|
[
|
|
'timeout' => 100,
|
|
'connectTimeout' => 200
|
|
]
|
|
],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider provideCreateTimeouts */
|
|
public function testCreateTimeouts( $config, $createOptions, $expected ) {
|
|
$factory = $this->newFactory( $config );
|
|
$request = $factory->create( 'https://example.test', $createOptions );
|
|
$request = TestingAccessWrapper::newFromObject( $request );
|
|
foreach ( $expected as $key => $expectedValue ) {
|
|
$this->assertEquals( $expectedValue, $request->$key, "key $key" );
|
|
}
|
|
}
|
|
|
|
/** @dataProvider provideCreateTimeouts */
|
|
public function testCreateMultiTimeouts( $config, $createOptions, $expected ) {
|
|
$factory = $this->newFactory( $config );
|
|
$multi = $factory->createMultiClient( $createOptions );
|
|
$multi = TestingAccessWrapper::newFromObject( $multi );
|
|
$this->assertEquals( $expected['connectTimeout'], $multi->connTimeout );
|
|
$this->assertEquals( $expected['timeout'], $multi->reqTimeout );
|
|
}
|
|
|
|
/** @dataProvider provideCreateTimeouts */
|
|
public function testCreateGuzzleClient( $config, $createOptions, $expected ) {
|
|
$factory = $this->newFactory( $config );
|
|
$client = $factory->createGuzzleClient(
|
|
[
|
|
'timeout' => $createOptions['timeout'] ?? null,
|
|
'connect_timeout' => $createOptions['connectTimeout'] ?? null,
|
|
'maxTimeout' => $createOptions['maxTimeout'] ?? null,
|
|
'maxConnectTimeout' => $createOptions['maxConnectTimeout'] ?? null
|
|
]
|
|
);
|
|
$this->assertEquals(
|
|
$expected['connectTimeout'],
|
|
$client->getConfig( 'connect_timeout' )
|
|
);
|
|
$this->assertEquals(
|
|
$expected['timeout'],
|
|
$client->getConfig( 'timeout' )
|
|
);
|
|
}
|
|
}
|