|
11 | 11 |
|
12 | 12 | namespace Symfony\Component\HttpClient\Tests;
|
13 | 13 |
|
| 14 | +use GuzzleHttp\Promise\FulfilledPromise as GuzzleFulfilledPromise; |
14 | 15 | use Http\Client\Exception\NetworkException;
|
15 | 16 | use Http\Client\Exception\RequestException;
|
| 17 | +use Http\Promise\FulfilledPromise; |
16 | 18 | use Http\Promise\Promise;
|
17 | 19 | use PHPUnit\Framework\TestCase;
|
18 | 20 | use Psr\Http\Message\ResponseInterface;
|
| 21 | +use Symfony\Component\HttpClient\Exception\TransportException; |
19 | 22 | use Symfony\Component\HttpClient\HttplugClient;
|
| 23 | +use Symfony\Component\HttpClient\MockHttpClient; |
20 | 24 | use Symfony\Component\HttpClient\NativeHttpClient;
|
| 25 | +use Symfony\Component\HttpClient\Response\MockResponse; |
21 | 26 | use Symfony\Contracts\HttpClient\Test\TestHttpServer;
|
22 | 27 |
|
23 | 28 | class HttplugClientTest extends TestCase
|
@@ -152,4 +157,114 @@ public function testRequestException()
|
152 | 157 | $this->expectException(RequestException::class);
|
153 | 158 | $client->sendRequest($client->createRequest('BAD.METHOD', 'http://localhost:8057'));
|
154 | 159 | }
|
| 160 | + |
| 161 | + public function testRetry404() |
| 162 | + { |
| 163 | + $client = new HttplugClient(new NativeHttpClient()); |
| 164 | + |
| 165 | + $successCallableCalled = false; |
| 166 | + $failureCallableCalled = false; |
| 167 | + |
| 168 | + $promise = $client |
| 169 | + ->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/404')) |
| 170 | + ->then( |
| 171 | + function (ResponseInterface $response) use (&$successCallableCalled, $client) { |
| 172 | + $this->assertSame(404, $response->getStatusCode()); |
| 173 | + $successCallableCalled = true; |
| 174 | + |
| 175 | + return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057')); |
| 176 | + }, |
| 177 | + function (\Exception $exception) use (&$failureCallableCalled) { |
| 178 | + $failureCallableCalled = true; |
| 179 | + |
| 180 | + throw $exception; |
| 181 | + } |
| 182 | + ) |
| 183 | + ; |
| 184 | + |
| 185 | + $response = $promise->wait(true); |
| 186 | + |
| 187 | + $this->assertTrue($successCallableCalled); |
| 188 | + $this->assertFalse($failureCallableCalled); |
| 189 | + $this->assertSame(200, $response->getStatusCode()); |
| 190 | + } |
| 191 | + |
| 192 | + public function testRetryNetworkError() |
| 193 | + { |
| 194 | + $client = new HttplugClient(new NativeHttpClient()); |
| 195 | + |
| 196 | + $successCallableCalled = false; |
| 197 | + $failureCallableCalled = false; |
| 198 | + |
| 199 | + $promise = $client |
| 200 | + ->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057/chunked-broken')) |
| 201 | + ->then(function (ResponseInterface $response) use (&$successCallableCalled) { |
| 202 | + $successCallableCalled = true; |
| 203 | + |
| 204 | + return $response; |
| 205 | + }, function (\Exception $exception) use (&$failureCallableCalled, $client) { |
| 206 | + $this->assertSame(NetworkException::class, \get_class($exception)); |
| 207 | + $this->assertSame(TransportException::class, \get_class($exception->getPrevious())); |
| 208 | + $failureCallableCalled = true; |
| 209 | + |
| 210 | + return $client->sendAsyncRequest($client->createRequest('GET', 'http://localhost:8057')); |
| 211 | + }) |
| 212 | + ; |
| 213 | + |
| 214 | + $response = $promise->wait(true); |
| 215 | + |
| 216 | + $this->assertFalse($successCallableCalled); |
| 217 | + $this->assertTrue($failureCallableCalled); |
| 218 | + $this->assertSame(200, $response->getStatusCode()); |
| 219 | + } |
| 220 | + |
| 221 | + public function testRetryEarlierError() |
| 222 | + { |
| 223 | + $isFirstRequest = true; |
| 224 | + $errorMessage = 'Error occurred before making the actual request.'; |
| 225 | + |
| 226 | + $client = new HttplugClient(new MockHttpClient(function () use (&$isFirstRequest, $errorMessage) { |
| 227 | + if ($isFirstRequest) { |
| 228 | + $isFirstRequest = false; |
| 229 | + throw new TransportException($errorMessage); |
| 230 | + } |
| 231 | + |
| 232 | + return new MockResponse('OK', ['http_code' => 200]); |
| 233 | + })); |
| 234 | + |
| 235 | + $request = $client->createRequest('GET', 'http://test'); |
| 236 | + |
| 237 | + $successCallableCalled = false; |
| 238 | + $failureCallableCalled = false; |
| 239 | + |
| 240 | + $promise = $client |
| 241 | + ->sendAsyncRequest($request) |
| 242 | + ->then( |
| 243 | + function (ResponseInterface $response) use (&$successCallableCalled) { |
| 244 | + $successCallableCalled = true; |
| 245 | + |
| 246 | + return $response; |
| 247 | + }, |
| 248 | + function (\Exception $exception) use ($errorMessage, &$failureCallableCalled, $client, $request) { |
| 249 | + $this->assertSame(NetworkException::class, \get_class($exception)); |
| 250 | + $this->assertSame($errorMessage, $exception->getMessage()); |
| 251 | + $failureCallableCalled = true; |
| 252 | + |
| 253 | + // Ensure arbitrary levels of promises work. |
| 254 | + return (new FulfilledPromise(null))->then(function () use ($client, $request) { |
| 255 | + return (new GuzzleFulfilledPromise(null))->then(function () use ($client, $request) { |
| 256 | + return $client->sendAsyncRequest($request); |
| 257 | + }); |
| 258 | + }); |
| 259 | + } |
| 260 | + ) |
| 261 | + ; |
| 262 | + |
| 263 | + $response = $promise->wait(true); |
| 264 | + |
| 265 | + $this->assertFalse($successCallableCalled); |
| 266 | + $this->assertTrue($failureCallableCalled); |
| 267 | + $this->assertSame(200, $response->getStatusCode()); |
| 268 | + $this->assertSame('OK', (string) $response->getBody()); |
| 269 | + } |
155 | 270 | }
|
0 commit comments