From 79aa62d55a46275ad339e4233f8f8487dbbc7bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1gi-Kaz=C3=A1r=20M=C3=A1rk?= Date: Fri, 25 Dec 2015 00:08:35 +0100 Subject: [PATCH] Add client decorators and emulators --- composer.json | 3 +- spec/BatchClientSpec.php | 2 +- spec/HttpAsyncClientDecoratorSpec.php | 47 ++++++++++++++++++++ spec/HttpAsyncClientEmulatorSpec.php | 52 ++++++++++++++++++++++ spec/HttpClientDecoratorSpec.php | 47 ++++++++++++++++++++ spec/HttpClientEmulatorSpec.php | 62 +++++++++++++++++++++++++++ spec/HttpMethodsClientSpec.php | 2 +- src/HttpAsyncClientDecorator.php | 29 +++++++++++++ src/HttpAsyncClientEmulator.php | 36 ++++++++++++++++ src/HttpClientDecorator.php | 29 +++++++++++++ src/HttpClientEmulator.php | 32 ++++++++++++++ 11 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 spec/HttpAsyncClientDecoratorSpec.php create mode 100644 spec/HttpAsyncClientEmulatorSpec.php create mode 100644 spec/HttpClientDecoratorSpec.php create mode 100644 spec/HttpClientEmulatorSpec.php create mode 100644 src/HttpAsyncClientDecorator.php create mode 100644 src/HttpAsyncClientEmulator.php create mode 100644 src/HttpClientDecorator.php create mode 100644 src/HttpClientEmulator.php diff --git a/composer.json b/composer.json index 1fabbe7..957e4f8 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "require": { "php": ">=5.4", "php-http/httplug": "1.0.0-beta", - "php-http/message-factory": "^1.0" + "php-http/message-factory": "^1.0", + "php-http/promise": "^0.1.1" }, "require-dev": { "phpspec/phpspec": "^2.4", diff --git a/spec/BatchClientSpec.php b/spec/BatchClientSpec.php index b7375ad..962f00a 100644 --- a/spec/BatchClientSpec.php +++ b/spec/BatchClientSpec.php @@ -3,9 +3,9 @@ namespace spec\Http\Client\Common; use Http\Client\HttpClient; -use PhpSpec\ObjectBehavior; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use PhpSpec\ObjectBehavior; class BatchClientSpec extends ObjectBehavior { diff --git a/spec/HttpAsyncClientDecoratorSpec.php b/spec/HttpAsyncClientDecoratorSpec.php new file mode 100644 index 0000000..01c4d79 --- /dev/null +++ b/spec/HttpAsyncClientDecoratorSpec.php @@ -0,0 +1,47 @@ +beAnInstanceOf('spec\Http\Client\Common\HttpAsyncClientDecoratorStub', [$httpAsyncClient]); + } + + function it_is_initializable() + { + $this->shouldHaveType('spec\Http\Client\Common\HttpAsyncClientDecoratorStub'); + } + + function it_is_an_http_async_client() + { + $this->shouldImplement('Http\Client\HttpAsyncClient'); + } + + function it_decorates_the_underlying_client(HttpAsyncClient $httpAsyncClient, RequestInterface $request, Promise $promise) + { + $httpAsyncClient->sendAsyncRequest($request)->willReturn($promise); + + $this->sendAsyncRequest($request)->shouldReturn($promise); + } +} + +class HttpAsyncClientDecoratorStub implements HttpAsyncClient +{ + use HttpAsyncClientDecorator; + + /** + * @param HttpAsyncClient $httpAsyncClient + */ + public function __construct(HttpAsyncClient $httpAsyncClient) + { + $this->httpAsyncClient = $httpAsyncClient; + } +} diff --git a/spec/HttpAsyncClientEmulatorSpec.php b/spec/HttpAsyncClientEmulatorSpec.php new file mode 100644 index 0000000..15eacc5 --- /dev/null +++ b/spec/HttpAsyncClientEmulatorSpec.php @@ -0,0 +1,52 @@ +beAnInstanceOf('spec\Http\Client\Common\HttpAsyncClientEmulatorStub', [$httpClient]); + } + + function it_is_initializable() + { + $this->shouldHaveType('spec\Http\Client\Common\HttpAsyncClientEmulatorStub'); + } + + function it_emulates_a_successful_request(HttpClient $httpClient, RequestInterface $request, ResponseInterface $response) + { + $httpClient->sendRequest($request)->willReturn($response); + + $this->sendAsyncRequest($request)->shouldReturnAnInstanceOf('Http\Promise\FulfilledPromise'); + } + + function it_emulates_a_failed_request(HttpClient $httpClient, RequestInterface $request) + { + $httpClient->sendRequest($request)->willThrow('Http\Client\Exception\TransferException'); + + $this->sendAsyncRequest($request)->shouldReturnAnInstanceOf('Http\Promise\RejectedPromise'); + } +} + +class HttpAsyncClientEmulatorStub implements HttpClient, HttpAsyncClient +{ + use HttpClientDecorator; + use HttpAsyncClientEmulator; + + /** + * @param HttpClient $httpClient + */ + public function __construct(HttpClient $httpClient) + { + $this->httpClient = $httpClient; + } +} diff --git a/spec/HttpClientDecoratorSpec.php b/spec/HttpClientDecoratorSpec.php new file mode 100644 index 0000000..2e24b7a --- /dev/null +++ b/spec/HttpClientDecoratorSpec.php @@ -0,0 +1,47 @@ +beAnInstanceOf('spec\Http\Client\Common\HttpClientDecoratorStub', [$httpClient]); + } + + function it_is_initializable() + { + $this->shouldHaveType('spec\Http\Client\Common\HttpClientDecoratorStub'); + } + + function it_is_an_http_client() + { + $this->shouldImplement('Http\Client\HttpClient'); + } + + function it_decorates_the_underlying_client(HttpClient $httpClient, RequestInterface $request, ResponseInterface $response) + { + $httpClient->sendRequest($request)->willReturn($response); + + $this->sendRequest($request)->shouldReturn($response); + } +} + +class HttpClientDecoratorStub implements HttpClient +{ + use HttpClientDecorator; + + /** + * @param HttpClient $httpClient + */ + public function __construct(HttpClient $httpClient) + { + $this->httpClient = $httpClient; + } +} diff --git a/spec/HttpClientEmulatorSpec.php b/spec/HttpClientEmulatorSpec.php new file mode 100644 index 0000000..7a56a3c --- /dev/null +++ b/spec/HttpClientEmulatorSpec.php @@ -0,0 +1,62 @@ +beAnInstanceOf('spec\Http\Client\Common\HttpClientEmulatorStub', [$httpAsyncClient]); + } + + function it_is_initializable() + { + $this->shouldHaveType('spec\Http\Client\Common\HttpClientEmulatorStub'); + } + + function it_emulates_a_successful_request(HttpAsyncClient $httpAsyncClient, RequestInterface $request, Promise $promise, ResponseInterface $response) + { + $promise->wait()->shouldBeCalled(); + $promise->getState()->willReturn(Promise::FULFILLED); + $promise->wait()->willReturn($response); + + $httpAsyncClient->sendAsyncRequest($request)->willReturn($promise); + + $this->sendRequest($request)->shouldReturn($response); + } + + function it_emulates_a_failed_request(HttpAsyncClient $httpAsyncClient, RequestInterface $request, Promise $promise) + { + $promise->wait()->shouldBeCalled(); + $promise->getState()->willReturn(Promise::REJECTED); + $promise->wait()->willThrow(new TransferException()); + + $httpAsyncClient->sendAsyncRequest($request)->willReturn($promise); + + $this->shouldThrow('Http\Client\Exception')->duringSendRequest($request); + } +} + +class HttpClientEmulatorStub implements HttpAsyncClient, HttpClient +{ + use HttpAsyncClientDecorator; + use HttpClientEmulator; + + /** + * @param HttpAsyncClient $httpAsyncClient + */ + public function __construct(HttpAsyncClient $httpAsyncClient) + { + $this->httpAsyncClient = $httpAsyncClient; + } +} diff --git a/spec/HttpMethodsClientSpec.php b/spec/HttpMethodsClientSpec.php index b5b82da..07c0b47 100644 --- a/spec/HttpMethodsClientSpec.php +++ b/spec/HttpMethodsClientSpec.php @@ -6,9 +6,9 @@ use Http\Client\HttpClient; use Http\Client\Common\HttpMethodsClient; use Http\Message\MessageFactory; -use PhpSpec\ObjectBehavior; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use PhpSpec\ObjectBehavior; class HttpMethodsClientSpec extends ObjectBehavior { diff --git a/src/HttpAsyncClientDecorator.php b/src/HttpAsyncClientDecorator.php new file mode 100644 index 0000000..6eb576c --- /dev/null +++ b/src/HttpAsyncClientDecorator.php @@ -0,0 +1,29 @@ + + */ +trait HttpAsyncClientDecorator +{ + /** + * @var HttpAsyncClient + */ + protected $httpAsyncClient; + + /** + * {@inheritdoc} + * + * @see HttpAsyncClient::sendAsyncRequest + */ + public function sendAsyncRequest(RequestInterface $request) + { + return $this->httpAsyncClient->sendAsyncRequest($request); + } +} diff --git a/src/HttpAsyncClientEmulator.php b/src/HttpAsyncClientEmulator.php new file mode 100644 index 0000000..9f527f4 --- /dev/null +++ b/src/HttpAsyncClientEmulator.php @@ -0,0 +1,36 @@ + + */ +trait HttpAsyncClientEmulator +{ + /** + * {@inheritdoc} + * + * @see HttpClient::sendRequest + */ + abstract public function sendRequest(RequestInterface $request); + + /** + * {@inheritdoc} + * + * @see HttpAsyncClient::sendAsyncRequest + */ + public function sendAsyncRequest(RequestInterface $request) + { + try { + return new Promise\FulfilledPromise($this->sendRequest($request)); + } catch (Exception $e) { + return new Promise\RejectedPromise($e); + } + } +} diff --git a/src/HttpClientDecorator.php b/src/HttpClientDecorator.php new file mode 100644 index 0000000..a33d5ef --- /dev/null +++ b/src/HttpClientDecorator.php @@ -0,0 +1,29 @@ + + */ +trait HttpClientDecorator +{ + /** + * @var HttpClient + */ + protected $httpClient; + + /** + * {@inheritdoc} + * + * @see HttpClient::sendRequest + */ + public function sendRequest(RequestInterface $request) + { + return $this->httpClient->sendRequest($request); + } +} diff --git a/src/HttpClientEmulator.php b/src/HttpClientEmulator.php new file mode 100644 index 0000000..dbec1ab --- /dev/null +++ b/src/HttpClientEmulator.php @@ -0,0 +1,32 @@ + + */ +trait HttpClientEmulator +{ + /** + * {@inheritdoc} + * + * @see HttpClient::sendRequest + */ + public function sendRequest(RequestInterface $request) + { + $promise = $this->sendAsyncRequest($request); + + return $promise->wait(); + } + + /** + * {@inheritdoc} + * + * @see HttpAsyncClient::sendAsyncRequest + */ + abstract public function sendAsyncRequest(RequestInterface $request); +}