def _botocore_error_serializer_integration_test( service: str, action: str, exception: ServiceException, code: str, status_code: int, message: Optional[str], is_sender_fault: bool = False, ): """ Performs an integration test for the error serialization using botocore as parser. It executes the following steps: - Load the given service (f.e. "sqs") - Serialize the _error_ response with the appropriate serializer from the AWS Serivce Framework - Parse the serialized error response using the botocore parser - Checks the the metadata is correct (status code, requestID,...) - Checks if the parsed error response content is correct :param service: to load the correct service specification, serializer, and parser :param action: to load the correct service specification, serializer, and parser :param exception: which should be serialized and tested against :param code: expected "code" of the exception (i.e. the AWS specific exception ID, f.e. "CloudFrontOriginAccessIdentityAlreadyExists") :param status_code: expected HTTP response status code :param message: expected error message :return: None """ # Load the appropriate service service = load_service(service) # Use our serializer to serialize the response response_serializer = create_serializer(service) serialized_response = response_serializer.serialize_error_to_response( exception, service.operation_model(action)) # Use the parser from botocore to parse the serialized response response_parser: ResponseParser = create_parser(service.protocol) parsed_response = response_parser.parse( serialized_response.to_readonly_response_dict(), service.operation_model(action).output_shape, ) # Check if the result is equal to the initial response params assert "Error" in parsed_response assert "Code" in parsed_response["Error"] assert "Message" in parsed_response["Error"] assert parsed_response["Error"]["Code"] == code assert parsed_response["Error"]["Message"] == message assert "ResponseMetadata" in parsed_response assert "RequestId" in parsed_response["ResponseMetadata"] assert len(parsed_response["ResponseMetadata"]["RequestId"]) == 52 assert "HTTPStatusCode" in parsed_response["ResponseMetadata"] assert parsed_response["ResponseMetadata"]["HTTPStatusCode"] == status_code type = parsed_response["Error"].get("Type") if is_sender_fault: assert type == "Sender" else: assert type is None
def _botocore_serializer_integration_test( service: str, action: str, response: dict, status_code=200, expected_response_content: dict = None, ): """ Performs an integration test for the serializer using botocore as parser. It executes the following steps: - Load the given service (f.e. "sqs") - Serialize the response with the appropriate serializer from the AWS Serivce Framework - Parse the serialized response using the botocore parser - Checks if the metadata is correct (status code, requestID,...) - Checks if the parsed response content is equal to the input to the serializer :param service: to load the correct service specification, serializer, and parser :param action: to load the correct service specification, serializer, and parser :param response: which should be serialized and tested against :param status_code: Optional - expected status code of the response - defaults to 200 :param expected_response_content: Optional - if the input data ("response") differs from the actually expected data (because f.e. it contains None values) :return: None """ # Load the appropriate service service = load_service(service) # Use our serializer to serialize the response response_serializer = create_serializer(service) # The serializer changes the incoming dict, therefore copy it before passing it to the serializer response_to_parse = copy.deepcopy(response) serialized_response = response_serializer.serialize_to_response( response_to_parse, service.operation_model(action)) # Use the parser from botocore to parse the serialized response response_parser = create_parser(service.protocol) parsed_response = response_parser.parse( serialized_response.to_readonly_response_dict(), service.operation_model(action).output_shape, ) return_response = copy.deepcopy(parsed_response) # Check if the result is equal to the initial response params assert "ResponseMetadata" in parsed_response assert "HTTPStatusCode" in parsed_response["ResponseMetadata"] assert parsed_response["ResponseMetadata"]["HTTPStatusCode"] == status_code assert "RequestId" in parsed_response["ResponseMetadata"] assert len(parsed_response["ResponseMetadata"]["RequestId"]) == 52 del parsed_response["ResponseMetadata"] if expected_response_content is None: expected_response_content = response if expected_response_content is not _skip_assert: assert parsed_response == expected_response_content return return_response
def test_json_protocol_content_type_1_1(): """Logs defines the jsonVersion 1.1, therefore the Content-Type needs to be application/x-amz-json-1.1.""" service = load_service("logs") response_serializer = create_serializer(service) result: Response = response_serializer.serialize_to_response( {}, service.operation_model("DeleteLogGroup")) assert result is not None assert result.content_type is not None assert result.content_type == "application/x-amz-json-1.1"
def test_json_protocol_content_type_1_0(): """AppRunner defines the jsonVersion 1.0, therefore the Content-Type needs to be application/x-amz-json-1.0.""" service = load_service("apprunner") response_serializer = create_serializer(service) result: Response = response_serializer.serialize_to_response( {}, service.operation_model("DeleteConnection")) assert result is not None assert result.content_type is not None assert result.content_type == "application/x-amz-json-1.0"
def __init__(self, service: ServiceModel, implementation: Union[Any, DispatchTable]): self.service = service self.parser = create_parser(service) self.serializer = create_serializer(service) if isinstance(implementation, dict): self.dispatch_table = implementation else: self.dispatch_table = create_dispatch_table(implementation)
def test_no_mutation_of_parameters(): service = load_service("appconfig") response_serializer = create_serializer(service) parameters = { "ApplicationId": "app_id", "ConfigurationProfileId": "conf_id", "VersionNumber": 1, "Content": b'{"Id":"foo"}', "ContentType": "application/json", } expected = parameters.copy() # serialize response and check whether parameters are unchanged _ = response_serializer.serialize_to_response( parameters, service.operation_model("CreateHostedConfigurationVersion")) assert parameters == expected
def test_query_protocol_error_serialization_plain(): # Specific error of the ChangeMessageVisibility operation in SQS as the scaffold would generate it class ReceiptHandleIsInvalid(ServiceException): pass exception = ReceiptHandleIsInvalid( 'The input receipt handle "garbage" is not a valid receipt handle.') # Load the SQS service service = load_service("sqs") # Use our serializer to serialize the response response_serializer = create_serializer(service) serialized_response = response_serializer.serialize_error_to_response( exception, service.operation_model("ChangeMessageVisibility")) serialized_response_dict = serialized_response.to_readonly_response_dict() # Replace the random request ID with a static value for comparison serialized_response_body = re.sub( "<RequestId>.*</RequestId>", "<RequestId>static_request_id</RequestId>", to_str(serialized_response_dict["body"]), ) # This expected_response_body differs from the actual response in the following ways: # - The original response does not define an encoding. # - There is no newline after the XML declaration. # - The response does not contain a Type nor Detail tag (since they aren't contained in the spec). # - The original response uses double quotes for the xml declaration. # Most of these differences should be handled equally by parsing clients, however, we might adopt some of these # changes in the future. expected_response_body = ( "<?xml version='1.0' encoding='utf-8'?>\n" '<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">' "<Error>" "<Code>ReceiptHandleIsInvalid</Code>" "<Message>The input receipt handle "garbage" is not a valid receipt handle." "</Message>" "</Error>" "<RequestId>static_request_id</RequestId>" "</ErrorResponse>") assert serialized_response_body == expected_response_body assert serialized_response_dict["headers"].get("Content-Type") is not None assert serialized_response_dict["headers"]["Content-Type"] == "text/xml"
from localstack.aws.api import CommonServiceException from localstack.aws.protocol.parser import OperationNotFoundParserError, create_parser from localstack.aws.protocol.serializer import create_serializer from localstack.aws.protocol.validate import MissingRequiredField, validate_request from localstack.aws.spec import load_service from localstack.http import Request, Response, Router, route from localstack.http.dispatcher import Handler from localstack.services.sqs.provider import MissingParameter from localstack.utils.aws import aws_stack from localstack.utils.aws.request_context import extract_region_from_headers LOG = logging.getLogger(__name__) service = load_service("sqs") parser = create_parser(service) serializer = create_serializer(service) @route( '/queue/<regex("[a-z0-9-]+"):region>/<regex("[0-9]{12}"):account_id>/<regex("[a-zA-Z0-9_-]+(.fifo)?"):queue_name>', methods=["POST", "GET"], ) def path_strategy_handler(request: Request, region, account_id: str, queue_name: str): return handle_request(request, region) @route( '/<regex("[0-9]{12}"):account_id>/<regex("[a-zA-Z0-9_-]+(.fifo)?"):queue_name>', host='<regex("([a-z0-9-]+\\.)?"):region>queue.localhost.localstack.cloud<regex("(:[0-9]{2,5})?"):port>', methods=["POST", "GET"], )