Skip to content

Commit

Permalink
Simplified AsyncHttpConnector by applying Porter 5 changes.
Browse files Browse the repository at this point in the history
Increased ExponentialBackoffExceptionHandler delay in functional test.
  • Loading branch information
Bilge committed Apr 22, 2018
1 parent 9ff2fa4 commit 41e8aed
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 69 deletions.
43 changes: 20 additions & 23 deletions src/AsyncHttpConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
use Amp\Artax\Response;
use Amp\Artax\SocketException;
use Amp\Artax\TimeoutException;
use Amp\Promise;
use ScriptFUSION\Porter\Connector\AsyncConnector;
use ScriptFUSION\Porter\Connector\ConnectionContext;
use ScriptFUSION\Porter\Connector\ConnectorOptions;
use ScriptFUSION\Porter\Options\EncapsulatedOptions;

class AsyncHttpConnector implements AsyncConnector, ConnectorOptions
{
Expand All @@ -27,31 +27,28 @@ public function __clone()
$this->options = clone $this->options;
}

public function fetchAsync(ConnectionContext $context, string $source): Promise
public function fetchAsync(string $source, ConnectionContext $context)
{
return \Amp\call(function () use ($context, $source) {
$client = new DefaultClient($this->getOptions()->getCookieJar());
$client->setOptions($this->getOptions()->extractArtaxOptions());

return $context->retryAsync(
static function () use ($client, $source) {
try {
/** @var Response $response */
$response = yield $client->request($source);
$body = yield $response->getBody();
// Retry HTTP timeouts, socket timeouts and DNS resolution errors.
} catch (TimeoutException | SocketException | DnsException $exception) {
// Convert exception to recoverable exception.
throw new HttpConnectionException($exception->getMessage(), $exception->getCode(), $exception);
}

return HttpResponse::fromArtaxResponse($response, $body);
}
);
});
$client = new DefaultClient($this->options->getCookieJar());
$client->setOptions($this->options->extractArtaxOptions());

try {
/** @var Response $response */
$response = yield $client->request($source);
$body = yield $response->getBody();
// Retry HTTP timeouts, socket timeouts and DNS resolution errors.
} catch (TimeoutException | SocketException | DnsException $exception) {
// Convert exception to recoverable exception.
throw new HttpConnectionException($exception->getMessage(), $exception->getCode(), $exception);
}

return HttpResponse::fromArtaxResponse($response, $body);
}

public function getOptions()
/**
* @return ArtaxHttpOptions
*/
public function getOptions(): EncapsulatedOptions
{
return $this->options;
}
Expand Down
34 changes: 16 additions & 18 deletions src/HttpConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use ScriptFUSION\Porter\Connector\ConnectionContext;
use ScriptFUSION\Porter\Connector\Connector;
use ScriptFUSION\Porter\Connector\ConnectorOptions;
use ScriptFUSION\Porter\Options\EncapsulatedOptions;

/**
* Fetches data from an HTTP server via the PHP wrapper.
Expand All @@ -15,7 +16,6 @@
*/
class HttpConnector implements Connector, ConnectorOptions
{
/** @var HttpOptions */
private $options;

public function __construct(HttpOptions $options = null)
Expand All @@ -31,16 +31,16 @@ public function __clone()
/**
* {@inheritdoc}
*
* @param ConnectionContext $context Runtime connection settings and methods.
* @param string $source Source.
* @param ConnectionContext $context Runtime connection settings and methods.
*
* @return HttpResponse Response.
*
* @throws \InvalidArgumentException Options is not an instance of HttpOptions.
* @throws HttpConnectionException Failed to connect to source.
* @throws HttpServerException Server sent an error code.
*/
public function fetch(ConnectionContext $context, $source)
public function fetch(string $source, ConnectionContext $context)
{
$streamContext = stream_context_create([
'http' =>
Expand All @@ -51,29 +51,27 @@ public function fetch(ConnectionContext $context, $source)
'ssl' => $this->options->getSslOptions()->extractSslContextOptions(),
]);

return $context->retry(static function () use ($source, $streamContext) {
if (false === $body = @file_get_contents($source, false, $streamContext)) {
$error = error_get_last();
throw new HttpConnectionException($error['message'], $error['type']);
}
if (false === $body = @file_get_contents($source, false, $streamContext)) {
$error = error_get_last();
throw new HttpConnectionException($error['message'], $error['type']);
}

$response = HttpResponse::fromPhpWrapper($http_response_header, $body);
$response = HttpResponse::fromPhpWrapper($http_response_header, $body);

if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 400) {
throw new HttpServerException(
"HTTP server responded with error: \"{$response->getReasonPhrase()}\".\n\n$response",
$response
);
}
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 400) {
throw new HttpServerException(
"HTTP server responded with error: \"{$response->getReasonPhrase()}\".\n\n$response",
$response
);
}

return $response;
});
return $response;
}

