Skip to content

Commit

Permalink
Merge branch '5.0' into 5.1
Browse files Browse the repository at this point in the history
* 5.0:
  minor #37121 [Contracts] Add missing "extra.thanks" entries in composer.json (nicolas-grekas)
  [Process] Fix Permission Denied error when writing sf_proc_00 lock files on Windows
  fix handling null as empty data
  No need to create an issue when creating a PR
  Use ">=" for the "php" requirement
  [HttpClient] Fix promise behavior in HttplugClient
  [Console] Fixes question input encoding on Windows
  • Loading branch information
nicolas-grekas committed Jul 6, 2020
2 parents 4b296e8 + 9eec6ed commit 050dc63
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 3 deletions.
4 changes: 2 additions & 2 deletions HttplugClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\HttpClient;

use GuzzleHttp\Promise\Promise as GuzzlePromise;
use GuzzleHttp\Promise\RejectedPromise;
use Http\Client\Exception\NetworkException;
use Http\Client\Exception\RequestException;
use Http\Client\HttpAsyncClient;
Expand All @@ -22,7 +23,6 @@
use Http\Message\StreamFactory;
use Http\Message\UriFactory;
use Http\Promise\Promise;
use Http\Promise\RejectedPromise;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\Request;
use Nyholm\Psr7\Uri;
Expand Down Expand Up @@ -114,7 +114,7 @@ public function sendAsyncRequest(RequestInterface $request): Promise
try {
$response = $this->sendPsr7Request($request, true);
} catch (NetworkException $e) {
return new RejectedPromise($e);
return new HttplugPromise(new RejectedPromise($e));
}

$waitLoop = $this->waitLoop;
Expand Down
8 changes: 7 additions & 1 deletion Response/HttplugPromise.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ public function getState(): string
*/
public function wait($unwrap = true)
{
return $this->promise->wait($unwrap);
$result = $this->promise->wait($unwrap);

while ($result instanceof HttplugPromiseInterface || $result instanceof GuzzlePromiseInterface) {
$result = $result->wait($unwrap);
}

return $result;
}
}
115 changes: 115 additions & 0 deletions Tests/HttplugClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@

namespace Symfony\Component\HttpClient\Tests;

use GuzzleHttp\Promise\FulfilledPromise as GuzzleFulfilledPromise;
use Http\Client\Exception\NetworkException;
use Http\Client\Exception\RequestException;
use Http\Promise\FulfilledPromise;
use Http\Promise\Promise;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpClient\Exception\TransportException;
use Symfony\Component\HttpClient\HttplugClient;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\NativeHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\HttpClient\Test\TestHttpServer;

class HttplugClientTest extends TestCase
Expand Down Expand Up @@ -152,4 +157,114 @@ public function testRequestException()
$this->expectException(RequestException::class);
$client->sendRequest($client->createRequest('BAD.METHOD', 'http://localhost:8057'));
}

public function testRetry404()
{
$client = new HttplugClient(new NativeHttpClient());

$successCallableCalled = false;
$failureCallableCalled = false;

$promise = $client
->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/404'))
->then(
function (ResponseInterface $response) use (&$successCallableCalled, $client) {
$this->assertSame(404, $response->getStatusCode());
$successCallableCalled = true;

return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057'));
},
function (\Exception $exception) use (&$failureCallableCalled) {
$failureCallableCalled = true;

throw $exception;
}
)
;

$response = $promise->wait(true);

$this->assertTrue($successCallableCalled);
$this->assertFalse($failureCallableCalled);
$this->assertSame(200, $response->getStatusCode());
}

public function testRetryNetworkError()
{
$client = new HttplugClient(new NativeHttpClient());

$successCallableCalled = false;
$failureCallableCalled = false;

$promise = $client
->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/chunked-broken'))
->then(function (ResponseInterface $response) use (&$successCallableCalled) {
$successCallableCalled = true;

return $response;
}, function (\Exception $exception) use (&$failureCallableCalled, $client) {
$this->assertSame(NetworkException::class, \get_class($exception));
$this->assertSame(TransportException::class, \get_class($exception->getPrevious()));
$failureCallableCalled = true;

return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057'));
})
;

$response = $promise->wait(true);

$this->assertFalse($successCallableCalled);
$this->assertTrue($failureCallableCalled);
$this->assertSame(200, $response->getStatusCode());
}

public function testRetryEarlierError()
{
$isFirstRequest = true;
$errorMessage = 'Error occurred before making the actual request.';

$client = new HttplugClient(new MockHttpClient(function () use (&$isFirstRequest, $errorMessage) {
if ($isFirstRequest) {
$isFirstRequest = false;
throw new TransportException($errorMessage);
}

return new MockResponse('OK', ['http_code' => 200]);
}));

$request = $client->createRequest('GET', 'http://test');

$successCallableCalled = false;
$failureCallableCalled = false;

$promise = $client
->sendAsyncRequest($request)
->then(
function (ResponseInterface $response) use (&$successCallableCalled) {
$successCallableCalled = true;

return $response;
},
function (\Exception $exception) use ($errorMessage, &$failureCallableCalled, $client, $request) {
$this->assertSame(NetworkException::class, \get_class($exception));
$this->assertSame($errorMessage, $exception->getMessage());
$failureCallableCalled = true;

// Ensure arbitrary levels of promises work.
return (new FulfilledPromise(null))->then(function () use ($client, $request) {
return (new GuzzleFulfilledPromise(null))->then(function () use ($client, $request) {
return $client->sendAsyncRequest($request);
});
});
}
)
;

$response = $promise->wait(true);

$this->assertFalse($successCallableCalled);
$this->assertTrue($failureCallableCalled);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('OK', (string) $response->getBody());
}
}

0 comments on commit 050dc63

Please sign in to comment.