diff --git a/tests/unit/http/test_async_http_client.py b/tests/unit/http/test_async_http_client.py index 23df35dc0..2498c2685 100644 --- a/tests/unit/http/test_async_http_client.py +++ b/tests/unit/http/test_async_http_client.py @@ -1,3 +1,5 @@ +import asyncio + import aiounittest from aiohttp import ClientSession @@ -131,3 +133,59 @@ async def test_session_not_preserved(self): # No session used, responses should be different (not cached) self.assertEqual(response_1.content, "response_1") self.assertEqual(response_2.content, "response_2") + + async def test_temporary_session_closed_after_request_error(self): + self._setup_session_response("unused") + session = self.session_constructor_mock.return_value + session.request.side_effect = OSError("connection failed") + client = AsyncTwilioHttpClient(pool_connections=False) + + with self.assertRaisesRegex(OSError, "connection failed"): + await client.request("GET", "https://api.twilio.com") + + session.close.assert_awaited_once() + + async def test_temporary_session_closed_after_body_error(self): + self._setup_session_response("unused") + session = self.session_constructor_mock.return_value + session.request.return_value.text = AsyncMock( + side_effect=UnicodeDecodeError("utf-8", b"\xff", 0, 1, "invalid byte") + ) + client = AsyncTwilioHttpClient(pool_connections=False) + + with self.assertRaises(UnicodeDecodeError): + await client.request("GET", "https://api.twilio.com") + + session.close.assert_awaited_once() + + async def test_temporary_session_closed_after_cancellation(self): + self._setup_session_response("unused") + session = self.session_constructor_mock.return_value + session.request.side_effect = asyncio.CancelledError() + client = AsyncTwilioHttpClient(pool_connections=False) + + with self.assertRaises(asyncio.CancelledError): + await client.request("GET", "https://api.twilio.com") + + session.close.assert_awaited_once() + + async def test_pooled_session_preserved_after_request_error(self): + self._setup_session_response("unused") + session = self.session_constructor_mock.return_value + session.request.side_effect = OSError("connection failed") + client = AsyncTwilioHttpClient() + + with self.assertRaisesRegex(OSError, "connection failed"): + await client.request("GET", "https://api.twilio.com") + + session.close.assert_not_awaited() + + async def test_temporary_session_closed_after_success(self): + self._setup_session_response("response") + session = self.session_constructor_mock.return_value + client = AsyncTwilioHttpClient(pool_connections=False) + + response = await client.request("GET", "https://api.twilio.com") + + self.assertEqual(response.content, "response") + session.close.assert_awaited_once() diff --git a/twilio/http/async_http_client.py b/twilio/http/async_http_client.py index ecd5d4de9..483c4c436 100644 --- a/twilio/http/async_http_client.py +++ b/twilio/http/async_http_client.py @@ -104,15 +104,17 @@ async def request( else: session = ClientSession() temp = True - self._test_only_last_request = TwilioRequest(**kwargs) - response = await session.request(**kwargs) - self.log_response(response.status, response) - self._test_only_last_response = Response( - response.status, await response.text(), response.headers - ) - if temp: - await session.close() - return self._test_only_last_response + try: + self._test_only_last_request = TwilioRequest(**kwargs) + response = await session.request(**kwargs) + self.log_response(response.status, response) + self._test_only_last_response = Response( + response.status, await response.text(), response.headers + ) + return self._test_only_last_response + finally: + if temp: + await session.close() async def close(self): """