Skip to content

Commit f8bcc85

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: [HttpClient] Fix handling thrown \Exception in \Generator in MockResponse [DebugBundle] Add missing README [Lock] Fix missing argument in PostgreSqlStore::putOffExpiration with DBAL connection Bump Symfony version to 5.4.2 Update VERSION for 5.4.1 Update CHANGELOG for 5.4.1 [String] Fix requiring wcswitch table several times
2 parents 583f015 + 5157005 commit f8bcc85

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

Response/MockResponse.php

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class MockResponse implements ResponseInterface, StreamableInterface
4141
/**
4242
* @param string|string[]|iterable $body The response body as a string or an iterable of strings,
4343
* yielding an empty string simulates an idle timeout,
44-
* exceptions are turned to TransportException
44+
* throwing an exception yields an ErrorChunk
4545
*
4646
* @see ResponseInterface::getInfo() for possible info, e.g. "response_headers"
4747
*/
@@ -208,6 +208,9 @@ protected static function perform(ClientState $multi, array &$responses): void
208208
$multi->handlesActivity[$id][] = null;
209209
$multi->handlesActivity[$id][] = $e;
210210
}
211+
} elseif ($chunk instanceof \Throwable) {
212+
$multi->handlesActivity[$id][] = null;
213+
$multi->handlesActivity[$id][] = $chunk;
211214
} else {
212215
// Data or timeout chunk
213216
$multi->handlesActivity[$id][] = $chunk;
@@ -300,16 +303,20 @@ private static function readResponse(self $response, array $options, ResponseInt
300303
$body = $mock instanceof self ? $mock->body : $mock->getContent(false);
301304

302305
if (!\is_string($body)) {
303-
foreach ($body as $chunk) {
304-
if ('' === $chunk = (string) $chunk) {
305-
// simulate an idle timeout
306-
$response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url']));
307-
} else {
308-
$response->body[] = $chunk;
309-
$offset += \strlen($chunk);
310-
// "notify" download progress
311-
$onProgress($offset, $dlSize, $response->info);
306+
try {
307+
foreach ($body as $chunk) {
308+
if ('' === $chunk = (string) $chunk) {
309+
// simulate an idle timeout
310+
$response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url']));
311+
} else {
312+
$response->body[] = $chunk;
313+
$offset += \strlen($chunk);
314+
// "notify" download progress
315+
$onProgress($offset, $dlSize, $response->info);
316+
}
312317
}
318+
} catch (\Throwable $e) {
319+
$response->body[] = $e;
313320
}
314321
} elseif ('' !== $body) {
315322
$response->body[] = $body;

Tests/MockHttpClientTest.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Symfony\Component\HttpClient\Tests;
1313

14+
use Symfony\Component\HttpClient\Chunk\DataChunk;
15+
use Symfony\Component\HttpClient\Chunk\ErrorChunk;
16+
use Symfony\Component\HttpClient\Chunk\FirstChunk;
1417
use Symfony\Component\HttpClient\Exception\TransportException;
1518
use Symfony\Component\HttpClient\MockHttpClient;
1619
use Symfony\Component\HttpClient\NativeHttpClient;
@@ -184,6 +187,46 @@ public function invalidResponseFactoryProvider()
184187
];
185188
}
186189

190+
public function testThrowExceptionInBodyGenerator()
191+
{
192+
$mockHttpClient = new MockHttpClient([
193+
new MockResponse((static function (): \Generator {
194+
yield 'foo';
195+
throw new TransportException('foo ccc');
196+
})()),
197+
new MockResponse((static function (): \Generator {
198+
yield 'bar';
199+
throw new \RuntimeException('bar ccc');
200+
})()),
201+
]);
202+
203+
try {
204+
$mockHttpClient->request('GET', 'https://symfony.com', [])->getContent();
205+
$this->fail();
206+
} catch (TransportException $e) {
207+
$this->assertEquals(new TransportException('foo ccc'), $e->getPrevious());
208+
$this->assertSame('foo ccc', $e->getMessage());
209+
}
210+
211+
$chunks = [];
212+
try {
213+
foreach ($mockHttpClient->stream($mockHttpClient->request('GET', 'https://symfony.com', [])) as $chunk) {
214+
$chunks[] = $chunk;
215+
}
216+
$this->fail();
217+
} catch (TransportException $e) {
218+
$this->assertEquals(new \RuntimeException('bar ccc'), $e->getPrevious());
219+
$this->assertSame('bar ccc', $e->getMessage());
220+
}
221+
222+
$this->assertCount(3, $chunks);
223+
$this->assertEquals(new FirstChunk(0, ''), $chunks[0]);
224+
$this->assertEquals(new DataChunk(0, 'bar'), $chunks[1]);
225+
$this->assertInstanceOf(ErrorChunk::class, $chunks[2]);
226+
$this->assertSame(3, $chunks[2]->getOffset());
227+
$this->assertSame('bar ccc', $chunks[2]->getError());
228+
}
229+
187230
protected function getHttpClient(string $testCase): HttpClientInterface
188231
{
189232
$responses = [];
@@ -299,7 +342,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface
299342
case 'testResolve':
300343
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
301344
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
302-
$responses[] = new MockResponse((function () { throw new \Exception('Fake connection timeout'); yield ''; })(), ['response_headers' => $headers]);
345+
$responses[] = new MockResponse((function () { yield ''; })(), ['response_headers' => $headers]);
303346
break;
304347

305348
case 'testTimeoutOnStream':

0 commit comments

Comments
 (0)