/**
* @return HttpOptions
*/
public function getOptions()
public function getOptions(): EncapsulatedOptions
{
return $this->options;
}
Expand Down
9 changes: 2 additions & 7 deletions test/FixtureFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
namespace ScriptFUSIONTest;

use ScriptFUSION\Porter\Connector\ConnectionContext;
use ScriptFUSION\Porter\Connector\FetchExceptionHandler\FetchExceptionHandler;
use ScriptFUSION\StaticClass;

final class FixtureFactory
Expand All @@ -14,12 +13,8 @@ final class FixtureFactory
*
* @return ConnectionContext
*/
public static function createConnectionContext()
public static function createConnectionContext(): ConnectionContext
{
return new ConnectionContext(
false,
\Mockery::spy(FetchExceptionHandler::class),
1
);
return new ConnectionContext(false);
}
}
35 changes: 14 additions & 21 deletions test/Functional/HttpConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace ScriptFUSIONTest\Functional\Porter\Net\Http;

use Amp\Coroutine;
use ScriptFUSION\Porter\Connector\Connector;
use ScriptFUSION\Porter\Net\Http\AsyncHttpConnector;
use ScriptFUSION\Porter\Net\Http\HttpConnectionException;
Expand Down Expand Up @@ -95,30 +96,24 @@ public function testAsyncConnectionToLocalWebserver(): void

public function testConnectionTimeout(): void
{
try {
$this->fetch();
$this->setExpectedException(HttpConnectionException::class);

self::fail('Expected FailingTooHardException exception.');
} catch (FailingTooHardException $exception) {
self::assertInstanceOf(HttpConnectionException::class, $exception->getPrevious());
}
$this->fetch();
}

public function testErrorResponse(): void
{
$server = $this->startServer();

$this->setExpectedException(HttpServerException::class);

try {
$this->fetch('404.php');
} catch (HttpServerException $exception) {
$this->assertStringEndsWith('foo', $exception->getMessage());
$this->assertSame('foo', $exception->getResponse()->getBody());

self::fail('Expected FailingTooHardException exception.');
} catch (FailingTooHardException $exception) {
/** @var HttpServerException $innerException */
self::assertInstanceOf(HttpServerException::class, $innerException = $exception->getPrevious());

self::assertSame(404, $innerException->getResponse()->getStatusCode());
self::assertSame('foo', $innerException->getResponse()->getBody());
self::assertStringEndsWith("\n\nfoo", $innerException->getMessage());
throw $exception;
} finally {
$this->stopServer($server);
}
Expand Down Expand Up @@ -204,17 +199,17 @@ private function fetch(string $url = self::URI)
$fullUrl = 'http://' . self::HOST . "/$url";

if ($this->connector instanceof AsyncHttpConnector) {
return \Amp\Promise\wait($this->connector->fetchAsync($context, $fullUrl));
return \Amp\Promise\wait(new Coroutine($this->connector->fetchAsync($fullUrl, $context)));
}

return $this->connector->fetch($context, $fullUrl);
return $this->connector->fetch($fullUrl, $context);
}

private function fetchViaSsl(Connector $connector)
{
return $connector->fetch(
FixtureFactory::createConnectionContext(),
'https://' . self::SSL_HOST . '/' . self::URI
'https://' . self::SSL_HOST . '/' . self::URI,
FixtureFactory::createConnectionContext()
);
}

Expand All @@ -229,9 +224,7 @@ private static function waitForHttpServer(\Closure $serverInvoker): void
ImportSpecification::DEFAULT_FETCH_ATTEMPTS,
$serverInvoker,
function (\Exception $exception) {
if (!$exception instanceof FailingTooHardException
|| !$exception->getPrevious() instanceof HttpConnectionException
) {
if (!$exception instanceof HttpConnectionException) {
return false;
}

Expand Down

0 comments on commit 41e8aed

Please sign in to comment.