Skip to content

Commit 810e8a6

Browse files
committed
[HttpClient] Fix handling thrown \Exception in \Generator in MockResponse
1 parent 2a1b2aa commit 810e8a6

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

src/Symfony/Component/HttpClient/Response/MockResponse.php

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,16 +275,20 @@ private static function readResponse(self $response, array $options, ResponseInt
275275
$body = $mock instanceof self ? $mock->body : $mock->getContent(false);
276276

277277
if (!\is_string($body)) {
278-
foreach ($body as $chunk) {
279-
if ('' === $chunk = (string) $chunk) {
280-
// simulate an idle timeout
281-
$response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url']));
282-
} else {
283-
$response->body[] = $chunk;
284-
$offset += \strlen($chunk);
285-
// "notify" download progress
286-
$onProgress($offset, $dlSize, $response->info);
278+
try {
279+
foreach ($body as $chunk) {
280+
if ('' === $chunk = (string) $chunk) {
281+
// simulate an idle timeout
282+
$response->body[] = new ErrorChunk($offset, sprintf('Idle timeout reached for "%s".', $response->info['url']));
283+
} else {
284+
$response->body[] = $chunk;
285+
$offset += \strlen($chunk);
286+
// "notify" download progress
287+
$onProgress($offset, $dlSize, $response->info);
288+
}
287289
}
290+
} catch (\Exception $e) {
291+
$response->body[] = new ErrorChunk($offset, $e);
288292
}
289293
} elseif ('' !== $body) {
290294
$response->body[] = $body;

src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php

Lines changed: 43 additions & 0 deletions
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;
@@ -63,6 +66,46 @@ public function invalidResponseFactoryProvider()
6366
];
6467
}
6568

69+
public function testThrowExceptionInBodyGenerator()
70+
{
71+
$mockHttpClient = new MockHttpClient([
72+
new MockResponse((static function(): \Generator {
73+
yield 'foo';
74+
throw new TransportException('foo ccc');
75+
})()),
76+
new MockResponse((static function(): \Generator {
77+
yield 'bar';
78+
throw new \RuntimeException('bar ccc');
79+
})()),
80+
]);
81+
82+
try {
83+
$mockHttpClient->request('GET', 'https://symfony.com', [])->getContent();
84+
$this->fail();
85+
} catch (TransportException $e) {
86+
$this->assertEquals(new TransportException('foo ccc'), $e->getPrevious());
87+
$this->assertSame('foo ccc', $e->getMessage());
88+
}
89+
90+
$chunks = [];
91+
try {
92+
foreach ($mockHttpClient->stream($mockHttpClient->request('GET', 'https://symfony.com', [])) as $chunk) {
93+
$chunks[] = $chunk;
94+
}
95+
$this->fail();
96+
} catch (TransportException $e) {
97+
$this->assertEquals(new \RuntimeException('bar ccc'), $e->getPrevious());
98+
$this->assertSame('bar ccc', $e->getMessage());
99+
}
100+
101+
$this->assertCount(3, $chunks);
102+
$this->assertEquals(new FirstChunk(0, ''), $chunks[0]);
103+
$this->assertEquals(new DataChunk(0, 'bar'), $chunks[1]);
104+
$this->assertInstanceOf(ErrorChunk::class, $chunks[2]);
105+
$this->assertSame(3, $chunks[2]->getOffset());
106+
$this->assertSame('bar ccc', $chunks[2]->getError());
107+
}
108+
66109
protected function getHttpClient(string $testCase): HttpClientInterface
67110
{
68111
$responses = [];

0 commit comments

Comments
 (0)