From caab1c3ebc82ea69a7d262b2c685711657da7228 Mon Sep 17 00:00:00 2001 From: Gordon Govan Date: Wed, 26 Oct 2022 16:52:45 +0200 Subject: [PATCH] Include parsed error info in TransportError in async connections Passing the Content-Type to `_raise_errors` will cause the json body to be parsed and included in the `TransportError`. This matches the behaviour of the sync client. Fixes #225 Signed-off-by: Gordon Govan --- CHANGELOG.md | 1 + opensearchpy/_async/http_aiohttp.py | 6 +++- .../test_async/test_connection.py | 28 ++++++++++++++++--- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 479a0ac3..bc0712d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Fixed - Fixed import cycle when importing async helpers ([#311](https://github.com/opensearch-project/opensearch-py/pull/311)) - Fixed userguide for async client ([#340](https://github.com/opensearch-project/opensearch-py/pull/340)) +- Include parsed error info in TransportError in async connections (fixes #225) ([#226](https://github.com/opensearch-project/opensearch-py/pull/226) ### Security - Fixed CVE-2022-23491 reported in opensearch-dsl-py ([#295](https://github.com/opensearch-project/opensearch-py/pull/295)) - Update ci workflows ([#318](https://github.com/opensearch-project/opensearch-py/pull/318)) diff --git a/opensearchpy/_async/http_aiohttp.py b/opensearchpy/_async/http_aiohttp.py index 6f96997e..f630a3bd 100644 --- a/opensearchpy/_async/http_aiohttp.py +++ b/opensearchpy/_async/http_aiohttp.py @@ -331,7 +331,11 @@ async def perform_request( status_code=response.status, response=raw_data, ) - self._raise_error(response.status, raw_data) + self._raise_error( + response.status, + raw_data, + response.headers.get("content-type"), + ) self.log_request_success( method, str(url), url_path, orig_body, response.status, raw_data, duration diff --git a/test_opensearchpy/test_async/test_connection.py b/test_opensearchpy/test_async/test_connection.py index d43b2bb5..1b8cdc58 100644 --- a/test_opensearchpy/test_async/test_connection.py +++ b/test_opensearchpy/test_async/test_connection.py @@ -42,7 +42,7 @@ from opensearchpy import AIOHttpConnection, AsyncOpenSearch, __versionstr__, serializer from opensearchpy.compat import reraise_exceptions from opensearchpy.connection import Connection, async_connections -from opensearchpy.exceptions import ConnectionError +from opensearchpy.exceptions import ConnectionError, TransportError pytestmark = pytest.mark.asyncio @@ -53,7 +53,13 @@ def gzip_decompress(data): class TestAIOHttpConnection: - async def _get_mock_connection(self, connection_params={}, response_body=b"{}"): + async def _get_mock_connection( + self, + connection_params={}, + response_code=200, + response_body=b"{}", + response_headers={}, + ): con = AIOHttpConnection(**connection_params) await con._create_aiohttp_session() @@ -69,8 +75,8 @@ async def text(self): return response_body.decode("utf-8", "surrogatepass") dummy_response = DummyResponse() - dummy_response.headers = CIMultiDict() - dummy_response.status = 200 + dummy_response.headers = CIMultiDict(**response_headers) + dummy_response.status = response_code _dummy_request.call_args = (args, kwargs) return dummy_response @@ -298,6 +304,20 @@ def request_raise(*_, **__): await conn.perform_request("GET", "/") assert str(e.value) == "Wasn't modified!" + async def test_json_errors_are_parsed(self): + con = await self._get_mock_connection( + response_code=400, + response_body=b'{"error": {"type": "snapshot_in_progress_exception"}}', + response_headers={"Content-Type": "application/json;"}, + ) + try: + with pytest.raises(TransportError) as e: + await con.perform_request("POST", "/", body=b'{"some": "json"') + + assert e.value.error == "snapshot_in_progress_exception" + finally: + await con.close() + class TestConnectionHttpbin: """Tests the HTTP connection implementations against a live server E2E"""