Пример #1
0
    def test_error_from_headers(self):
        exc = CustomError("some error message", error_data={"key": "value"})
        headers = dict()

        error_info, _ = Error.from_exception(exc)
        error_info.to_headers(headers)

        from_headers = Error.from_headers(headers)

        assert from_headers == error_info
Пример #2
0
    def test_error_from_headers_no_data(self):
        exc = CustomError("some error message")
        headers = dict()

        error_info, _ = Error.from_exception(exc)
        error_info.to_headers(headers)

        from_headers = Error.from_headers(headers)

        assert from_headers == error_info
Пример #3
0
def validate_error(response: requests.Response,
                   error_type: Type[APIError]) -> Error:
    """
    Validates response contains correct error info, prints response and headers for
    test logs.

    :param response: from test client.
    :param error_type: APIError class that returned error should correspond to.

    :raises NoErrorReturnedError: No error information in response headers.
    :raises StatusMismatchError: Response http code does not match ``error_type``.
    :raises WrongExceptionError: Error data does not match ``error_type``.

    :return: error data model.

    Response status code and data are printed to stdout for log capture.

    All exceptions are inherited from :class:`ResponseValidationError`
    """
    _print_response_data(response)

    error = Error.from_headers(response.headers)

    try:
        assert error.name == error_type.__name__
        assert error.code == error_type.api_code
        assert error.message
        assert isinstance(error.id, uuid.UUID)
    except AssertionError:
        raise WrongExceptionError(
            f"Expected {error_type.__name__}. Got {error.name}")

    _validate_status(response, error_type.http_code)

    return error
Пример #4
0
    def test_to_exception_error(self):
        exc = CustomError("some error message", error_data={"key": "value"})

        error_info, _ = Error.from_exception(exc)

        with pytest.raises(InvalidAPIErrorCodeError):
            error_info.to_exception()
Пример #5
0
    def test_to_headers_no_data(self):
        exc = CustomError("some error message")
        headers = dict()

        error_info, _ = Error.from_exception(exc)
        error_info.to_headers(headers)

        assert "error-data" not in headers
Пример #6
0
    def test_to_exception(self):
        exc = errors_api.APILimitError("some error message",
                                       error_data={"key": "value"})

        error_info, _ = Error.from_exception(exc)
        exc_generated = error_info.to_exception()

        assert type(exc_generated) is errors_api.APILimitError
        assert exc_generated.api_code == exc.api_code
        assert exc_generated.error_data == exc.error_data
        assert str(exc_generated) == str(exc)
Пример #7
0
    def test_from_exception_api(self):
        exc = CustomError("some error message", error_data={"key": "value"})
        error_info, exc_returned = Error.from_exception(exc)

        assert exc_returned is exc

        assert error_info.name == CustomError.__name__
        assert error_info.code == CustomError.api_code
        assert error_info.data == exc.error_data
        assert error_info.id == exc.id
        assert error_info.message == str(exc)
Пример #8
0
    def test_to_exception_custom(self):
        exc = CustomError("some error message", error_data={"key": "value"})

        error_info, _ = Error.from_exception(exc)
        exc_generated = error_info.to_exception(
            errors_additional={CustomError.api_code: CustomError})

        assert type(exc_generated) is CustomError
        assert exc_generated.api_code == exc.api_code
        assert exc_generated.error_data == exc.error_data
        assert str(exc_generated) == str(exc)
Пример #9
0
    def test_to_headers(self):
        exc = CustomError("some error message", error_data={"key": "value"})
        headers = dict()

        error_info, _ = Error.from_exception(exc)
        error_info.to_headers(headers)

        assert headers["error-name"] == CustomError.__name__
        assert headers["error-message"] == str(exc)
        assert headers["error-id"] == str(exc.id)
        assert headers["error-code"] == str(CustomError.api_code)
        assert headers["error-data"] == json.dumps({"key": "value"})
