mirror of
https://github.com/guzzle/guzzle.git
synced 2025-02-24 10:03:27 +01:00
619 lines
20 KiB
PHP
619 lines
20 KiB
PHP
<?php
|
|
namespace GuzzleHttp\Tests;
|
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Event\BeforeEvent;
|
|
use GuzzleHttp\Event\ErrorEvent;
|
|
use GuzzleHttp\Exception\CancelledRequestException;
|
|
use GuzzleHttp\Message\MessageFactory;
|
|
use GuzzleHttp\Message\Response;
|
|
use GuzzleHttp\Exception\RequestException;
|
|
use GuzzleHttp\Ring\Client\MockAdapter;
|
|
use GuzzleHttp\Ring\Future\FutureArray;
|
|
use GuzzleHttp\Subscriber\History;
|
|
use GuzzleHttp\Subscriber\Mock;
|
|
use GuzzleHttp\Event\RequestEvents;
|
|
use GuzzleHttp\Event\EndEvent;
|
|
use React\Promise\Deferred;
|
|
|
|
/**
|
|
* @covers GuzzleHttp\Client
|
|
*/
|
|
class ClientTest extends \PHPUnit_Framework_TestCase
|
|
{
|
|
/** @callable */
|
|
private $ma;
|
|
|
|
public function setup()
|
|
{
|
|
$this->ma = function () {
|
|
throw new \RuntimeException('Should not have been called.');
|
|
};
|
|
}
|
|
|
|
public function testProvidesDefaultUserAgent()
|
|
{
|
|
$ua = Client::getDefaultUserAgent();
|
|
$this->assertEquals(1, preg_match('#^Guzzle/.+ curl/.+ PHP/.+$#', $ua));
|
|
}
|
|
|
|
public function testUsesDefaultDefaultOptions()
|
|
{
|
|
$client = new Client();
|
|
$this->assertTrue($client->getDefaultOption('allow_redirects'));
|
|
$this->assertTrue($client->getDefaultOption('exceptions'));
|
|
$this->assertTrue($client->getDefaultOption('verify'));
|
|
}
|
|
|
|
public function testUsesProvidedDefaultOptions()
|
|
{
|
|
$client = new Client([
|
|
'defaults' => [
|
|
'allow_redirects' => false,
|
|
'query' => ['foo' => 'bar']
|
|
]
|
|
]);
|
|
$this->assertFalse($client->getDefaultOption('allow_redirects'));
|
|
$this->assertTrue($client->getDefaultOption('exceptions'));
|
|
$this->assertTrue($client->getDefaultOption('verify'));
|
|
$this->assertEquals(['foo' => 'bar'], $client->getDefaultOption('query'));
|
|
}
|
|
|
|
public function testCanSpecifyBaseUrl()
|
|
{
|
|
$this->assertSame('', (new Client())->getBaseUrl());
|
|
$this->assertEquals('http://foo', (new Client([
|
|
'base_url' => 'http://foo'
|
|
]))->getBaseUrl());
|
|
}
|
|
|
|
public function testCanSpecifyBaseUrlUriTemplate()
|
|
{
|
|
$client = new Client(['base_url' => ['http://foo.com/{var}/', ['var' => 'baz']]]);
|
|
$this->assertEquals('http://foo.com/baz/', $client->getBaseUrl());
|
|
}
|
|
|
|
/**
|
|
* @expectedException \Exception
|
|
* @expectedExceptionMessage Foo
|
|
*/
|
|
public function testCanSpecifyAdapter()
|
|
{
|
|
$client = new Client(['adapter' => function () {
|
|
throw new \Exception('Foo');
|
|
}]);
|
|
$client->get('http://httpbin.org');
|
|
}
|
|
|
|
/**
|
|
* @expectedException \Exception
|
|
* @expectedExceptionMessage Foo
|
|
*/
|
|
public function testCanSpecifyMessageFactory()
|
|
{
|
|
$factory = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
|
|
->setMethods(['createRequest'])
|
|
->getMockForAbstractClass();
|
|
$factory->expects($this->once())
|
|
->method('createRequest')
|
|
->will($this->throwException(new \Exception('Foo')));
|
|
$client = new Client(['message_factory' => $factory]);
|
|
$client->get();
|
|
}
|
|
|
|
public function testCanSpecifyEmitter()
|
|
{
|
|
$emitter = $this->getMockBuilder('GuzzleHttp\Event\EmitterInterface')
|
|
->setMethods(['listeners'])
|
|
->getMockForAbstractClass();
|
|
$emitter->expects($this->once())
|
|
->method('listeners')
|
|
->will($this->returnValue('foo'));
|
|
|
|
$client = new Client(['emitter' => $emitter]);
|
|
$this->assertEquals('foo', $client->getEmitter()->listeners());
|
|
}
|
|
|
|
public function testAddsDefaultUserAgentHeaderWithDefaultOptions()
|
|
{
|
|
$client = new Client(['defaults' => ['allow_redirects' => false]]);
|
|
$this->assertFalse($client->getDefaultOption('allow_redirects'));
|
|
$this->assertEquals(
|
|
['User-Agent' => Client::getDefaultUserAgent()],
|
|
$client->getDefaultOption('headers')
|
|
);
|
|
}
|
|
|
|
public function testAddsDefaultUserAgentHeaderWithoutDefaultOptions()
|
|
{
|
|
$client = new Client();
|
|
$this->assertEquals(
|
|
['User-Agent' => Client::getDefaultUserAgent()],
|
|
$client->getDefaultOption('headers')
|
|
);
|
|
}
|
|
|
|
private function getRequestClient()
|
|
{
|
|
$client = $this->getMockBuilder('GuzzleHttp\Client')
|
|
->setMethods(['send'])
|
|
->getMock();
|
|
$client->expects($this->once())
|
|
->method('send')
|
|
->will($this->returnArgument(0));
|
|
|
|
return $client;
|
|
}
|
|
|
|
public function requestMethodProvider()
|
|
{
|
|
return [
|
|
['GET', false],
|
|
['HEAD', false],
|
|
['DELETE', false],
|
|
['OPTIONS', false],
|
|
['POST', 'foo'],
|
|
['PUT', 'foo'],
|
|
['PATCH', 'foo']
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider requestMethodProvider
|
|
*/
|
|
public function testClientProvidesMethodShortcut($method, $body)
|
|
{
|
|
$client = $this->getRequestClient();
|
|
if ($body) {
|
|
$request = $client->{$method}('http://foo.com', [
|
|
'headers' => ['X-Baz' => 'Bar'],
|
|
'body' => $body,
|
|
'query' => ['a' => 'b']
|
|
]);
|
|
} else {
|
|
$request = $client->{$method}('http://foo.com', [
|
|
'headers' => ['X-Baz' => 'Bar'],
|
|
'query' => ['a' => 'b']
|
|
]);
|
|
}
|
|
$this->assertEquals($method, $request->getMethod());
|
|
$this->assertEquals('Bar', $request->getHeader('X-Baz'));
|
|
$this->assertEquals('a=b', $request->getQuery());
|
|
if ($body) {
|
|
$this->assertEquals($body, $request->getBody());
|
|
}
|
|
}
|
|
|
|
public function testClientMergesDefaultOptionsWithRequestOptions()
|
|
{
|
|
$f = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface')
|
|
->setMethods(array('createRequest'))
|
|
->getMockForAbstractClass();
|
|
|
|
$o = null;
|
|
// Intercept the creation
|
|
$f->expects($this->once())
|
|
->method('createRequest')
|
|
->will($this->returnCallback(
|
|
function ($method, $url, array $options = []) use (&$o) {
|
|
$o = $options;
|
|
return (new MessageFactory())->createRequest($method, $url, $options);
|
|
}
|
|
));
|
|
|
|
$client = new Client([
|
|
'message_factory' => $f,
|
|
'defaults' => [
|
|
'headers' => ['Foo' => 'Bar'],
|
|
'query' => ['baz' => 'bam'],
|
|
'exceptions' => false
|
|
]
|
|
]);
|
|
|
|
$request = $client->createRequest('GET', 'http://foo.com?a=b', [
|
|
'headers' => ['Hi' => 'there', '1' => 'one'],
|
|
'allow_redirects' => false,
|
|
'query' => ['t' => 1]
|
|
]);
|
|
|
|
$this->assertFalse($o['allow_redirects']);
|
|
$this->assertFalse($o['exceptions']);
|
|
$this->assertEquals('Bar', $request->getHeader('Foo'));
|
|
$this->assertEquals('there', $request->getHeader('Hi'));
|
|
$this->assertEquals('one', $request->getHeader('1'));
|
|
$this->assertEquals('a=b&baz=bam&t=1', $request->getQuery());
|
|
}
|
|
|
|
public function testClientMergesDefaultHeadersCaseInsensitively()
|
|
{
|
|
$client = new Client(['defaults' => ['headers' => ['Foo' => 'Bar']]]);
|
|
$request = $client->createRequest('GET', 'http://foo.com?a=b', [
|
|
'headers' => ['foo' => 'custom', 'user-agent' => 'test']
|
|
]);
|
|
$this->assertEquals('test', $request->getHeader('User-Agent'));
|
|
$this->assertEquals('custom', $request->getHeader('Foo'));
|
|
}
|
|
|
|
public function testDoesNotOverwriteExistingUA()
|
|
{
|
|
$client = new Client(['defaults' => [
|
|
'headers' => ['User-Agent' => 'test']
|
|
]]);
|
|
$this->assertEquals(
|
|
['User-Agent' => 'test'],
|
|
$client->getDefaultOption('headers')
|
|
);
|
|
}
|
|
|
|
public function testUsesBaseUrlWhenNoUrlIsSet()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
|
|
$this->assertEquals(
|
|
'http://www.foo.com/baz?bam=bar',
|
|
$client->createRequest('GET')->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testUsesBaseUrlCombinedWithProvidedUrl()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
|
|
$this->assertEquals(
|
|
'http://www.foo.com/bar/bam',
|
|
$client->createRequest('GET', 'bar/bam')->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testUsesBaseUrlCombinedWithProvidedUrlViaUriTemplate()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
|
|
$this->assertEquals(
|
|
'http://www.foo.com/bar/123',
|
|
$client->createRequest('GET', ['bar/{bam}', ['bam' => '123']])->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testSettingAbsoluteUrlOverridesBaseUrl()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
|
|
$this->assertEquals(
|
|
'http://www.foo.com/foo',
|
|
$client->createRequest('GET', '/foo')->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testSettingAbsoluteUriTemplateOverridesBaseUrl()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']);
|
|
$this->assertEquals(
|
|
'http://goo.com/1',
|
|
$client->createRequest(
|
|
'GET',
|
|
['http://goo.com/{bar}', ['bar' => '1']]
|
|
)->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testCanSetRelativeUrlStartingWithHttp()
|
|
{
|
|
$client = new Client(['base_url' => 'http://www.foo.com']);
|
|
$this->assertEquals(
|
|
'http://www.foo.com/httpfoo',
|
|
$client->createRequest('GET', 'httpfoo')->getUrl()
|
|
);
|
|
}
|
|
|
|
public function testClientSendsRequests()
|
|
{
|
|
$mock = new MockAdapter(['status' => 200, 'headers' => []]);
|
|
$client = new Client(['adapter' => $mock]);
|
|
$response = $client->get('http://test.com');
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$this->assertEquals('http://test.com', $response->getEffectiveUrl());
|
|
}
|
|
|
|
public function testSendingRequestCanBeIntercepted()
|
|
{
|
|
$response = new Response(200);
|
|
$client = new Client(['adapter' => $this->ma]);
|
|
$client->getEmitter()->on(
|
|
'before',
|
|
function (BeforeEvent $e) use ($response) {
|
|
$e->intercept($response);
|
|
}
|
|
);
|
|
$this->assertSame($response, $client->get('http://test.com'));
|
|
$this->assertEquals('http://test.com', $response->getEffectiveUrl());
|
|
}
|
|
|
|
/**
|
|
* @expectedException \GuzzleHttp\Exception\RequestException
|
|
* @expectedExceptionMessage Argument 1 passed to GuzzleHttp\Message\FutureResponse::proxy()
|
|
*/
|
|
public function testEnsuresResponseIsPresentAfterSending()
|
|
{
|
|
$adapter = function () {};
|
|
$client = new Client(['adapter' => $adapter]);
|
|
$client->get('http://httpbin.org');
|
|
}
|
|
|
|
/**
|
|
* @expectedException \GuzzleHttp\Exception\RequestException
|
|
* @expectedExceptionMessage Deref did not resolve future
|
|
*/
|
|
public function testEnsuresResponseIsPresentAfterDereferencing()
|
|
{
|
|
$deferred = new Deferred();
|
|
$adapter = new MockAdapter(function () use ($deferred) {
|
|
return new FutureArray(
|
|
$deferred->promise(),
|
|
function () {
|
|
return [];
|
|
}
|
|
);
|
|
});
|
|
$client = new Client(['adapter' => $adapter]);
|
|
$client->get('http://httpbin.org')->deref();
|
|
}
|
|
|
|
public function testClientHandlesErrorsDuringBeforeSend()
|
|
{
|
|
$client = new Client();
|
|
$client->getEmitter()->on('before', function ($e) {
|
|
throw new \Exception('foo');
|
|
});
|
|
$client->getEmitter()->on('error', function (ErrorEvent $e) {
|
|
$e->intercept(new Response(200));
|
|
});
|
|
$this->assertEquals(
|
|
200,
|
|
$client->get('http://test.com')->getStatusCode()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @expectedException \GuzzleHttp\Exception\RequestException
|
|
* @expectedExceptionMessage foo
|
|
*/
|
|
public function testClientHandlesErrorsDuringBeforeSendAndThrowsIfUnhandled()
|
|
{
|
|
$client = new Client();
|
|
$client->getEmitter()->on('before', function (BeforeEvent $e) {
|
|
throw new RequestException('foo', $e->getRequest());
|
|
});
|
|
$client->get('http://httpbin.org');
|
|
}
|
|
|
|
/**
|
|
* @expectedException \GuzzleHttp\Exception\RequestException
|
|
* @expectedExceptionMessage foo
|
|
*/
|
|
public function testClientWrapsExceptions()
|
|
{
|
|
$client = new Client();
|
|
$client->getEmitter()->on('before', function (BeforeEvent $e) {
|
|
throw new \Exception('foo');
|
|
});
|
|
$client->get('http://httpbin.org');
|
|
}
|
|
|
|
public function testCanInjectResponseForFutureError()
|
|
{
|
|
$calledFuture = false;
|
|
$deferred = new Deferred();
|
|
$future = new FutureArray(
|
|
$deferred->promise(),
|
|
function () use ($deferred, &$calledFuture) {
|
|
$calledFuture = true;
|
|
$deferred->resolve(['error' => new \Exception('Noo!')]);
|
|
}
|
|
);
|
|
$mock = new MockAdapter($future);
|
|
$client = new Client(['adapter' => $mock]);
|
|
$called = 0;
|
|
$response = $client->get('http://localhost:123/foo', [
|
|
'future' => true,
|
|
'events' => [
|
|
'error' => function (ErrorEvent $e) use (&$called) {
|
|
$called++;
|
|
$e->intercept(new Response(200));
|
|
}
|
|
]
|
|
]);
|
|
$this->assertEquals(0, $called);
|
|
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$this->assertTrue($calledFuture);
|
|
$this->assertEquals(1, $called);
|
|
}
|
|
|
|
public function testCanReturnFutureResults()
|
|
{
|
|
$called = false;
|
|
$deferred = new Deferred();
|
|
$future = new FutureArray(
|
|
$deferred->promise(),
|
|
function () use ($deferred, &$called) {
|
|
$called = true;
|
|
$deferred->resolve(['status' => 201, 'headers' => []]);
|
|
}
|
|
);
|
|
$mock = new MockAdapter($future);
|
|
$client = new Client(['adapter' => $mock]);
|
|
$response = $client->get('http://localhost:123/foo', ['future' => true]);
|
|
$this->assertFalse($called);
|
|
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $response);
|
|
$this->assertEquals(201, $response->getStatusCode());
|
|
$this->assertTrue($called);
|
|
}
|
|
|
|
public function testThrowsExceptionsWhenDereferenced()
|
|
{
|
|
$calledFuture = false;
|
|
$deferred = new Deferred();
|
|
$future = new FutureArray(
|
|
$deferred->promise(),
|
|
function () use ($deferred, &$calledFuture) {
|
|
$calledFuture = true;
|
|
$deferred->resolve(['error' => new \Exception('Noop!')]);
|
|
}
|
|
);
|
|
$client = new Client(['adapter' => new MockAdapter($future)]);
|
|
try {
|
|
$res = $client->get('http://localhost:123/foo', ['future' => true]);
|
|
$res->deref();
|
|
$this->fail('Did not throw');
|
|
} catch (RequestException $e) {
|
|
$this->assertEquals(1, $calledFuture);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @expectedExceptionMessage Noo!
|
|
* @expectedException \GuzzleHttp\Exception\RequestException
|
|
*/
|
|
public function testThrowsExceptionsSynchronously()
|
|
{
|
|
$client = new Client([
|
|
'adapter' => new MockAdapter(['error' => new \Exception('Noo!')])
|
|
]);
|
|
$client->get('http://localhost:123/foo');
|
|
}
|
|
|
|
public function testCanSetDefaultValues()
|
|
{
|
|
$client = new Client(['foo' => 'bar']);
|
|
$client->setDefaultOption('headers/foo', 'bar');
|
|
$this->assertNull($client->getDefaultOption('foo'));
|
|
$this->assertEquals('bar', $client->getDefaultOption('headers/foo'));
|
|
}
|
|
|
|
public function testSendsAllInParallel()
|
|
{
|
|
$client = new Client();
|
|
$client->getEmitter()->attach(new Mock([
|
|
new Response(200),
|
|
new Response(201),
|
|
new Response(202),
|
|
]));
|
|
$history = new History();
|
|
$client->getEmitter()->attach($history);
|
|
|
|
$requests = [
|
|
$client->createRequest('GET', 'http://test.com'),
|
|
$client->createRequest('POST', 'http://test.com'),
|
|
$client->createRequest('PUT', 'http://test.com')
|
|
];
|
|
|
|
$client->sendAll($requests);
|
|
$requests = array_map(function($r) {
|
|
return $r->getMethod();
|
|
}, $history->getRequests());
|
|
$this->assertContains('GET', $requests);
|
|
$this->assertContains('POST', $requests);
|
|
$this->assertContains('PUT', $requests);
|
|
}
|
|
|
|
public function testCanDisableAuthPerRequest()
|
|
{
|
|
$client = new Client(['defaults' => ['auth' => 'foo']]);
|
|
$request = $client->createRequest('GET', 'http://test.com');
|
|
$this->assertEquals('foo', $request->getConfig()['auth']);
|
|
$request = $client->createRequest('GET', 'http://test.com', ['auth' => null]);
|
|
$this->assertFalse($request->getConfig()->hasKey('auth'));
|
|
}
|
|
|
|
public function testUsesProxyEnvironmentVariables()
|
|
{
|
|
$http = getenv('HTTP_PROXY');
|
|
$https = getenv('HTTPS_PROXY');
|
|
|
|
$client = new Client();
|
|
$this->assertNull($client->getDefaultOption('proxy'));
|
|
|
|
putenv('HTTP_PROXY=127.0.0.1');
|
|
$client = new Client();
|
|
$this->assertEquals(
|
|
['http' => '127.0.0.1'],
|
|
$client->getDefaultOption('proxy')
|
|
);
|
|
|
|
putenv('HTTPS_PROXY=127.0.0.2');
|
|
$client = new Client();
|
|
$this->assertEquals(
|
|
['http' => '127.0.0.1', 'https' => '127.0.0.2'],
|
|
$client->getDefaultOption('proxy')
|
|
);
|
|
|
|
putenv("HTTP_PROXY=$http");
|
|
putenv("HTTPS_PROXY=$https");
|
|
}
|
|
|
|
public function testCanInjectCancelledFutureInRequestEvents()
|
|
{
|
|
$client = new Client(['adapter' => new MockAdapter(['status' => 404])]);
|
|
$request = $client->createRequest('GET', 'http://localhost:123/foo', [
|
|
'future' => true
|
|
]);
|
|
$ex = null;
|
|
$request->getEmitter()->on('end', function (EndEvent $e) use (&$ex) {
|
|
$ex = $e->getException();
|
|
RequestEvents::cancelEndEvent($e);
|
|
});
|
|
|
|
// Should not throw yet!
|
|
$res = $client->send($request);
|
|
|
|
try {
|
|
// now it throws
|
|
$res->deref();
|
|
$this->fail('Did not throw');
|
|
} catch (CancelledRequestException $e) {
|
|
$this->assertTrue($res->cancelled());
|
|
$this->assertTrue($res->realized());
|
|
$this->assertInstanceOf('GuzzleHttp\Exception\ClientException', $e->getPrevious());
|
|
}
|
|
}
|
|
|
|
public function testCanInjectCancelledFutureForSynchronous()
|
|
{
|
|
$client = new Client(['adapter' => new MockAdapter(['status' => 404])]);
|
|
$request = $client->createRequest('GET', 'http://localhost:123/foo');
|
|
$ex = null;
|
|
$request->getEmitter()->on('end', function (EndEvent $e) use (&$ex) {
|
|
$ex = $e->getException();
|
|
RequestEvents::cancelEndEvent($e);
|
|
});
|
|
$res = $client->send($request);
|
|
$this->assertInstanceOf('GuzzleHttp\Message\CancelledFutureResponse', $res);
|
|
$this->assertTrue($res->cancelled());
|
|
$this->assertTrue($res->realized());
|
|
}
|
|
|
|
public function testReturnsFutureForErrorWhenRequested()
|
|
{
|
|
$client = new Client(['adapter' => new MockAdapter(['status' => 404])]);
|
|
$request = $client->createRequest('GET', 'http://localhost:123/foo', [
|
|
'future' => true
|
|
]);
|
|
$res = $client->send($request);
|
|
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
|
|
try {
|
|
$res->deref();
|
|
$this->fail('did not throw');
|
|
} catch (RequestException $e) {
|
|
$this->assertContains('404', $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function testReturnsFutureForResponseWhenRequested()
|
|
{
|
|
$client = new Client(['adapter' => new MockAdapter(['status' => 200])]);
|
|
$request = $client->createRequest('GET', 'http://localhost:123/foo', [
|
|
'future' => true
|
|
]);
|
|
$res = $client->send($request);
|
|
$this->assertInstanceOf('GuzzleHttp\Message\FutureResponse', $res);
|
|
$this->assertEquals(200, $res->getStatusCode());
|
|
}
|
|
}
|