From 47af7fc2ca415918ca8faf9c023f783a6845fdde Mon Sep 17 00:00:00 2001 From: alex-smile <443677891@qq.com> Date: Mon, 20 Nov 2023 09:34:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bkapi_client_core/client.py | 6 +- sdks/bkapi-client-core/tests/test_client.py | 48 ++++++-- .../tests/test_exceptions.py | 110 +++++++++++++++--- sdks/bkapi-client-core/tests/test_utils.py | 16 +-- 4 files changed, 146 insertions(+), 34 deletions(-) diff --git a/sdks/bkapi-client-core/bkapi_client_core/client.py b/sdks/bkapi-client-core/bkapi_client_core/client.py index 697f979c..df68632d 100644 --- a/sdks/bkapi-client-core/bkapi_client_core/client.py +++ b/sdks/bkapi-client-core/bkapi_client_core/client.py @@ -13,7 +13,7 @@ from typing import Any, Dict, Optional from requests import Response -from requests.exceptions import HTTPError, RequestException, JSONDecodeError +from requests.exceptions import HTTPError, RequestException from requests.sessions import merge_setting from requests.structures import CaseInsensitiveDict @@ -267,7 +267,7 @@ def _handle_exception( if isinstance(exception, RequestException): response = exception.response response_headers_representer = ResponseHeadersRepresenter(response and response.headers) - logger.exception( + logger.warning( "request bkapi failed. status_code: %s, %s\n%s", response and response.status_code, response_headers_representer, @@ -318,7 +318,7 @@ def _handle_response_content( # 如此,方便调用者在同一层中处理 http 状态码和 json 两个异常 try: response_json = response.json() - except (TypeError, json.JSONDecodeError, JSONDecodeError): + except (TypeError, json.JSONDecodeError): raise JSONResponseError( "The response is not a valid JSON", response=response, diff --git a/sdks/bkapi-client-core/tests/test_client.py b/sdks/bkapi-client-core/tests/test_client.py index 00ba79d7..cd0545a4 100644 --- a/sdks/bkapi-client-core/tests/test_client.py +++ b/sdks/bkapi-client-core/tests/test_client.py @@ -213,15 +213,35 @@ def test_has_apigateway_error(self, headers, expected): headers = ResponseHeadersRepresenter(headers) assert headers.has_apigateway_error == expected - def test_str(self, faker): - headers = ResponseHeadersRepresenter( - { - "X-Bkapi-Error-Code": faker.pystr(), - "X-Bkapi-Error-Message": faker.pystr(), - "X-Bkapi-Request-Id": faker.uuid4(), - } - ) - assert "request_id:" in str(headers) + @pytest.mark.parametrize( + "headers, expected", + [ + ( + { + "X-Bkapi-Request-Id": "abcdef", + "X-Bkapi-Error-Code": "foo", + "X-Bkapi-Error-Message": "error", + }, + "request_id: abcdef, error_code: foo, error", + ), + ( + { + "X-Bkapi-Request-Id": "abcdef", + "X-Bkapi-Error-Code": "foo", + }, + "request_id: abcdef, error_code: foo", + ), + ( + { + "X-Bkapi-Request-Id": "abcdef", + }, + "request_id: abcdef", + ), + ] + ) + def test_str(self, headers, expected): + representer = ResponseHeadersRepresenter(headers) + assert str(representer) == expected class TestBaseClient: @@ -428,12 +448,20 @@ def test_handler_exception(self, mocker): def test_handle_response_content(self, mocker): assert self.client._handle_response_content(mocker.MagicMock(), None) is None + response = { + "headers": {"X-Bkapi-Request-Id": "abcd"}, + "json.return_value": {"foo": "bar"}, + "raise_for_status.return_value": None, + } + result = self.client._handle_response_content(None, mocker.MagicMock(**response)) + assert result == {"foo": "bar"} + @pytest.mark.parametrize( "response", [ {"headers": {"X-Bkapi-Error-Code": "error"}}, + {"json.side_effect": TypeError}, {"raise_for_status.side_effect": RequestException("error")}, - {"raise_for_status.return_value": None, "json.side_effect": TypeError}, ], ) def test_handle_response_content_error(self, mocker, response): diff --git a/sdks/bkapi-client-core/tests/test_exceptions.py b/sdks/bkapi-client-core/tests/test_exceptions.py index 51d1e18a..3e14c729 100644 --- a/sdks/bkapi-client-core/tests/test_exceptions.py +++ b/sdks/bkapi-client-core/tests/test_exceptions.py @@ -8,28 +8,54 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. """ +import pytest +import requests + from bkapi_client_core import exceptions from bkapi_client_core.client import ResponseHeadersRepresenter class TestResponseError: - def test_str(self, mocker, faker): - err = exceptions.ResponseError("error", response=None) - assert str(err) == "error" - - err = exceptions.ResponseError( - "error", - response=mocker.MagicMock(), - response_headers_representer=ResponseHeadersRepresenter( + @pytest.mark.parametrize( + "error, response, headers, expected", + [ + ( + "error", + { + "status_code": 400, + }, + { + "X-Bkapi-Error-Code": "code", + "X-Bkapi-Error-Message": "error-message", + "X-Bkapi-Request-Id": "abcdef", + }, + "error, status_code: 400, request_id: abcdef, error_code: code, error-message", + ), + ( + "error", + None, + None, + "error", + ), + ( + "error", + { + "status_code": 400, + }, { - "X-Bkapi-Error-Code": faker.pystr(), - "X-Bkapi-Error-Message": faker.pystr(), - "X-Bkapi-Request-Id": faker.uuid4(), - } + "X-Bkapi-Request-Id": "abcdef", + }, + "error, status_code: 400, request_id: abcdef", ), + ] + ) + def test_str(self, mocker, error, response, headers, expected): + err = exceptions.ResponseError( + error, + response=response and mocker.MagicMock(**response), + response_headers_representer=ResponseHeadersRepresenter(headers), ) - assert str(err).startswith("error") - assert "request_id:" in str(err) + assert str(err) == expected def test_error_code(self, mocker): err = exceptions.ResponseError( @@ -54,3 +80,59 @@ def test_request_id(self, mocker): response_headers_representer=ResponseHeadersRepresenter({"X-Bkapi-Request-Id": "abcdef"}), ) assert err.request_id == "abcdef" + + def test_curl_command(self, mocker, faker): + mocker.patch( + "bkapi_client_core.exceptions.CurlRequest.to_curl", return_value="curl -X GET http://example.com", + ) + err = exceptions.ResponseError( + faker.pystr(), + response=mocker.MagicMock(), + response_headers_representer=ResponseHeadersRepresenter({"X-Bkapi-Request-Id": "abcdef"}), + ) + assert err.curl_command == "curl -X GET http://example.com" + + @pytest.mark.parametrize( + "request_, expected", + [ + (None, None), + ({"method": "GET"}, "GET"), + ] + ) + def test_request_method(self, mocker, faker, request_, expected): + err = exceptions.ResponseError( + faker.pystr(), + request=request_ and mocker.MagicMock(**request_), + response_headers_representer=ResponseHeadersRepresenter({"X-Bkapi-Request-Id": "abcdef"}), + ) + assert err.request_method == expected + + @pytest.mark.parametrize( + "request_, expected", + [ + (None, ""), + ({"url": "http://example.com/test?foo=bar"}, "http://example.com/test"), + ] + ) + def test_request_url(self, mocker, faker, request_, expected): + err = exceptions.ResponseError( + faker.pystr(), + request=request_ and mocker.MagicMock(**request_), + response_headers_representer=ResponseHeadersRepresenter({"X-Bkapi-Request-Id": "abcdef"}), + ) + assert err.request_url == expected + + @pytest.mark.parametrize( + "response, expected", + [ + (None, None), + ({"status_code": 200}, 200), + ] + ) + def test_request_status_code(self, mocker, faker, response, expected): + err = exceptions.ResponseError( + faker.pystr(), + response=response and mocker.MagicMock(**response), + response_headers_representer=ResponseHeadersRepresenter({"X-Bkapi-Request-Id": "abcdef"}), + ) + assert err.response_status_code == expected diff --git a/sdks/bkapi-client-core/tests/test_utils.py b/sdks/bkapi-client-core/tests/test_utils.py index f7ebf49e..4d23a6af 100644 --- a/sdks/bkapi-client-core/tests/test_utils.py +++ b/sdks/bkapi-client-core/tests/test_utils.py @@ -9,6 +9,7 @@ * specific language governing permissions and limitations under the License. """ import pytest +import requests from bkapi_client_core import utils @@ -42,10 +43,11 @@ def test_to_curl(mocker, curlify, request_, expected): class TestCurlRequest: - def test_str(self, mocker): - curlify = mocker.patch.object(utils, "curlify") - curlify.to_curl.return_value = "curl http://example.com" - - request = mocker.MagicMock(url="http://example.com") - result = utils.CurlRequest(request) - assert str(result) == "curl http://example.com" + def test_str(self): + request = requests.Request("GET", "https://example.com/get").prepare() + result = utils.CurlRequest(request).to_curl() + assert result == "curl -X GET https://example.com/get" + + request = requests.Request("GET", "https://example.com/get", params={"foo": "bar"}, headers={"x-token": "test"}).prepare() + result = utils.CurlRequest(request).to_curl() + assert result == "curl -X GET 'https://example.com/get?foo=bar'" \ No newline at end of file