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
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
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
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()
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
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)
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)
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)
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"})
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."
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""
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
def test_error_from_headers_no_error(self): headers = dict() with pytest.raises(NoErrorReturnedError): Error.from_headers(headers)
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)