Пример #10
0
    def test_from_exception_non_api(self):

        exc = ValueError("some error message")
        error_info, exc_returned = Error.from_exception(exc)

        assert exc_returned is not exc
        assert type(exc_returned) is errors_api.APIError

        assert error_info.name == errors_api.APIError.__name__
        assert error_info.code == errors_api.APIError.api_code
        assert error_info.id == exc_returned.id
        assert error_info.message == "An unknown error occurred."
Пример #11
0
def _handle_route_error(exc: BaseException, req: Request, resp: Response) -> None:
    error_data, exc_api = Error.from_exception(exc)

    # Set the response status code
    resp.status_code = exc_api.http_code

    # Set the header error info
    error_data.to_headers(resp.headers)

    sys.stderr.write(f'ERROR: ({error_data.id}) - {error_data.name} "{exc_api}"\n')
    traceback.print_exc(file=sys.stderr)

    if exc_api.send_media and not isinstance(exc_api, DumpErrors):
        try:
            resp._dump_media()
        except DumpErrors:
            resp.content = b""
    else:
        resp.content = b""
Пример #12
0
 def mock_exception(self, exc_base: BaseException) -> None:
     """Mock spanserver-style exception headers."""
     self._exception = exc_base
     error_data, exc = Error.from_exception(exc_base)
     error_data.to_headers(self.headers)
     self.status = exc.http_code
Пример #13
0
    def test_error_from_headers_no_error(self):
        headers = dict()

        with pytest.raises(NoErrorReturnedError):
            Error.from_headers(headers)
Пример #14
0
async def handle_response_aio(
    response: ClientResponse,
    valid_status_codes: Union[int, Tuple[int, ...]] = 200,
    data_schema: Optional[Union[Schema, MimeType]] = None,
    api_errors_additional: Optional[Dict[int, Type[APIError]]] = None,
    current_data_object: Optional[ModelType] = None,
    data_object_updater: Optional[Callable[[ModelType, Any], None]] = None,
    decoders: DecoderIndexType = DEFAULT_DECODERS,
) -> ResponseData:
    """
    Examines response from SpanReed service and raises reported errors.

    :param response: from aiohttp
    :param valid_status_codes: Valid return http code(s).
    :param data_schema: Schema object for loading responses.
    :param api_errors_additional: Code, Error Class Mapping of Additional APIError types
        the response may return.
    :param current_data_object: Current object which represents response payload. Will
        be updated in-place with response data.
    :param data_object_updater: Callable which takes args:
        (current_data_object, new_data_object). Used to update current_data_object
        in place of the default updater.

    :return: Loaded data, raw data mapping (dict or bson record).

    :raises ResponseStatusError: If status code does match.
    :raises ContentTypeUnknownError: If content-type is not a type that is known.
    :raises marshmallow.ValidationError: If data not consistent with schema.
    """

    # Try to raise error, catch if it does not exist.
    try:
        raise Error.from_headers(response.headers).to_exception(api_errors_additional)
    except NoErrorReturnedError:
        pass

    _check_status_code(
        received_code=response.status,
        valid_status_codes=valid_status_codes,
        response=response,
    )

    content = await response.read()

    if content or data_schema is not None:
        try:
            loaded_data, decoded_data = decode_content(
                content=content,
                mimetype=MimeType.from_headers(response.headers),
                data_schema=data_schema,
                allow_sniff=True,
                decoders=decoders,
            )
        except ContentDecodeBase as error:
            raise ContentDecodeError(str(error), response=response)
        except ContentTypeUnknownBase as error:
            raise ContentTypeUnknownError(str(error), response=response)
    else:
        loaded_data, decoded_data = None, None

    if current_data_object is not None:
        _update_data(
            current_data_object=current_data_object,
            new_data_object=loaded_data,
            object_updater=data_object_updater,
        )
        loaded_data = current_data_object

    return ResponseData(resp=response, loaded=loaded_data, decoded=decoded_data)