From 9b7cb32e10d571a73fd6fe1aa741d1cb3b28ad70 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Thu, 5 Sep 2024 17:08:24 -0700 Subject: [PATCH 1/9] Add smithy generated response parsing protocol tests --- tests/unit/protocols/output/ec2.json | 2421 +++++++-- tests/unit/protocols/output/json.json | 2966 +++++++--- tests/unit/protocols/output/json_1_0.json | 1157 ++++ tests/unit/protocols/output/query.json | 3252 ++++++++--- tests/unit/protocols/output/rest-json.json | 5563 ++++++++++++++----- tests/unit/protocols/output/rest-xml.json | 5747 +++++++++++++++----- 6 files changed, 16310 insertions(+), 4796 deletions(-) create mode 100644 tests/unit/protocols/output/json_1_0.json diff --git a/tests/unit/protocols/output/ec2.json b/tests/unit/protocols/output/ec2.json index fa21de0ace..0a52651d08 100644 --- a/tests/unit/protocols/output/ec2.json +++ b/tests/unit/protocols/output/ec2.json @@ -1,612 +1,1847 @@ [ - { - "description": "Scalar members", - "metadata": { - "protocol": "ec2" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType", - "locationName": "FooNum" - }, - "FalseBool": { - "shape": "BooleanType" - }, - "TrueBool": { - "shape": "BooleanType" - }, - "Float": { - "shape": "FloatType" - }, - "Double": { - "shape": "DoubleType" - }, - "Long": { - "shape": "LongType" - }, - "Char": { - "shape": "CharType" - } - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "FloatType": { - "type": "float" - }, - "DoubleType": { - "type": "double" - }, - "LongType": { - "type": "long" - }, - "CharType": { - "type": "character" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Str": "myname", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "myname123falsetrue1.21.3200arequest-id" - } - } - ] - }, - { - "description": "Blob", - "metadata": { - "protocol": "ec2" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Blob": { - "shape": "BlobType" - } - } - }, - "BlobType": { - "type": "blob" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Blob": "value" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "dmFsdWU=requestid" - } - } - ] - }, - { - "description": "Lists", - "metadata": { - "protocol": "ec2" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for DatetimeOffsets operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "Ec2QueryDateTimeWithNegativeOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2019-12-16T22:48:18-01:00\n requestid\n\n" + } + }, + { + "id": "Ec2QueryDateTimeWithPositiveOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2019-12-17T00:48:18+01:00\n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "List with custom member name", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for EmptyInputAndEmptyOutput operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "Ec2QueryEmptyInputAndEmptyOutput", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response members.

While this should be rare, code generators must support this.

" + }, + "description": "Empty output", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n requestid\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType", - "locationName": "item" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for FractionalSeconds operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "Ec2QueryDateTimeWithFractionalSeconds", + "given": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FractionalSecondsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", + "result": { + "datetime": 9.46845296123E8 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2000-01-02T20:34:56.123Z\n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "Flattened List", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "Ec2GreetingWithErrors", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
" + }, + "description": "Ensures that operations with errors successfully know how to deserialize the successful response", + "result": { + "greeting": "Hello" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n Hello\n requestid\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType", - "flattened": true - } - } - }, - "ListType": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "Ec2InvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
", + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple XML errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n \n InvalidGreeting\n Hi\n \n \n foo-id\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "Normal map", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "Ec2ComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
", + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "errorCode": "ComplexError", + "error": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n \n ComplexError\n Hi\n Top level\n \n bar\n \n \n \n foo-id\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "MapType" - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StructureType" - } - }, - "StructureType": { - "type": "structure", - "members": { - "foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for IgnoresWrappingXmlName operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "IgnoresWrappingXmlNameOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + } + }, + "locationName": "IgnoreMe" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "Ec2IgnoresWrappingXmlName", + "given": { + "name": "IgnoresWrappingXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "IgnoresWrappingXmlNameOutput" + }, + "documentation": "

The xmlName trait on the output structure is ignored in AWS Query.

The wrapping element is always operation name + "Response".

" + }, + "description": "The xmlName trait on the output structure is ignored in the ec2 protocol", + "result": { + "foo": "bar" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n bar\n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": { - "foo": "bar" - }, - "baz": { - "foo": "bam" - } - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Flattened map", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for NoInputAndOutput operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "Ec2QueryNoInputAndOutput", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request payload or response members.

While this should be rare, code generators must support this.

" + }, + "description": "Empty output", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n requestid\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "MapType", - "flattened": true - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for RecursiveXmlShapes operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "RecursiveXmlShapesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + }, + "RecursiveXmlShapesOutputNested1": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "nested": { + "shape": "RecursiveXmlShapesOutputNested2" + } + } + }, + "String": { + "type": "string" + }, + "RecursiveXmlShapesOutputNested2": { + "type": "structure", + "members": { + "bar": { + "shape": "String" + }, + "recursiveMember": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + } + }, + "cases": [ + { + "id": "Ec2RecursiveShapes", + "given": { + "name": "RecursiveXmlShapes", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "RecursiveXmlShapesOutput" + }, + "documentation": "

Recursive shapes

" + }, + "description": "Serializes recursive structures", + "result": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n Foo1\n \n Bar1\n \n Foo2\n \n Bar2\n \n \n \n \n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Named map", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for SimpleScalarXmlProperties operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "SimpleScalarXmlPropertiesOutput": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "emptyStringValue": { + "shape": "String" + }, + "trueBooleanValue": { + "shape": "Boolean" + }, + "falseBooleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double", + "locationName": "DoubleDribble" + } + } + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } + }, + "cases": [ + { + "id": "Ec2SimpleScalarProperties", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Serializes simple scalar properties", + "result": { + "stringValue": "string", + "emptyStringValue": "", + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n string\n \n true\n false\n 1\n 2\n 3\n 4\n 5.5\n 6.5\n requestid\n\n" + } + }, + { + "id": "Ec2QuerySupportsNaNFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n NaN\n NaN\n\n" + } + }, + { + "id": "Ec2QuerySupportsInfinityFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n Infinity\n Infinity\n\n" + } + }, + { + "id": "Ec2QuerySupportsNegativeInfinityFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n -Infinity\n -Infinity\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "MapType", - "flattened": true - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType", - "locationName": "foo" - }, - "value": { - "shape": "StringType", - "locationName": "bar" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlBlobs operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlBlobsOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "Ec2XmlBlobs", + "given": { + "name": "XmlBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Blobs are base64 encoded", + "result": { + "data": "value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n dmFsdWU=\n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Empty string", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for XmlEmptyBlobs operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlBlobsOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "Ec2XmlEmptyBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + } + }, + "description": "Empty blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n requestid\n\n" + } + }, + { + "id": "Ec2XmlEmptySelfClosedBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + } + }, + "description": "Empty self closed blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n requestid\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlEmptyLists operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlListsOutput": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "Ec2XmlEmptyLists", + "given": { + "name": "XmlEmptyLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput" + } + }, + "description": "Deserializes empty XML lists", + "result": { + "stringList": [], + "stringSet": [] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Foo": "" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "requestid" - } - } - ] - }, - { - "description": "Timestamp members", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for XmlEnums operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlEnumsOutput": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "Ec2XmlEnums", + "given": { + "name": "XmlEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlEnumsOutput" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

" + }, + "description": "Serializes simple scalar properties", + "result": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n Foo\n 0\n 1\n \n Foo\n 0\n \n \n Foo\n 0\n \n \n \n hi\n Foo\n \n \n zero\n 0\n \n \n requestid\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "TimeArg": { - "shape": "TimestampType" - }, - "TimeCustom": { - "timestampFormat": "rfc822", - "shape": "TimestampType" - }, - "TimeFormat": { - "shape": "TimestampFormatType" - }, - "StructMember": { - "shape": "TimeContainer" - } - } - }, - "TimeContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "TimestampType" - }, - "bar": { - "shape": "TimestampFormatType" - } - } - }, - "TimestampFormatType": { - "timestampFormat": "unixTimestamp", - "type": "timestamp" - }, - "TimestampType": { - "type": "timestamp" - } + { + "description": "Test cases for XmlIntEnums operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlIntEnumsOutput": { + "type": "structure", + "members": { + "intEnum1": { + "shape": "IntegerEnum" + }, + "intEnum2": { + "shape": "IntegerEnum" + }, + "intEnum3": { + "shape": "IntegerEnum" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "intEnumSet": { + "shape": "IntegerEnumSet" + }, + "intEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "Ec2XmlIntEnums", + "given": { + "name": "XmlIntEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlIntEnumsOutput" + }, + "documentation": "

This example serializes intEnums as top level properties, in lists, sets, and maps.

" + }, + "description": "Serializes simple scalar properties", + "result": { + "intEnum1": 1, + "intEnum2": 2, + "intEnum3": 3, + "intEnumList": [ + 1, + 2 + ], + "intEnumSet": [ + 1, + 2 + ], + "intEnumMap": { + "a": 1, + "b": 2 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 1\n 2\n 3\n \n 1\n 2\n \n \n 1\n 2\n \n \n \n a\n 1\n \n \n b\n 2\n \n \n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "TimeArg": 1398796238, - "TimeCustom": 1398796238, - "TimeFormat": 1398796238, - "StructMember": { - "foo": 1398796238, - "bar": 1398796238 - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "2014-04-29T18:30:38+00:0013987962382014-04-29T18:30:38+00:00Tue, 29 Apr 2014 18:30:38 GMT1398796238requestid" - } - } - ] - }, - { - "description": "Modeled exceptions", - "metadata": { - "protocol": "ec2" + { + "description": "Test cases for XmlLists operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlListsOutput": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "Ec2XmlLists", + "given": { + "name": "XmlLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput" + }, + "documentation": "

This test case serializes XML lists for the following cases for both input and output:

  1. Normal XML lists.
  2. Normal XML sets.
  3. XML lists of lists.
  4. XML lists with @xmlName on its members
  5. Flattened XML lists.
  6. Flattened XML lists with @xmlName.
  7. Flattened XML lists with @xmlNamespace.
  8. Lists of structures.
" + }, + "description": "Tests for XML list serialization", + "result": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238, + 1398796238 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "renamedListMembers": [ + "foo", + "bar" + ], + "flattenedList": [ + "hi", + "bye" + ], + "flattenedList2": [ + "yep", + "nope" + ], + "flattenedListWithMemberNamespace": [ + "a", + "b" + ], + "flattenedListWithNamespace": [ + "a", + "b" + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n foo\n bar\n \n \n foo\n bar\n \n \n 1\n 2\n \n \n true\n false\n \n \n 2014-04-29T18:30:38Z\n 2014-04-29T18:30:38Z\n \n \n Foo\n 0\n \n \n 1\n 2\n \n \n \n foo\n bar\n \n \n baz\n qux\n \n \n \n foo\n bar\n \n hi\n bye\n yep\n nope\n a\n b\n a\n b\n \n \n 1\n 2\n \n \n 3\n 4\n \n \n requestid\n\n" + } + } + ] }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "OtherExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - } - } - }, - "StatusShape": { - "type": "integer" - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlNamespaces operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlNamespacesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "XmlNamespaceNested" + } + }, + "xmlNamespace": "http://foo.com" + }, + "XmlNamespaceNested": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "xmlNamespace": { + "prefix": "baz", + "uri": "http://baz.com" + } + }, + "values": { + "shape": "XmlNamespacedList", + "xmlNamespace": "http://qux.com" + } + }, + "xmlNamespace": "http://foo.com" + }, + "String": { + "type": "string" + }, + "XmlNamespacedList": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "http://bux.com" + } + } + }, + "cases": [ + { + "id": "Ec2XmlNamespaces", + "given": { + "name": "XmlNamespaces", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlNamespacesOutput" + } + }, + "description": "Serializes XML namespaces", + "result": { + "nested": { + "foo": "Foo", + "values": [ + "Bar", + "Baz" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n \n Foo\n \n Bar\n Baz\n \n \n requestid\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "ExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "OtherExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": {}, - "errorCode": "UndefinedShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "UndefinedShapemymessagemybody" - } - } - ] - } + { + "description": "Test cases for XmlTimestamps operation", + "metadata": { + "protocol": "ec2", + "protocols": [ + "ec2" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlTimestampsOutput": { + "type": "structure", + "members": { + "normal": { + "shape": "Timestamp" + }, + "dateTime": { + "shape": "SyntheticTimestamp_date_time" + }, + "dateTimeOnTarget": { + "shape": "DateTime" + }, + "epochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds" + }, + "epochSecondsOnTarget": { + "shape": "EpochSeconds" + }, + "httpDate": { + "shape": "SyntheticTimestamp_http_date" + }, + "httpDateOnTarget": { + "shape": "HttpDate" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + } + }, + "cases": [ + { + "id": "Ec2XmlTimestamps", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Tests how normal timestamps are serialized", + "result": { + "normal": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2014-04-29T18:30:38Z\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithDateTimeFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time works like normal timestamps", + "result": { + "dateTime": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2014-04-29T18:30:38Z\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithDateTimeOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time on the target shape works like normal timestamps", + "result": { + "dateTimeOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 2014-04-29T18:30:38Z\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithEpochSecondsFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds works", + "result": { + "epochSeconds": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 1398796238\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithEpochSecondsOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds on the target shape works", + "result": { + "epochSecondsOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n 1398796238\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithHttpDateFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date works", + "result": { + "httpDate": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n Tue, 29 Apr 2014 18:30:38 GMT\n requestid\n\n" + } + }, + { + "id": "Ec2XmlTimestampsWithHttpDateOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date on the target shape works", + "result": { + "httpDateOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml;charset=UTF-8" + }, + "body": "\n Tue, 29 Apr 2014 18:30:38 GMT\n requestid\n\n" + } + } + ] + } ] diff --git a/tests/unit/protocols/output/json.json b/tests/unit/protocols/output/json.json index c463aac2bc..8b2ab6a13a 100644 --- a/tests/unit/protocols/output/json.json +++ b/tests/unit/protocols/output/json.json @@ -1,824 +1,2218 @@ [ - { - "description": "Scalar members", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType" - }, - "FalseBool": { - "shape": "BooleanType" - }, - "TrueBool": { - "shape": "BooleanType" - }, - "Float": { - "shape": "FloatType" - }, - "Double": { - "shape": "DoubleType" - }, - "Long": { - "shape": "LongType" - }, - "Char": { - "shape": "CharType" - } - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "FloatType": { - "type": "float" - }, - "DoubleType": { - "type": "double" - }, - "LongType": { - "type": "long" - }, - "CharType": { - "type": "character" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for DatetimeOffsets operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "Str": "myname", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a" + "shapes": { + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"Str\": \"myname\", \"Num\": 123, \"FalseBool\": false, \"TrueBool\": true, \"Float\": 1.2, \"Double\": 1.3, \"Long\": 200, \"Char\": \"a\"}" - } - } - ] - }, - { - "description": "Blob members", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "BlobMember": { - "shape": "BlobType" - }, - "StructMember": { - "shape": "BlobContainer" - } - } - }, - "BlobType": { - "type": "blob" - }, - "BlobContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "BlobType" - } - } - } + "cases": [ + { + "id": "AwsJson11DateTimeWithNegativeOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": " {\n \"datetime\": \"2019-12-16T22:48:18-01:00\"\n }\n" + } + }, + { + "id": "AwsJson11DateTimeWithPositiveOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": " {\n \"datetime\": \"2019-12-17T00:48:18+01:00\"\n }\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "BlobMember": "hi!", - "StructMember": { - "foo": "there!" - } + { + "description": "Test cases for EmptyOperation operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"BlobMember\": \"aGkh\", \"StructMember\": {\"foo\": \"dGhlcmUh\"}}" - } - } - ] - }, - { - "description": "Timestamp members", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "TimeArg": { - "shape": "TimestampType" - }, - "TimeCustom": { - "timestampFormat": "rfc822", - "shape": "TimestampType" - }, - "TimeFormat": { - "shape": "TimestampFormatType" - }, - "StructMember": { - "shape": "TimeContainer" - } - } - }, - "TimeContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "TimestampType" - }, - "bar": { - "shape": "TimestampFormatType" - } - } - }, - "TimestampFormatType": { - "timestampFormat": "iso8601", - "type": "timestamp" - }, - "TimestampType": { - "type": "timestamp" - } + "shapes": {}, + "cases": [ + { + "id": "handles_empty_output_shape", + "given": { + "name": "EmptyOperation", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "description": "When no output is defined, the service is expected to return\nan empty payload, however, client must ignore a JSON payload\nif one is returned. This ensures that if output is added later,\nthen it will not break the client.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{}" + } + }, + { + "id": "handles_unexpected_json_output", + "given": { + "name": "EmptyOperation", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "description": "This client-only test builds on handles_empty_output_shape,\nby including unexpected fields in the JSON. A client\nneeds to ignore JSON output that is empty or that contains\nJSON object data.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"foo\": true\n}" + } + }, + { + "id": "json_1_1_service_responds_with_no_payload", + "given": { + "name": "EmptyOperation", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "description": "When no output is defined, the service is expected to return\nan empty payload. Despite the lack of a payload, the service\nis expected to always send a Content-Type header. Clients must\nhandle cases where a service returns a JSON object and where\na service returns no JSON at all.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for FractionalSeconds operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "TimeArg": 1398796238, - "TimeCustom": 1398796238, - "TimeFormat": 1398796238, - "StructMember": { - "foo": 1398796238, - "bar": 1398796238 - } + "shapes": { + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"TimeArg\": 1398796238, \"TimeCustom\": \"Tue, 29 Apr 2014 18:30:38 GMT\", \"TimeFormat\": \"2014-04-29T18:30:38+00:00\", \"StructMember\": {\"foo\": 1398796238, \"bar\": \"2014-04-29T18:30:38+00:00\"}}" - } - } - ] - }, - { - "description": "Lists", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType" - }, - "ListMemberMap": { - "shape": "ListTypeMap" - }, - "ListMemberStruct": { - "shape": "ListTypeStruct" - } - } - }, - "ListType": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "ListTypeMap": { - "type": "list", - "member": { - "shape": "MapType" - } - }, - "ListTypeStruct": { - "type": "list", - "member": { - "shape": "StructType" - } - }, - "StringType": { - "type": "string" - }, - "StructType": { - "type": "structure", - "members": { - } - }, - "MapType": { - "type": "string", - "key": { "shape": "StringType" }, - "value": { "shape": "StringType" } - } + "cases": [ + { + "id": "AwsJson11DateTimeWithFractionalSeconds", + "given": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FractionalSecondsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", + "result": { + "datetime": 9.46845296123E8 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": " {\n \"datetime\": \"2000-01-02T20:34:56.123Z\"\n }\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["a", "b"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"ListMember\": [\"a\", \"b\"]}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "ListMember": ["a", null], - "ListMemberMap": [{}, null, null, {}], - "ListMemberStruct": [{}, null, null, {}] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"ListMember\": [\"a\", null], \"ListMemberMap\": [{}, null, null, {}], \"ListMemberStruct\": [{}, null, null, {}]}" - } - } - ] - }, - { - "description": "Maps", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "MapMember": { - "shape": "MapType" - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType" + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "exception": true + }, + "String": { + "type": "string" + } }, - "value": { - "shape": "NumberList" - } - }, - "StringType": { - "type": "string" - }, - "NumberList": { - "type": "list", - "member": { - "shape": "IntegerType" - } - }, - "IntegerType": { - "type": "integer" - } + "cases": [ + { + "id": "AwsJson11InvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple JSON errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"InvalidGreeting\",\n \"Message\": \"Hi\"\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "MapMember": { - "a": [1, 2], - "b": [3, 4] - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"MapMember\": {\"a\": [1, 2], \"b\": [3, 4]}}" - } - } - ] - }, - { - "description": "Ignores extra data", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "StrType": { - "shape": "StrType" - } - } - }, - "StrType": { - "type": "string" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + } }, - "result": {}, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"foo\": \"bar\"}" - } - } - ] - }, - { - "description": "RPC JSON Event Stream", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Payload": {"shape": "EventStream"}, - "InitialResponse": {"shape": "StringType"} - } - }, - "EventStream": { - "type": "structure", - "eventstream": true, - "members": { - "TypeA": {"shape": "TypeAEvent"}, - "TypeB": {"shape": "TypeBEvent"} - } - }, - "TypeAEvent": { - "type": "structure", - "event": true, - "members": { - "Payload": { - "shape": "BlobType", - "eventpayload": true - } - } - }, - "TypeBEvent": { - "type": "structure", - "event": true, - "members": { - "Details": { - "shape": "Details", - "eventpayload": true - } - } - }, - "Details": { - "type": "structure", - "members": { - "StringField": {"shape": "StringType"}, - "IntegerField": {"shape": "IntegerType"} - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BlobType": { - "type": "blob" - } + "cases": [ + { + "id": "AwsJson11ComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "description": "Parses a complex error with no message member", + "errorCode": "ComplexError", + "error": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"ComplexError\",\n \"TopLevel\": \"Top level\",\n \"Nested\": {\n \"Foo\": \"bar\"\n }\n}" + } + }, + { + "id": "AwsJson11EmptyComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "errorCode": "ComplexError", + "error": {}, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"ComplexError\"\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "InitialResponse": "sometext", - "Payload": [ - { - "TypeA": {"Payload": "somebytes"} - }, - { - "TypeB": { - "Details": { - "StringField": "somestring", - "IntegerField": 123 - } - } - } - ] + "shapes": { + "FooError": { + "type": "structure", + "members": {}, + "documentation": "

This error has test cases that test some of the dark corners of Amazon service framework history. It should only be implemented by clients.

", + "exception": true, + "fault": true + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "AAAAfgAAAE/Fo93GDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcAEGluaXRpYWwtcmVzcG9uc2UNOmNvbnRlbnQtdHlwZQcACXRleHQvanNvbnsiSW5pdGlhbFJlc3BvbnNlIjogInNvbWV0ZXh0In32mCSDAAAAbAAAAFPLgkVrDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVR5cGVBDTpjb250ZW50LXR5cGUHABhhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1zb21lYnl0ZXMesj2HAAAAhgAAAEQqNR/SDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVR5cGVCDTpjb250ZW50LXR5cGUHAAl0ZXh0L2pzb257IlN0cmluZ0ZpZWxkIjogInNvbWVzdHJpbmciLCAiSW50ZWdlckZpZWxkIjogMTIzfffGN30=" - } - } - ] - }, - { - "description": "Modeled exceptions", - "metadata": { - "protocol": "json" - }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - }, - "Code": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "OtherExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + "cases": [ + { + "id": "AwsJson11FooErrorUsingXAmznErrorType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Serializes the X-Amzn-ErrorType header. For an example service, see Amazon EKS.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError" + } + } + }, + { + "id": "AwsJson11FooErrorUsingXAmznErrorTypeWithUri", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some X-Amzn-Errortype headers contain URLs. Clients need to split the URL on ':' and take only the first half of the string. For example, 'ValidationException:http://internal.amazon.com/coral/com.amazon.coral.validate/'\nis to be interpreted as 'ValidationException'.\n\nFor an example service see Amazon Polly.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "AwsJson11FooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "X-Amzn-Errortype might contain a URL and a namespace. Client should extract only the shape name. This is a pathalogical case that might not actually happen in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "AwsJson11FooErrorUsingCode", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "This example uses the 'code' property in the output rather than X-Amzn-Errortype. Some services do this though it's preferable to send the X-Amzn-Errortype. Client implementations must first check for the X-Amzn-Errortype and then check for a top-level 'code' property.\n\nFor example service see Amazon S3 Glacier.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"code\": \"FooError\"\n}" + } + }, + { + "id": "AwsJson11FooErrorUsingCodeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"code\": \"aws.protocoltests.restjson#FooError\"\n}" + } + }, + { + "id": "AwsJson11FooErrorUsingCodeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"code\": \"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + }, + { + "id": "AwsJson11FooErrorWithDunderType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"FooError\"\n}" + } + }, + { + "id": "AwsJson11FooErrorWithDunderTypeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"aws.protocoltests.restjson#FooError\"\n}" + } + }, + { + "id": "AwsJson11FooErrorWithDunderTypeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"__type\": \"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" + { + "description": "Test cases for JsonEnums operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "error": { - "BodyMember": "mybody", - "Code": "OtherExceptionShape", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "{ \"__type\": \"ExceptionShape\", \"Code\": \"OtherExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "{ \"__type\": \"OtherExceptionShape\", \"Code\": \"ExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" + "shapes": { + "JsonEnumsInputOutput": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "String": { + "type": "string" + } }, - "error": {}, - "errorCode": "UndefinedShape", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "{ \"__type\": \"UndefinedShape\", \"Code\": \"ExceptionShape\", \"BodyMember\": \"mybody\"}" - } - } - ] - }, - { - "description": "Modeled exceptions with jsonVersion 1.0", - "metadata": { - "protocol": "json", - "jsonVersion": "1.0" - }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + "cases": [ + { + "id": "AwsJson11Enums", + "given": { + "name": "JsonEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonEnumsInputOutput" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"fooEnum1\": \"Foo\",\n \"fooEnum2\": \"0\",\n \"fooEnum3\": \"1\",\n \"fooEnumList\": [\n \"Foo\",\n \"0\"\n ],\n \"fooEnumSet\": [\n \"Foo\",\n \"0\"\n ],\n \"fooEnumMap\": {\n \"hi\": \"Foo\",\n \"zero\": \"0\"\n }\n}" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" + { + "description": "Test cases for JsonUnions operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "error": { - "BodyMember": "mybody", - "Message": "mymessage" + "shapes": { + "UnionInputOutput": { + "type": "structure", + "members": { + "contents": { + "shape": "MyUnion" + } + }, + "documentation": "

A shared structure that contains a single union member.

" + }, + "MyUnion": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "booleanValue": { + "shape": "Boolean" + }, + "numberValue": { + "shape": "Integer" + }, + "blobValue": { + "shape": "Blob" + }, + "timestampValue": { + "shape": "Timestamp" + }, + "enumValue": { + "shape": "FooEnum" + }, + "listValue": { + "shape": "StringList" + }, + "mapValue": { + "shape": "StringMap" + }, + "structureValue": { + "shape": "GreetingStruct" + } + }, + "documentation": "

A union with a representative set of types for members.

", + "union": true + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Blob": { + "type": "blob" + }, + "Timestamp": { + "type": "timestamp" + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + } }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "{ \"__type\": \"FooPrefix#ExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - } - ] - }, - { - "description": "Serialize document with standalone primitive type in a JSON response", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "inlineDocument": { - "shape": "DocumentType" + "cases": [ + { + "id": "AwsJson11DeserializeStringUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a string union value", + "result": { + "contents": { + "stringValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"stringValue\": \"foo\"\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeBooleanUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a boolean union value", + "result": { + "contents": { + "booleanValue": true + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"booleanValue\": true\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeNumberUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a number union value", + "result": { + "contents": { + "numberValue": 1 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"numberValue\": 1\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeBlobUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a blob union value", + "result": { + "contents": { + "blobValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"blobValue\": \"Zm9v\"\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeTimestampUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a timestamp union value", + "result": { + "contents": { + "timestampValue": 1398796238 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"timestampValue\": 1398796238\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeEnumUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes an enum union value", + "result": { + "contents": { + "enumValue": "Foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"enumValue\": \"Foo\"\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeListUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a list union value", + "result": { + "contents": { + "listValue": [ + "foo", + "bar" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"listValue\": [\"foo\", \"bar\"]\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeMapUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a map union value", + "result": { + "contents": { + "mapValue": { + "foo": "bar", + "spam": "eggs" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"mapValue\": {\n \"foo\": \"bar\",\n \"spam\": \"eggs\"\n }\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeStructureUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a structure union value", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + }, + { + "id": "AwsJson11DeserializeIgnoreType", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Ignores an unrecognized __type property", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"contents\": {\n \"__type\": \"aws.protocoltests.json10#MyUnion\",\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "inlineDocument": "foo" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": \"foo\"}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "inlineDocument": 123 - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": 123}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "inlineDocument": 1.2 + { + "description": "Test cases for KitchenSinkOperation operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": 1.2}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "inlineDocument": true - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": true}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "inlineDocument": "" + "shapes": { + "KitchenSink": { + "type": "structure", + "members": { + "Blob": { + "shape": "Blob" + }, + "Boolean": { + "shape": "Boolean" + }, + "Double": { + "shape": "Double" + }, + "EmptyStruct": { + "shape": "EmptyStruct" + }, + "Float": { + "shape": "Float" + }, + "HttpdateTimestamp": { + "shape": "SyntheticTimestamp_http_date" + }, + "Integer": { + "shape": "Integer" + }, + "Iso8601Timestamp": { + "shape": "SyntheticTimestamp_date_time" + }, + "JsonValue": { + "shape": "JsonValue", + "jsonvalue": true + }, + "ListOfLists": { + "shape": "ListOfListOfStrings" + }, + "ListOfMapsOfStrings": { + "shape": "ListOfMapsOfStrings" + }, + "ListOfStrings": { + "shape": "ListOfStrings" + }, + "ListOfStructs": { + "shape": "ListOfStructs" + }, + "Long": { + "shape": "Long" + }, + "MapOfListsOfStrings": { + "shape": "MapOfListsOfStrings" + }, + "MapOfMaps": { + "shape": "MapOfMapOfStrings" + }, + "MapOfStrings": { + "shape": "MapOfStrings" + }, + "MapOfStructs": { + "shape": "MapOfStructs" + }, + "RecursiveList": { + "shape": "ListOfKitchenSinks" + }, + "RecursiveMap": { + "shape": "MapOfKitchenSinks" + }, + "RecursiveStruct": { + "shape": "KitchenSink" + }, + "SimpleStruct": { + "shape": "SimpleStruct" + }, + "String": { + "shape": "String" + }, + "StructWithJsonName": { + "shape": "StructWithJsonName" + }, + "Timestamp": { + "shape": "Timestamp" + }, + "UnixTimestamp": { + "shape": "SyntheticTimestamp_epoch_seconds" + } + } + }, + "Blob": { + "type": "blob" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Double": { + "type": "double", + "box": true + }, + "EmptyStruct": { + "type": "structure", + "members": {} + }, + "Float": { + "type": "float", + "box": true + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "Integer": { + "type": "integer", + "box": true + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "JsonValue": { + "type": "string" + }, + "ListOfListOfStrings": { + "type": "list", + "member": { + "shape": "ListOfStrings" + } + }, + "ListOfMapsOfStrings": { + "type": "list", + "member": { + "shape": "MapOfStrings" + } + }, + "ListOfStrings": { + "type": "list", + "member": { + "shape": "String" + } + }, + "ListOfStructs": { + "type": "list", + "member": { + "shape": "SimpleStruct" + } + }, + "Long": { + "type": "long", + "box": true + }, + "MapOfListsOfStrings": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "ListOfStrings" + } + }, + "MapOfMapOfStrings": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "MapOfStrings" + } + }, + "MapOfStrings": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "MapOfStructs": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "SimpleStruct" + } + }, + "ListOfKitchenSinks": { + "type": "list", + "member": { + "shape": "KitchenSink" + } + }, + "MapOfKitchenSinks": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "KitchenSink" + } + }, + "SimpleStruct": { + "type": "structure", + "members": { + "Value": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + }, + "StructWithJsonName": { + "type": "structure", + "members": { + "Value": { + "shape": "String" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": \"\"}" - } - } - ] - }, - { - "description": "Serialize inline document in a JSON response", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "inlineDocument": { - "shape": "DocumentType" + "cases": [ + { + "id": "parses_operations_with_empty_json_bodies", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses operations with empty JSON bodies", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{}" + } + }, + { + "id": "parses_string_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses string shapes", + "result": { + "String": "string-value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"String\":\"string-value\"}" + } + }, + { + "id": "parses_integer_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses integer shapes", + "result": { + "Integer": 1234 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Integer\":1234}" + } + }, + { + "id": "parses_long_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses long shapes", + "result": { + "Long": 1234567890123456789 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Long\":1234567890123456789}" + } + }, + { + "id": "parses_float_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses float shapes", + "result": { + "Float": 1234.5 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Float\":1234.5}" + } + }, + { + "id": "parses_double_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses double shapes", + "result": { + "Double": 1.2345678912345679E8 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Double\":123456789.12345679}" + } + }, + { + "id": "parses_boolean_shapes_true", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses boolean shapes (true)", + "result": { + "Boolean": true + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Boolean\":true}" + } + }, + { + "id": "parses_boolean_false", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses boolean (false)", + "result": { + "Boolean": false + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Boolean\":false}" + } + }, + { + "id": "parses_blob_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses blob shapes", + "result": { + "Blob": "binary-value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Blob\":\"YmluYXJ5LXZhbHVl\"}" + } + }, + { + "id": "parses_timestamp_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses timestamp shapes", + "result": { + "Timestamp": 946845296 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Timestamp\":946845296}" + } + }, + { + "id": "parses_iso8601_timestamps", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses iso8601 timestamps", + "result": { + "Iso8601Timestamp": 946845296 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"Iso8601Timestamp\":\"2000-01-02T20:34:56Z\"}" + } + }, + { + "id": "parses_httpdate_timestamps", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses httpdate timestamps", + "result": { + "HttpdateTimestamp": 946845296 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"HttpdateTimestamp\":\"Sun, 02 Jan 2000 20:34:56 GMT\"}" + } + }, + { + "id": "parses_list_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses list shapes", + "result": { + "ListOfStrings": [ + "abc", + "mno", + "xyz" + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"ListOfStrings\":[\"abc\",\"mno\",\"xyz\"]}" + } + }, + { + "id": "parses_list_of_map_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses list of map shapes", + "result": { + "ListOfMapsOfStrings": [ + { + "size": "large" + }, + { + "color": "red" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"ListOfMapsOfStrings\":[{\"size\":\"large\"},{\"color\":\"red\"}]}" + } + }, + { + "id": "parses_list_of_list_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses list of list shapes", + "result": { + "ListOfLists": [ + [ + "abc", + "mno", + "xyz" + ], + [ + "hjk", + "qrs", + "tuv" + ] + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"ListOfLists\":[[\"abc\",\"mno\",\"xyz\"],[\"hjk\",\"qrs\",\"tuv\"]]}" + } + }, + { + "id": "parses_list_of_structure_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses list of structure shapes", + "result": { + "ListOfStructs": [ + { + "Value": "value-1" + }, + { + "Value": "value-2" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"ListOfStructs\":[{\"Value\":\"value-1\"},{\"Value\":\"value-2\"}]}" + } + }, + { + "id": "parses_list_of_recursive_structure_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses list of recursive structure shapes", + "result": { + "RecursiveList": [ + { + "RecursiveList": [ + { + "RecursiveList": [ + { + "String": "value" + } + ] + } + ] + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"RecursiveList\":[{\"RecursiveList\":[{\"RecursiveList\":[{\"String\":\"value\"}]}]}]}" + } + }, + { + "id": "parses_map_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses map shapes", + "result": { + "MapOfStrings": { + "size": "large", + "color": "red" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"MapOfStrings\":{\"size\":\"large\",\"color\":\"red\"}}" + } + }, + { + "id": "parses_map_of_list_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses map of list shapes", + "result": { + "MapOfListsOfStrings": { + "sizes": [ + "large", + "small" + ], + "colors": [ + "red", + "green" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"MapOfListsOfStrings\":{\"sizes\":[\"large\",\"small\"],\"colors\":[\"red\",\"green\"]}}" + } + }, + { + "id": "parses_map_of_map_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses map of map shapes", + "result": { + "MapOfMaps": { + "sizes": { + "large": "L", + "medium": "M" + }, + "colors": { + "red": "R", + "blue": "B" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"MapOfMaps\":{\"sizes\":{\"large\":\"L\",\"medium\":\"M\"},\"colors\":{\"red\":\"R\",\"blue\":\"B\"}}}" + } + }, + { + "id": "parses_map_of_structure_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses map of structure shapes", + "result": { + "MapOfStructs": { + "size": { + "Value": "small" + }, + "color": { + "Value": "red" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"MapOfStructs\":{\"size\":{\"Value\":\"small\"},\"color\":{\"Value\":\"red\"}}}" + } + }, + { + "id": "parses_map_of_recursive_structure_shapes", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses map of recursive structure shapes", + "result": { + "RecursiveMap": { + "key-1": { + "RecursiveMap": { + "key-2": { + "RecursiveMap": { + "key-3": { + "String": "value" + } + } + } + } + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\"RecursiveMap\":{\"key-1\":{\"RecursiveMap\":{\"key-2\":{\"RecursiveMap\":{\"key-3\":{\"String\":\"value\"}}}}}}}" + } + }, + { + "id": "parses_the_request_id_from_the_response", + "given": { + "name": "KitchenSinkOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "KitchenSink" + } + }, + "description": "Parses the request id from the response", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1", + "X-Amzn-Requestid": "amazon-uniq-request-id" + }, + "body": "{}" + } } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for NullOperation operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "inlineDocument": {"foo": "bar"} + "shapes": { + "NullOperationInputOutput": { + "type": "structure", + "members": { + "string": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"inlineDocument\": {\"foo\": \"bar\"}}" - } - } - ] - }, - { - "description": "Serialize aggregate documents in a JSON response", - "metadata": { - "protocol": "json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "parentDocument": { - "shape": "DocumentType" + "cases": [ + { + "id": "AwsJson11StructuresDontDeserializeNullValues", + "given": { + "name": "NullOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "NullOperationInputOutput" + } + }, + "description": "Null structure values are dropped", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"string\": null\n}" + } } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + { + "description": "Test cases for PutAndGetInlineDocuments operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "parentDocument": { - "str": "test", - "num": 123, - "float": 1.2, - "bool": true, - "null": "", - "document": {"foo": false}, - "list": ["myname", 321, 1.3, true, "", {"nested": true}, [200, ""]] - } + "shapes": { + "PutAndGetInlineDocumentsInputOutput": { + "type": "structure", + "members": { + "inlineDocument": { + "shape": "Document" + } + } + }, + "Document": { + "type": "structure", + "members": {}, + "document": true + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"parentDocument\": {\"str\": \"test\", \"num\": 123, \"float\": 1.2, \"bool\": true, \"null\": \"\", \"document\": {\"foo\": false}, \"list\": [\"myname\", 321, 1.3, true, \"\", {\"nested\": true}, [200, \"\"]]}}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" + "cases": [ + { + "id": "PutAndGetInlineDocumentsInput", + "given": { + "name": "PutAndGetInlineDocuments", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "PutAndGetInlineDocumentsInputOutput" + }, + "documentation": "

This example serializes an inline document as part of the payload.

" + }, + "description": "Serializes inline documents in a JSON response.", + "result": { + "inlineDocument": { + "foo": "bar" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"inlineDocument\": {\"foo\": \"bar\"}\n}" + } + } + ] + }, + { + "description": "Test cases for SimpleScalarProperties operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" }, - "result": { - "parentDocument": [ - "test", - 123, - 1.2, - true, - "", - {"str": "myname", "num": 321, "float": 1.3, "bool": true, "null": "", "document": {"nested": true}, "list": [200, ""]}, - ["foo", false] - ] + "shapes": { + "SimpleScalarPropertiesInputOutput": { + "type": "structure", + "members": { + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + } + } + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"parentDocument\": [\"test\", 123, 1.2, true, \"\", {\"str\": \"myname\", \"num\": 321, \"float\": 1.3, \"bool\": true, \"null\": \"\", \"document\": {\"nested\": true}, \"list\": [200, \"\"]}, [\"foo\", false]]}" - } - } - ] - } + "cases": [ + { + "id": "AwsJson11SupportsNaNFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + } + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"floatValue\": \"NaN\",\n \"doubleValue\": \"NaN\"\n}" + } + }, + { + "id": "AwsJson11SupportsInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + } + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"floatValue\": \"Infinity\",\n \"doubleValue\": \"Infinity\"\n}" + } + }, + { + "id": "AwsJson11SupportsNegativeInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + } + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1" + }, + "body": "{\n \"floatValue\": \"-Infinity\",\n \"doubleValue\": \"-Infinity\"\n}" + } + } + ] + } ] diff --git a/tests/unit/protocols/output/json_1_0.json b/tests/unit/protocols/output/json_1_0.json new file mode 100644 index 0000000000..920a8bebae --- /dev/null +++ b/tests/unit/protocols/output/json_1_0.json @@ -0,0 +1,1157 @@ +[ + { + "description": "Test cases for EmptyInputAndEmptyOutput operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "AwsJson10EmptyInputAndEmptyOutputSendJsonObject", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has an empty input and empty output structure that reuses the same shape. While this should be rare, code generators must support this.

" + }, + "description": "A service will always return a JSON object for operations with modeled output.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "AwsJson10InvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple JSON errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#InvalidGreeting\",\n \"Message\": \"Hi\"\n}" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "FooError": { + "type": "structure", + "members": {}, + "documentation": "

This error has test cases that test some of the dark corners of Amazon service framework history. It should only be implemented by clients.

", + "exception": true, + "fault": true + } + }, + "cases": [ + { + "id": "AwsJson10FooErrorUsingXAmznErrorType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Serializes the X-Amzn-ErrorType header. For an example service, see Amazon EKS.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError" + } + } + }, + { + "id": "AwsJson10FooErrorUsingXAmznErrorTypeWithUri", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some X-Amzn-Errortype headers contain URLs. Clients need to split the URL on ':' and take only the first half of the string. For example, 'ValidationException:http://internal.amazon.com/coral/com.amazon.coral.validate/'\nis to be interpreted as 'ValidationException'.\n\nFor an example service see Amazon Polly.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "AwsJson10FooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "X-Amzn-Errortype might contain a URL and a namespace. Client should extract only the shape name. This is a pathalogical case that might not actually happen in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "aws.protocoltests.json10#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "AwsJson10FooErrorUsingCode", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "This example uses the 'code' property in the output rather than X-Amzn-Errortype. Some services do this though it's preferable to send the X-Amzn-Errortype. Client implementations must first check for the X-Amzn-Errortype and then check for a top-level 'code' property.\n\nFor example service see Amazon S3 Glacier.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"code\": \"FooError\"\n}" + } + }, + { + "id": "AwsJson10FooErrorUsingCodeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"code\": \"aws.protocoltests.json10#FooError\"\n}" + } + }, + { + "id": "AwsJson10FooErrorUsingCodeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"code\": \"aws.protocoltests.json10#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + }, + { + "id": "AwsJson10FooErrorWithDunderType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"FooError\"\n}" + } + }, + { + "id": "AwsJson10FooErrorWithDunderTypeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#FooError\"\n}" + } + }, + { + "id": "AwsJson10FooErrorWithDunderTypeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "AwsJson10ComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "description": "Parses a complex error with no message member", + "errorCode": "ComplexError", + "error": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#ComplexError\",\n \"TopLevel\": \"Top level\",\n \"Nested\": {\n \"Foo\": \"bar\"\n }\n}" + } + }, + { + "id": "AwsJson10EmptyComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A ComplexError error.

Implementations must be able to successfully take a response and properly deserialize successful and error responses.

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "description": "Parses a complex error with an empty body", + "errorCode": "ComplexError", + "error": {}, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#ComplexError\"\n}" + } + } + ] + }, + { + "description": "Test cases for JsonUnions operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "JsonUnionsOutput": { + "type": "structure", + "members": { + "contents": { + "shape": "MyUnion" + } + } + }, + "MyUnion": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "booleanValue": { + "shape": "Boolean" + }, + "numberValue": { + "shape": "Integer" + }, + "blobValue": { + "shape": "Blob" + }, + "timestampValue": { + "shape": "Timestamp" + }, + "enumValue": { + "shape": "FooEnum" + }, + "intEnumValue": { + "shape": "IntegerEnum" + }, + "listValue": { + "shape": "StringList" + }, + "mapValue": { + "shape": "StringMap" + }, + "structureValue": { + "shape": "GreetingStruct" + } + }, + "documentation": "

A union with a representative set of types for members.

", + "union": true + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Blob": { + "type": "blob" + }, + "Timestamp": { + "type": "timestamp" + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "AwsJson10DeserializeStringUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a string union value", + "result": { + "contents": { + "stringValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"stringValue\": \"foo\"\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeBooleanUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a boolean union value", + "result": { + "contents": { + "booleanValue": true + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"booleanValue\": true\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeNumberUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a number union value", + "result": { + "contents": { + "numberValue": 1 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"numberValue\": 1\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeBlobUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a blob union value", + "result": { + "contents": { + "blobValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"blobValue\": \"Zm9v\"\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeTimestampUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a timestamp union value", + "result": { + "contents": { + "timestampValue": 1398796238 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"timestampValue\": 1398796238\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeEnumUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes an enum union value", + "result": { + "contents": { + "enumValue": "Foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"enumValue\": \"Foo\"\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeIntEnumUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes an intEnum union value", + "result": { + "contents": { + "intEnumValue": 1 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"intEnumValue\": 1\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeListUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a list union value", + "result": { + "contents": { + "listValue": [ + "foo", + "bar" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"listValue\": [\"foo\", \"bar\"]\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeMapUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a map union value", + "result": { + "contents": { + "mapValue": { + "foo": "bar", + "spam": "eggs" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"mapValue\": {\n \"foo\": \"bar\",\n \"spam\": \"eggs\"\n }\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeStructureUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a structure union value", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeIgnoreType", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Ignores an unrecognized __type property", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"__type\": \"aws.protocoltests.json10#MyUnion\",\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + }, + { + "id": "AwsJson10DeserializeAllowNulls", + "given": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Allows for `: null` to be set for all unset fields", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"stringValue\": null,\n \"booleanValue\": null,\n \"numberValue\": null,\n \"blobValue\": null,\n \"timestampValue\": null,\n \"enumValue\": null,\n \"intEnumValue\": null,\n \"listValue\": null,\n \"mapValue\": null,\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + } + ] + }, + { + "description": "Test cases for NoInputAndNoOutput operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": {}, + "cases": [ + { + "id": "AwsJson10HandlesEmptyOutputShape", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output. While this should be rare, code generators must support this.

" + }, + "description": "When no output is defined, the service is expected to return\nan empty payload, however, client must ignore a JSON payload\nif one is returned. This ensures that if output is added later,\nthen it will not break the client.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + }, + { + "id": "AwsJson10HandlesUnexpectedJsonOutput", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output. While this should be rare, code generators must support this.

" + }, + "description": "This client-only test builds on handles_empty_output_shape,\nby including unexpected fields in the JSON. A client\nneeds to ignore JSON output that is empty or that contains\nJSON object data.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"foo\": true\n}" + } + }, + { + "id": "AwsJson10ServiceRespondsWithNoPayload", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output. While this should be rare, code generators must support this.

" + }, + "description": "When no output is defined, the service is expected to return\nan empty payload. Despite the lack of a payload, the service\nis expected to always send a Content-Type header. Clients must\nhandle cases where a service returns a JSON object and where\na service returns no JSON at all.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "" + } + } + ] + }, + { + "description": "Test cases for NoInputAndOutput operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "AwsJson10NoInputAndOutput", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input and the output is empty. While this should be rare, code generators must support this.

" + }, + "description": "Empty output always serializes an empty object payload.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + } + ] + }, + { + "description": "Test cases for SimpleScalarProperties operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2020-07-14", + "jsonVersion": "1.0", + "targetPrefix": "JsonRpc10" + }, + "shapes": { + "SimpleScalarPropertiesOutput": { + "type": "structure", + "members": { + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + } + } + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } + }, + "cases": [ + { + "id": "AwsJson10SupportsNaNFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesOutput" + } + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"NaN\",\n \"doubleValue\": \"NaN\"\n}" + } + }, + { + "id": "AwsJson10SupportsInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesOutput" + } + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"Infinity\",\n \"doubleValue\": \"Infinity\"\n}" + } + }, + { + "id": "AwsJson10SupportsNegativeInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarPropertiesOutput" + } + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"-Infinity\",\n \"doubleValue\": \"-Infinity\"\n}" + } + } + ] + } +] diff --git a/tests/unit/protocols/output/query.json b/tests/unit/protocols/output/query.json index 3faf5eb041..8195a44957 100644 --- a/tests/unit/protocols/output/query.json +++ b/tests/unit/protocols/output/query.json @@ -1,931 +1,2375 @@ [ - { - "description": "Scalar members", - "metadata": { - "protocol": "query" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType", - "locationName": "FooNum" - }, - "FalseBool": { - "shape": "BooleanType" - }, - "TrueBool": { - "shape": "BooleanType" - }, - "Float": { - "shape": "FloatType" - }, - "Double": { - "shape": "DoubleType" - }, - "Long": { - "shape": "LongType" - }, - "Char": { - "shape": "CharType" - }, - "Timestamp": { - "shape": "TimestampType" - } - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "FloatType": { - "type": "float" - }, - "DoubleType": { - "type": "double" - }, - "LongType": { - "type": "long" - }, - "CharType": { - "type": "character" - }, - "TimestampType": { - "type": "timestamp" - } - }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Str": "myname", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a", - "Timestamp": 1422172800 - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "myname123falsetrue1.21.3200a2015-01-25T08:00:00Zrequest-id" - } - } - ] - }, - { - "description": "Not all members in response", - "metadata": { - "protocol": "query" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType" - } - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - } - }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Str": "myname" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "mynamerequest-id" - } - } - ] - }, - { - "description": "Blob", - "metadata": { - "protocol": "query" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Blob": { - "shape": "BlobType" - } - } - }, - "BlobType": { - "type": "blob" - } - }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Blob": "value" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "dmFsdWU=requestid" - } - } - ] - }, - { - "description": "Lists", - "metadata": { - "protocol": "query" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } - }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "List with custom member name", - "metadata": { - "protocol": "query" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType", - "locationName": "item" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for DatetimeOffsets operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "AwsQueryDateTimeWithNegativeOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2019-12-16T22:48:18-01:00\n \n\n" + } + }, + { + "id": "AwsQueryDateTimeWithPositiveOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2019-12-17T00:48:18+01:00\n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "Flattened List", - "metadata": { - "protocol": "query" + { + "description": "Test cases for EmptyInputAndEmptyOutput operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "QueryEmptyInputAndEmptyOutput", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response members.

While this should be rare, code generators must support this.

" + }, + "description": "Empty output", + "result": {}, + "response": { + "status_code": 200 + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType" - } - } - }, - "ListType": { - "type": "list", - "flattened": true, - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for FlattenedXmlMap operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "FlattenedXmlMapOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FooEnumMap", + "flattened": true + } + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryQueryFlattenedXmlMap", + "given": { + "name": "FlattenedXmlMap", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapOutput" + }, + "documentation": "

Flattened maps

" + }, + "description": "Serializes flattened XML maps in responses", + "result": { + "myMap": { + "foo": "Foo", + "baz": "Baz" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n foo\n Foo\n \n \n baz\n Baz\n \n \n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123requestid" - } - } - ] - }, - { - "description": "Flattened single element list", - "metadata": { - "protocol": "query" + { + "description": "Test cases for FlattenedXmlMapWithXmlName operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "FlattenedXmlMapWithXmlNameOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FlattenedXmlMapWithXmlNameOutputMap", + "flattened": true, + "locationName": "KVP" + } + } + }, + "FlattenedXmlMapWithXmlNameOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K" + }, + "value": { + "shape": "String", + "locationName": "V" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryQueryFlattenedXmlMapWithXmlName", + "given": { + "name": "FlattenedXmlMapWithXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNameOutput" + }, + "documentation": "

Flattened maps with @xmlName

" + }, + "description": "Serializes flattened XML maps in responses that have xmlName on members", + "result": { + "myMap": { + "a": "A", + "b": "B" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n a\n A\n \n \n b\n B\n \n \n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType" - } - } - }, - "ListType": { - "type": "list", - "flattened": true, - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for FlattenedXmlMapWithXmlNamespace operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "FlattenedXmlMapWithXmlNamespaceOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FlattenedXmlMapWithXmlNamespaceOutputMap", + "flattened": true, + "locationName": "KVP", + "xmlNamespace": "https://the-member.example.com" + } + } + }, + "FlattenedXmlMapWithXmlNamespaceOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K", + "xmlNamespace": "https://the-key.example.com" + }, + "value": { + "shape": "String", + "locationName": "V", + "xmlNamespace": "https://the-value.example.com" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryQueryFlattenedXmlMapWithXmlNamespace", + "given": { + "name": "FlattenedXmlMapWithXmlNamespace", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNamespaceOutput" + }, + "documentation": "

Flattened maps with @xmlNamespace and @xmlName

" + }, + "description": "Serializes flattened XML maps in responses that have xmlNamespace and xmlName on members", + "result": { + "myMap": { + "a": "A", + "b": "B" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n a\n A\n \n \n b\n B\n \n \n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abcrequestid" - } - } - ] - }, - { - "description": "List of structures", - "metadata": { - "protocol": "query" + { + "description": "Test cases for FractionalSeconds operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "AwsQueryDateTimeWithFractionalSeconds", + "given": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FractionalSecondsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", + "result": { + "datetime": 9.46845296123E8 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2000-01-02T20:34:56.123Z\n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "List": { - "shape": "ListOfStructs" - } - } - }, - "ListOfStructs": { - "type": "list", - "member": { - "shape": "StructureShape" - } - }, - "StructureShape": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringShape" - }, - "Bar": { - "shape": "StringShape" - }, - "Baz": { - "shape": "StringShape" - } - } - }, - "StringShape": { - "type": "string" - } + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryGreetingWithErrors", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
" + }, + "description": "Ensures that operations with errors successfully know how to deserialize the successful response", + "result": { + "greeting": "Hello" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Hello\n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "List": [{"Foo": "firstfoo", "Bar": "firstbar", "Baz": "firstbaz"}, {"Foo": "secondfoo", "Bar": "secondbar", "Baz": "secondbaz"}] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "firstfoofirstbarfirstbazsecondfoosecondbarsecondbazrequestid" - } - } - ] - }, - { - "description": "Flattened list of structures", - "metadata": { - "protocol": "query" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryInvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
", + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple XML errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Sender\n InvalidGreeting\n Hi\n \n foo-id\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "resultWrapper": "OperationNameResult", - "members": { - "List": { - "shape": "ListOfStructs" - } - } - }, - "ListOfStructs": { - "type": "list", - "flattened": true, - "member": { - "shape": "StructureShape" - } - }, - "StructureShape": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringShape" - }, - "Bar": { - "shape": "StringShape" - }, - "Baz": { - "shape": "StringShape" - } - } - }, - "StringShape": { - "type": "string" - } + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "CustomCodeError": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "error": { + "code": "Customized", + "httpStatusCode": 402, + "senderFault": true + }, + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryCustomizedError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
", + "errors": [ + { + "shape": "CustomCodeError" + } + ] + }, + "description": "Parses customized XML errors", + "errorCode": "Customized", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 402, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Sender\n Customized\n Hi\n \n foo-id\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "List": [{"Foo": "firstfoo", "Bar": "firstbar", "Baz": "firstbaz"}, {"Foo": "secondfoo", "Bar": "secondbar", "Baz": "secondbaz"}] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "firstfoofirstbarfirstbazsecondfoosecondbarsecondbazrequestid" - } - } - ] - }, - { - "description": "Flattened list with location name", - "metadata": { - "protocol": "query" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "QueryComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
", + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "errorCode": "ComplexError", + "error": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Sender\n ComplexError\n Top level\n \n bar\n \n \n foo-id\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "List": { - "shape": "ListType" - } - } - }, - "ListType": { - "type": "list", - "flattened": true, - "member": { - "shape": "StringShape", - "locationName": "NamedList" - } - }, - "StringShape": { - "type": "string" - } + { + "description": "Test cases for IgnoresWrappingXmlName operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "IgnoresWrappingXmlNameOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + } + }, + "locationName": "IgnoreMe" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryIgnoresWrappingXmlName", + "given": { + "name": "IgnoresWrappingXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "IgnoresWrappingXmlNameOutput" + }, + "documentation": "

The xmlName trait on the output structure is ignored in AWS Query.

The wrapping element is always operation name + "Response", and inside of that wrapper is another wrapper named operation name + "Result".

" + }, + "description": "The xmlName trait on the output structure is ignored in AWS Query", + "result": { + "foo": "bar" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n bar\n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "List": ["a", "b"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abrequestid" - } - } - ] - }, - { - "description": "Normal map", - "metadata": { - "protocol": "query" + { + "description": "Test cases for NoInputAndNoOutput operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": {}, + "cases": [ + { + "id": "QueryNoInputAndNoOutput", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output.

While this should be rare, code generators must support this.

" + }, + "description": "Empty output. Note that no assertion is made on the output body itself.", + "result": {}, + "response": { + "status_code": 200 + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap" - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StructType" - } - }, - "StringType": { - "type": "string" - }, - "StructType": { - "type": "structure", - "members": { - "foo": { - "shape": "StringType" - } - } - } + { + "description": "Test cases for NoInputAndOutput operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "QueryNoInputAndOutput", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request payload or response members.

While this should be rare, code generators must support this.

" + }, + "description": "Empty output", + "result": {}, + "response": { + "status_code": 200 + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": { - "foo": "bar" - }, - "baz": { - "foo": "bam" - } - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Flattened map", - "metadata": { - "protocol": "query" + { + "description": "Test cases for RecursiveXmlShapes operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "RecursiveXmlShapesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + }, + "RecursiveXmlShapesOutputNested1": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "nested": { + "shape": "RecursiveXmlShapesOutputNested2" + } + } + }, + "String": { + "type": "string" + }, + "RecursiveXmlShapesOutputNested2": { + "type": "structure", + "members": { + "bar": { + "shape": "String" + }, + "recursiveMember": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + } + }, + "cases": [ + { + "id": "QueryRecursiveShapes", + "given": { + "name": "RecursiveXmlShapes", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "RecursiveXmlShapesOutput" + }, + "documentation": "

Recursive shapes

" + }, + "description": "Serializes recursive structures", + "result": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n Foo1\n \n Bar1\n \n Foo2\n \n Bar2\n \n \n \n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap", - "flattened": true - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for SimpleScalarXmlProperties operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "SimpleScalarXmlPropertiesOutput": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "emptyStringValue": { + "shape": "String" + }, + "trueBooleanValue": { + "shape": "Boolean" + }, + "falseBooleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double", + "locationName": "DoubleDribble" + } + } + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } + }, + "cases": [ + { + "id": "QuerySimpleScalarProperties", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Serializes simple scalar properties", + "result": { + "stringValue": "string", + "emptyStringValue": "", + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n string\n \n true\n false\n 1\n 2\n 3\n 4\n 5.5\n 6.5\n \n\n" + } + }, + { + "id": "AwsQuerySupportsNaNFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n NaN\n NaN\n \n\n" + } + }, + { + "id": "AwsQuerySupportsInfinityFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Infinity\n Infinity\n \n\n" + } + }, + { + "id": "AwsQuerySupportsNegativeInfinityFloatOutputs", + "given": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput" + } + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n -Infinity\n -Infinity\n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Flattened map in shape definition", - "metadata": { - "protocol": "query" + { + "description": "Test cases for XmlBlobs operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlBlobsOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "QueryXmlBlobs", + "given": { + "name": "XmlBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Blobs are base64 encoded", + "result": { + "data": "value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n dmFsdWU=\n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap", - "locationName": "Attribute" - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType", - "locationName": "Name" - }, - "value": { - "shape": "StringType", - "locationName": "Value" - }, - "flattened": true, - "locationName": "Attribute" - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlEmptyBlobs operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlBlobsOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "QueryXmlEmptyBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + } + }, + "description": "Empty blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + }, + { + "id": "QueryXmlEmptySelfClosedBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput" + } + }, + "description": "Empty self closed blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarrequestid" - } - } - ] - }, - { - "description": "Named map", - "metadata": { - "protocol": "query" + { + "description": "Test cases for XmlEmptyLists operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlListsOutput": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "QueryXmlEmptyLists", + "given": { + "name": "XmlEmptyLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput" + } + }, + "description": "Deserializes empty XML lists", + "result": { + "stringList": [], + "stringSet": [] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "MapType" - } - } - }, - "MapType": { - "type": "map", - "flattened": true, - "key": { - "locationName": "foo", - "shape": "StringType" - }, - "value": { - "locationName": "bar", - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlEmptyMaps operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlMapsOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsOutputMap" + } + } + }, + "XmlMapsOutputMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryXmlEmptyMaps", + "given": { + "name": "XmlEmptyMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsOutput" + } + }, + "description": "Deserializes Empty XML maps", + "result": { + "myMap": {} + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n \n\n" + } + }, + { + "id": "QueryXmlEmptySelfClosedMaps", + "given": { + "name": "XmlEmptyMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsOutput" + } + }, + "description": "Deserializes Self-Closed XML maps", + "result": { + "myMap": {} + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbamrequestid" - } - } - ] - }, - { - "description": "Empty string", - "metadata": { - "protocol": "query" + { + "description": "Test cases for XmlEnums operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlEnumsOutput": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryXmlEnums", + "given": { + "name": "XmlEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlEnumsOutput" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

" + }, + "description": "Serializes simple scalar properties", + "result": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Foo\n 0\n 1\n \n Foo\n 0\n \n \n Foo\n 0\n \n \n \n hi\n Foo\n \n \n zero\n 0\n \n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlIntEnums operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlIntEnumsOutput": { + "type": "structure", + "members": { + "intEnum1": { + "shape": "IntegerEnum" + }, + "intEnum2": { + "shape": "IntegerEnum" + }, + "intEnum3": { + "shape": "IntegerEnum" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "intEnumSet": { + "shape": "IntegerEnumSet" + }, + "intEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryXmlIntEnums", + "given": { + "name": "XmlIntEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlIntEnumsOutput" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

" + }, + "description": "Serializes simple scalar properties", + "result": { + "intEnum1": 1, + "intEnum2": 2, + "intEnum3": 3, + "intEnumList": [ + 1, + 2 + ], + "intEnumSet": [ + 1, + 2 + ], + "intEnumMap": { + "a": 1, + "b": 2 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 1\n 2\n 3\n \n 1\n 2\n \n \n 1\n 2\n \n \n \n a\n 1\n \n \n b\n 2\n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "resultWrapper": "OperationNameResult", - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Foo": "" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "requestid" - } - } - ] - }, - { - "description": "Timestamp members", - "metadata": { - "protocol": "query" + { + "description": "Test cases for XmlLists operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlListsOutput": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "QueryXmlLists", + "given": { + "name": "XmlLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput" + }, + "documentation": "

This test case serializes XML lists for the following cases for both input and output:

  1. Normal XML lists.
  2. Normal XML sets.
  3. XML lists of lists.
  4. XML lists with @xmlName on its members
  5. Flattened XML lists.
  6. Flattened XML lists with @xmlName.
  7. Lists of structures.
" + }, + "description": "Tests for XML list serialization", + "result": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238, + 1398796238 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "renamedListMembers": [ + "foo", + "bar" + ], + "flattenedList": [ + "hi", + "bye" + ], + "flattenedList2": [ + "yep", + "nope" + ], + "flattenedListWithMemberNamespace": [ + "a", + "b" + ], + "flattenedListWithNamespace": [ + "a", + "b" + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n foo\n bar\n \n \n foo\n bar\n \n \n 1\n 2\n \n \n true\n false\n \n \n 2014-04-29T18:30:38Z\n 2014-04-29T18:30:38Z\n \n \n Foo\n 0\n \n \n 1\n 2\n \n \n \n foo\n bar\n \n \n baz\n qux\n \n \n \n foo\n bar\n \n hi\n bye\n yep\n nope\n a\n b\n a\n b\n \n \n 1\n 2\n \n \n 3\n 4\n \n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "TimeArg": { - "shape": "TimestampType" - }, - "TimeCustom": { - "timestampFormat": "rfc822", - "shape": "TimestampType" - }, - "TimeFormat": { - "shape": "TimestampFormatType" - }, - "StructMember": { - "shape": "TimeContainer" - } - } - }, - "TimeContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "TimestampType" - }, - "bar": { - "shape": "TimestampFormatType" - } - } - }, - "TimestampFormatType": { - "timestampFormat": "unixTimestamp", - "type": "timestamp" - }, - "TimestampType": { - "type": "timestamp" - } + { + "description": "Test cases for XmlMaps operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlMapsOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsOutputMap" + } + } + }, + "XmlMapsOutputMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryXmlMaps", + "given": { + "name": "XmlMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsOutput" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "Tests for XML map serialization", + "result": { + "myMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n foo\n \n there\n \n \n \n baz\n \n bye\n \n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "TimeArg": 1398796238, - "TimeCustom": 1398796238, - "TimeFormat": 1398796238, - "StructMember": { - "foo": 1398796238, - "bar": 1398796238 - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "2014-04-29T18:30:38+00:0013987962382014-04-29T18:30:38+00:00Tue, 29 Apr 2014 18:30:38 GMT1398796238requestid" - } - } - ] - }, - { - "description": "Modeled exceptions", - "metadata": { - "protocol": "query" + { + "description": "Test cases for XmlMapsXmlName operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlMapsXmlNameOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsXmlNameOutputMap" + } + } + }, + "XmlMapsXmlNameOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "Attribute" + }, + "value": { + "shape": "GreetingStruct", + "locationName": "Setting" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "QueryQueryXmlMapsXmlName", + "given": { + "name": "XmlMapsXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsXmlNameOutput" + } + }, + "description": "Serializes XML lists", + "result": { + "myMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n foo\n \n there\n \n \n \n baz\n \n bye\n \n \n \n \n\n" + } + } + ] }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "OtherExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlNamespaces operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlNamespacesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "XmlNamespaceNested" + } + }, + "xmlNamespace": "http://foo.com" + }, + "XmlNamespaceNested": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "xmlNamespace": { + "prefix": "baz", + "uri": "http://baz.com" + } + }, + "values": { + "shape": "XmlNamespacedList", + "xmlNamespace": "http://qux.com" + } + }, + "xmlNamespace": "http://boo.com" + }, + "String": { + "type": "string" + }, + "XmlNamespacedList": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "http://bux.com" + } + } + }, + "cases": [ + { + "id": "QueryXmlNamespaces", + "given": { + "name": "XmlNamespaces", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlNamespacesOutput" + } + }, + "description": "Serializes XML namespaces", + "result": { + "nested": { + "foo": "Foo", + "values": [ + "Bar", + "Baz" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n Foo\n \n Bar\n Baz\n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "SomeTypeExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "SomeTypeOtherExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": {}, - "errorCode": "UndefinedShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": {}, - "body": "SomeTypeUndefinedShapemymessagemybody" - } - } - ] - } + { + "description": "Test cases for XmlTimestamps operation", + "metadata": { + "protocol": "query", + "protocols": [ + "query" + ], + "apiVersion": "2020-01-08" + }, + "shapes": { + "XmlTimestampsOutput": { + "type": "structure", + "members": { + "normal": { + "shape": "Timestamp" + }, + "dateTime": { + "shape": "SyntheticTimestamp_date_time" + }, + "dateTimeOnTarget": { + "shape": "DateTime" + }, + "epochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds" + }, + "epochSecondsOnTarget": { + "shape": "EpochSeconds" + }, + "httpDate": { + "shape": "SyntheticTimestamp_http_date" + }, + "httpDateOnTarget": { + "shape": "HttpDate" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + } + }, + "cases": [ + { + "id": "QueryXmlTimestamps", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Tests how normal timestamps are serialized", + "result": { + "normal": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithDateTimeFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time works like normal timestamps", + "result": { + "dateTime": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithDateTimeOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time on the target shape works like normal timestamps", + "result": { + "dateTimeOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithEpochSecondsFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds works", + "result": { + "epochSeconds": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 1398796238\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithEpochSecondsOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds on the target shape works", + "result": { + "epochSecondsOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 1398796238\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithHttpDateFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date works", + "result": { + "httpDate": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Tue, 29 Apr 2014 18:30:38 GMT\n \n\n" + } + }, + { + "id": "QueryXmlTimestampsWithHttpDateOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date on the target shape works", + "result": { + "httpDateOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Tue, 29 Apr 2014 18:30:38 GMT\n \n\n" + } + } + ] + } ] diff --git a/tests/unit/protocols/output/rest-json.json b/tests/unit/protocols/output/rest-json.json index c6bd958b92..c7e9f46a32 100644 --- a/tests/unit/protocols/output/rest-json.json +++ b/tests/unit/protocols/output/rest-json.json @@ -1,1312 +1,4323 @@ [ - { - "description": "Scalar members", - "metadata": { - "protocol": "rest-json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ImaHeader": { - "shape": "HeaderShape" - }, - "ImaHeaderLocation": { - "shape": "HeaderShape", - "locationName": "X-Foo" - }, - "Status": { - "shape": "StatusShape", - "location": "statusCode" - }, - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType" - }, - "FalseBool": { - "shape": "BooleanType" - }, - "TrueBool": { - "shape": "BooleanType" - }, - "Float": { - "shape": "FloatType" - }, - "Double": { - "shape": "DoubleType" - }, - "Long": { - "shape": "LongType" - }, - "Char": { - "shape": "CharType" - } - } - }, - "HeaderShape": { - "type": "string", - "location": "header" - }, - "StatusShape": { - "type": "integer" - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "FloatType": { - "type": "float" - }, - "DoubleType": { - "type": "double" - }, - "LongType": { - "type": "long" - }, - "CharType": { - "type": "character" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Status": 200, - "Str": "myname", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a" - }, - "response": { - "status_code": 200, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "{\"Str\": \"myname\", \"Num\": 123, \"FalseBool\": false, \"TrueBool\": true, \"Float\": 1.2, \"Double\": 1.3, \"Long\": 200, \"Char\": \"a\"}" - } - } - ] - }, - { - "description": "Blob members", - "metadata": { - "protocol": "rest-json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "BlobMember": { - "shape": "BlobType" - }, - "StructMember": { - "shape": "BlobContainer" - } - } - }, - "BlobType": { - "type": "blob" - }, - "BlobContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "BlobType" - } - } - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "BlobMember": "hi!", - "StructMember": { - "foo": "there!" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"BlobMember\": \"aGkh\", \"StructMember\": {\"foo\": \"dGhlcmUh\"}}" - } - } - ] - }, - { - "description": "Timestamp members", - "metadata": { - "protocol": "rest-json" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "TimeArg": { - "shape": "TimestampType" - }, - "TimeArgInHeader": { - "shape": "TimestampType", - "location": "header", - "locationName": "x-amz-timearg" - }, - "TimeCustom": { - "timestampFormat": "rfc822", - "shape": "TimestampType" - }, - "TimeCustomInHeader": { - "timestampFormat": "unixTimestamp", - "shape": "TimestampType", - "location": "header", - "locationName": "x-amz-timecustom" - }, - "TimeFormat": { - "shape": "TimestampFormatType" - }, - "TimeFormatInHeader": { - "shape": "TimestampFormatType", - "location": "header", - "locationName": "x-amz-timeformat" - }, - "StructMember": { - "shape": "TimeContainer" - } - } - }, - "TimeContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "TimestampType" - }, - "bar": { - "shape": "TimestampFormatType" - } - } - }, - "TimestampFormatType": { - "timestampFormat": "iso8601", - "type": "timestamp" - }, - "TimestampType": { - "type": "timestamp" - } + { + "description": "Test cases for DatetimeOffsets operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "RestJsonDateTimeWithNegativeOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/DatetimeOffsets", + "responseCode": 200 + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "body": " {\n \"datetime\": \"2019-12-16T22:48:18-01:00\"\n }\n" + } + }, + { + "id": "RestJsonDateTimeWithPositiveOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/DatetimeOffsets", + "responseCode": 200 + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "body": " {\n \"datetime\": \"2019-12-17T00:48:18+01:00\"\n }\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "TimeArg": 1398796238, - "TimeArgInHeader": 1398796238, - "TimeCustom": 1398796238, - "TimeCustomInHeader": 1398796238, - "TimeFormat": 1398796238, - "TimeFormatInHeader": 1398796238, - "StructMember": { - "foo": 1398796238, - "bar": 1398796238 - } - }, - "response": { - "status_code": 200, - "headers": { - "x-amz-timearg": "Tue, 29 Apr 2014 18:30:38 GMT", - "x-amz-timecustom": "1398796238", - "x-amz-timeformat": "2014-04-29T18:30:38+00:00" - }, - "body": "{\"TimeArg\": 1398796238, \"TimeCustom\": \"Tue, 29 Apr 2014 18:30:38 GMT\", \"TimeFormat\": \"2014-04-29T18:30:38+00:00\", \"StructMember\": {\"foo\": 1398796238, \"bar\": \"2014-04-29T18:30:38+00:00\"}}" - } - } - ] - }, - { - "description": "Lists", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for DocumentType operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "DocumentTypeInputOutput": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "documentValue": { + "shape": "Document" + } + } + }, + "String": { + "type": "string" + }, + "Document": { + "type": "structure", + "members": {}, + "document": true + } + }, + "cases": [ + { + "id": "DocumentOutput", + "given": { + "name": "DocumentType", + "http": { + "method": "PUT", + "requestUri": "/DocumentType", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeInputOutput" + }, + "documentation": "

This example serializes a document as part of the payload.

", + "idempotent": true + }, + "description": "Serializes documents as part of the JSON response payload with no escaping.", + "result": { + "stringValue": "string", + "documentValue": { + "foo": "bar" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": \"string\",\n \"documentValue\": {\n \"foo\": \"bar\"\n }\n}" + } + }, + { + "id": "DocumentOutputString", + "given": { + "name": "DocumentType", + "http": { + "method": "PUT", + "requestUri": "/DocumentType", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeInputOutput" + }, + "documentation": "

This example serializes a document as part of the payload.

", + "idempotent": true + }, + "description": "Document types can be JSON scalars too.", + "result": { + "stringValue": "string", + "documentValue": "hello" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": \"string\",\n \"documentValue\": \"hello\"\n}" + } + }, + { + "id": "DocumentOutputNumber", + "given": { + "name": "DocumentType", + "http": { + "method": "PUT", + "requestUri": "/DocumentType", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeInputOutput" + }, + "documentation": "

This example serializes a document as part of the payload.

", + "idempotent": true + }, + "description": "Document types can be JSON scalars too.", + "result": { + "stringValue": "string", + "documentValue": 10 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": \"string\",\n \"documentValue\": 10\n}" + } + }, + { + "id": "DocumentOutputBoolean", + "given": { + "name": "DocumentType", + "http": { + "method": "PUT", + "requestUri": "/DocumentType", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeInputOutput" + }, + "documentation": "

This example serializes a document as part of the payload.

", + "idempotent": true + }, + "description": "Document types can be JSON scalars too.", + "result": { + "stringValue": "string", + "documentValue": false + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": \"string\",\n \"documentValue\": false\n}" + } + }, + { + "id": "DocumentOutputArray", + "given": { + "name": "DocumentType", + "http": { + "method": "PUT", + "requestUri": "/DocumentType", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeInputOutput" + }, + "documentation": "

This example serializes a document as part of the payload.

", + "idempotent": true + }, + "description": "Document types can be JSON arrays.", + "result": { + "stringValue": "string", + "documentValue": [ + true, + false + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": \"string\",\n \"documentValue\": [\n true,\n false\n ]\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType" - } - } - }, - "ListType": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for DocumentTypeAsMapValue operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "DocumentTypeAsMapValueInputOutput": { + "type": "structure", + "members": { + "docValuedMap": { + "shape": "DocumentValuedMap" + } + } + }, + "DocumentValuedMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "Document" + } + }, + "Document": { + "type": "structure", + "members": {}, + "document": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "DocumentTypeAsMapValueOutput", + "given": { + "name": "DocumentTypeAsMapValue", + "http": { + "method": "PUT", + "requestUri": "/DocumentTypeAsMapValue", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeAsMapValueInputOutput" + }, + "documentation": "

This example serializes documents as the value of maps.

", + "idempotent": true + }, + "description": "Serializes a map that uses documents as the value.", + "result": { + "docValuedMap": { + "foo": { + "f": 1, + "o": 2 + }, + "bar": [ + "b", + "a", + "r" + ], + "baz": "BAZ" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"docValuedMap\": {\n \"foo\": { \"f\": 1, \"o\": 2 },\n \"bar\": [ \"b\", \"a\", \"r\" ],\n \"baz\": \"BAZ\"\n }\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["a", "b"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"ListMember\": [\"a\", \"b\"]}" - } - } - ] - }, - { - "description": "Lists with structure member", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for DocumentTypeAsPayload operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "DocumentTypeAsPayloadInputOutput": { + "type": "structure", + "members": { + "documentValue": { + "shape": "Document" + } + }, + "payload": "documentValue" + }, + "Document": { + "type": "structure", + "members": {}, + "document": true + } + }, + "cases": [ + { + "id": "DocumentTypeAsPayloadOutput", + "given": { + "name": "DocumentTypeAsPayload", + "http": { + "method": "PUT", + "requestUri": "/DocumentTypeAsPayload", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeAsPayloadInputOutput" + }, + "documentation": "

This example serializes a document as the entire HTTP payload.

", + "idempotent": true + }, + "description": "Serializes a document as the target of the httpPayload trait.", + "result": { + "documentValue": { + "foo": "bar" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"foo\": \"bar\"\n}" + } + }, + { + "id": "DocumentTypeAsPayloadOutputString", + "given": { + "name": "DocumentTypeAsPayload", + "http": { + "method": "PUT", + "requestUri": "/DocumentTypeAsPayload", + "responseCode": 200 + }, + "output": { + "shape": "DocumentTypeAsPayloadInputOutput" + }, + "documentation": "

This example serializes a document as the entire HTTP payload.

", + "idempotent": true + }, + "description": "Serializes a document as a payload string.", + "result": { + "documentValue": "hello" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "\"hello\"" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListType" - } - } - }, - "ListType": { - "type": "list", - "member": { - "shape": "SingleStruct" - } - }, - "StringType": { - "type": "string" - }, - "SingleStruct": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - } + { + "description": "Test cases for EmptyInputAndEmptyOutput operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "RestJsonEmptyInputAndEmptyOutput", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/EmptyInputAndEmptyOutput", + "responseCode": 200 + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has an empty input and empty output structure that reuses the same shape. While this should be rare, code generators must support this.

" + }, + "description": "As of January 2021, server implementations are expected to\nrespond with a JSON object regardless of if the output\nparameters are empty.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{}" + } + }, + { + "id": "RestJsonEmptyInputAndEmptyOutputJsonObjectOutput", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/EmptyInputAndEmptyOutput", + "responseCode": 200 + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has an empty input and empty output structure that reuses the same shape. While this should be rare, code generators must support this.

" + }, + "description": "This test ensures that clients can gracefully handle\nsituations where a service omits a JSON payload entirely.", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": [{"Foo": "a"}, {"Foo": "b"}] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"ListMember\": [{\"Foo\": \"a\"}, {\"Foo\": \"b\"}]}" - } - } - ] - }, - { - "description": "Maps", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for FractionalSeconds operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "RestJsonDateTimeWithFractionalSeconds", + "given": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/FractionalSeconds", + "responseCode": 200 + }, + "output": { + "shape": "FractionalSecondsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", + "result": { + "datetime": 9.46845296123E8 + }, + "response": { + "status_code": 200, + "body": " {\n \"datetime\": \"2000-01-02T20:34:56.123Z\"\n }\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "MapMember": { - "shape": "MapType" - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "ListType" - } - }, - "ListType": { - "type": "list", - "member": { - "shape": "IntegerType" - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - } + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String", + "location": "header", + "locationName": "X-Greeting" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonGreetingWithErrors", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true + }, + "description": "Ensures that operations with errors successfully know how\nto deserialize a successful response. As of January 2021,\nserver implementations are expected to respond with a\nJSON object regardless of if the output parameters are\nempty.", + "result": { + "greeting": "Hello" + }, + "response": { + "status_code": 200, + "headers": { + "X-Greeting": "Hello" + }, + "body": "{}" + } + }, + { + "id": "RestJsonGreetingWithErrorsNoPayload", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true + }, + "description": "This test is similar to RestJsonGreetingWithErrors, but it\nensures that clients can gracefully deal with a server\nomitting a response payload.", + "result": { + "greeting": "Hello" + }, + "response": { + "status_code": 200, + "headers": { + "X-Greeting": "Hello" + }, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "MapMember": { - "a": [1, 2], - "b": [3, 4] - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"MapMember\": {\"a\": [1, 2], \"b\": [3, 4]}}" - } - } - ] - }, - { - "description": "Complex Map Values", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FooError": { + "type": "structure", + "members": {}, + "documentation": "

This error has test cases that test some of the dark corners of Amazon service framework history. It should only be implemented by clients.

", + "error": { + "httpStatusCode": 500 + }, + "exception": true, + "fault": true + } + }, + "cases": [ + { + "id": "RestJsonFooErrorUsingXAmznErrorType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Serializes the X-Amzn-ErrorType header. For an example service, see Amazon EKS.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError" + } + } + }, + { + "id": "RestJsonFooErrorUsingXAmznErrorTypeWithUri", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some X-Amzn-Errortype headers contain URLs. Clients need to split the URL on ':' and take only the first half of the string. For example, 'ValidationException:http://internal.amazon.com/coral/com.amazon.coral.validate/'\nis to be interpreted as 'ValidationException'.\n\nFor an example service see Amazon Polly.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "RestJsonFooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "X-Amzn-Errortype might contain a URL and a namespace. Client should extract only the shape name. This is a pathalogical case that might not actually happen in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + { + "id": "RestJsonFooErrorUsingCode", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "This example uses the 'code' property in the output rather than X-Amzn-Errortype. Some services do this though it's preferable to send the X-Amzn-Errortype. Client implementations must first check for the X-Amzn-Errortype and then check for a top-level 'code' property.\n\nFor example service see Amazon S3 Glacier.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"code\": \"FooError\"\n}" + } + }, + { + "id": "RestJsonFooErrorUsingCodeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"code\": \"aws.protocoltests.restjson#FooError\"\n}" + } + }, + { + "id": "RestJsonFooErrorUsingCodeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using code, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"code\": \"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + }, + { + "id": "RestJsonFooErrorWithDunderType", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"__type\": \"FooError\"\n}" + } + }, + { + "id": "RestJsonFooErrorWithDunderTypeAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"__type\": \"aws.protocoltests.restjson#FooError\"\n}" + } + }, + { + "id": "RestJsonFooErrorWithDunderTypeUriAndNamespace", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "FooError" + } + ] + }, + "description": "Some services serialize errors using __type, and it might contain a namespace. It also might contain a URI. Clients should just take the last part of the string after '#' and before \":\". This is a pathalogical case that might not occur in any deployed AWS service.", + "errorCode": "FooError", + "error": {}, + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"__type\": \"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/\"\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "MapMember": { - "shape": "MapType" - } - } - }, - "MapType": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "TimeType" - } - }, - "TimeType": { - "type": "timestamp" - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "Header": { + "shape": "String", + "location": "header", + "locationName": "X-Header" + }, + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "error": { + "httpStatusCode": 403, + "senderFault": true + }, + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String", + "locationName": "Fooooo" + } + } + } + }, + "cases": [ + { + "id": "RestJsonComplexErrorWithNoMessage", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "description": "Serializes a complex error with no message member", + "errorCode": "ComplexError", + "error": { + "Header": "Header", + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 403, + "headers": { + "Content-Type": "application/json", + "X-Amzn-Errortype": "ComplexError", + "X-Header": "Header" + }, + "body": "{\n \"TopLevel\": \"Top level\",\n \"Nested\": {\n \"Fooooo\": \"bar\"\n }\n}" + } + }, + { + "id": "RestJsonEmptyComplexErrorWithNoMessage", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "errorCode": "ComplexError", + "error": {}, + "response": { + "status_code": 403, + "headers": { + "Content-Type": "application/json", + "X-Amzn-Errortype": "ComplexError" + }, + "body": "{}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "MapMember": { - "a": 1398796238, - "b": 1398796238 - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"MapMember\": {\"a\": 1398796238, \"b\": 1398796238}}" - } - } - ] - }, - { - "description": "Ignores extra data", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "error": { + "httpStatusCode": 400, + "senderFault": true + }, + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonInvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has four possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.
  4. A FooError.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple JSON errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/json", + "X-Amzn-Errortype": "InvalidGreeting" + }, + "body": "{\n \"Message\": \"Hi\"\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "StrType": { - "shape": "StrType" - } - } - }, - "StrType": { - "type": "string" - } + { + "description": "Test cases for HttpEnumPayload operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "EnumPayloadInput": { + "type": "structure", + "members": { + "payload": { + "shape": "StringEnum" + } + }, + "payload": "payload" + }, + "StringEnum": { + "type": "string", + "enum": [ + "enumvalue" + ] + } + }, + "cases": [ + { + "id": "RestJsonEnumPayloadResponse", + "given": { + "name": "HttpEnumPayload", + "http": { + "method": "POST", + "requestUri": "/EnumPayload", + "responseCode": 200 + }, + "output": { + "shape": "EnumPayloadInput" + } + }, + "result": { + "payload": "enumvalue" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/plain" + }, + "body": "enumvalue" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": {}, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"foo\": \"bar\"}" - } - } - ] - }, - { - "description": "Ignores undefined output", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for HttpPayloadTraits operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadTraitsInputOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "blob": { + "shape": "Blob" + } + }, + "payload": "blob" + }, + "String": { + "type": "string" + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "RestJsonHttpPayloadTraitsWithBlob", + "given": { + "name": "HttpPayloadTraits", + "http": { + "method": "POST", + "requestUri": "/HttpPayloadTraits", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadTraitsInputOutput" + }, + "documentation": "

This example serializes a blob shape in the payload.

In this example, no JSON document is synthesized because the payload is not a structure or a union type.

" + }, + "description": "Serializes a blob in the HTTP payload", + "result": { + "foo": "Foo", + "blob": "blobby blob blob" + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo" + }, + "body": "blobby blob blob" + } + }, + { + "id": "RestJsonHttpPayloadTraitsWithNoBlobBody", + "given": { + "name": "HttpPayloadTraits", + "http": { + "method": "POST", + "requestUri": "/HttpPayloadTraits", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadTraitsInputOutput" + }, + "documentation": "

This example serializes a blob shape in the payload.

In this example, no JSON document is synthesized because the payload is not a structure or a union type.

" + }, + "description": "Serializes an empty blob in the HTTP payload", + "result": { + "foo": "Foo" + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo" + }, + "body": "" + } + } + ] }, - "shapes": {}, - "cases": [ - { - "given": { - "name": "OperationName" - }, - "result": {}, - "response": { - "status_code": 200, - "headers": {}, - "body": "OK" - } - } - ] - }, - { - "description": "Supports header maps", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for HttpPayloadWithStructure operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithStructureInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "NestedPayload" + } + }, + "payload": "nested" + }, + "NestedPayload": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + }, + "name": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonHttpPayloadWithStructure", + "given": { + "name": "HttpPayloadWithStructure", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithStructure", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithStructureInputOutput" + }, + "documentation": "

This example serializes a structure in the payload.

Note that serializing a structure changes the wrapper element name to match the targeted structure.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload", + "result": { + "nested": { + "greeting": "hello", + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"greeting\": \"hello\",\n \"name\": \"Phreddy\"\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "AllHeaders": { - "shape": "HeaderMap", - "location": "headers" - }, - "PrefixedHeaders": { - "shape": "HeaderMap", - "location": "headers", - "locationName": "X-" - } - } - }, - "HeaderMap": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for HttpPayloadWithUnion operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithUnionInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "UnionPayload" + } + }, + "payload": "nested" + }, + "UnionPayload": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + }, + "union": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonHttpPayloadWithUnion", + "given": { + "name": "HttpPayloadWithUnion", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithUnion", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithUnionInputOutput" + }, + "documentation": "

This example serializes a union in the payload.

", + "idempotent": true + }, + "description": "Serializes a union in the payload.", + "result": { + "nested": { + "greeting": "hello" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"greeting\": \"hello\"\n}" + } + }, + { + "id": "RestJsonHttpPayloadWithUnsetUnion", + "given": { + "name": "HttpPayloadWithUnion", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithUnion", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithUnionInputOutput" + }, + "documentation": "

This example serializes a union in the payload.

", + "idempotent": true + }, + "description": "No payload is sent if the union has no value.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Length": "0" + }, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "AllHeaders": { - "Content-Length": "10", - "x-Foo": "bar", - "X-bam": "boo" - }, - "PrefixedHeaders": { - "Foo": "bar", - "bam": "boo" - } - }, - "response": { - "status_code": 200, - "headers": { - "Content-Length": "10", - "x-Foo": "bar", - "X-bam": "boo" - }, - "body": "{}" - } - } - ] - }, - { - "description": "JSON payload", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for HttpPrefixHeaders operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPrefixHeadersOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "fooMap": { + "shape": "StringMap", + "location": "headers", + "locationName": "X-Foo-" + } + } + }, + "String": { + "type": "string" + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + } + }, + "cases": [ + { + "id": "RestJsonHttpPrefixHeadersArePresent", + "given": { + "name": "HttpPrefixHeaders", + "http": { + "method": "GET", + "requestUri": "/HttpPrefixHeaders", + "responseCode": 200 + }, + "output": { + "shape": "HttpPrefixHeadersOutput" + }, + "documentation": "

This examples adds headers to the input of a request and response by prefix.

" + }, + "description": "Adds headers by prefix", + "result": { + "foo": "Foo", + "fooMap": { + "Abc": "Abc value", + "Def": "Def value" + } + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo", + "X-Foo-Abc": "Abc value", + "X-Foo-Def": "Def value" + } + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "payload": "Data", - "members": { - "Header": { - "shape": "StringType", - "location": "header", - "locationName": "X-Foo" - }, - "Data": { - "shape": "BodyStructure" - } - } - }, - "BodyStructure": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for HttpPrefixHeadersInResponse operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPrefixHeadersInResponseOutput": { + "type": "structure", + "members": { + "prefixHeaders": { + "shape": "StringMap", + "location": "headers", + "locationName": "" + } + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPrefixHeadersResponse", + "given": { + "name": "HttpPrefixHeadersInResponse", + "http": { + "method": "GET", + "requestUri": "/HttpPrefixHeadersResponse", + "responseCode": 200 + }, + "output": { + "shape": "HttpPrefixHeadersInResponseOutput" + }, + "documentation": "

Clients that perform this test extract all headers from the response.

" + }, + "description": "(de)serializes all response headers", + "result": { + "prefixHeaders": { + "X-Foo": "Foo", + "Hello": "Hello" + } + }, + "response": { + "status_code": 200, + "headers": { + "Hello": "Hello", + "X-Foo": "Foo" + } + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Header": "baz", - "Data": { - "Foo": "abc" - } - }, - "response": { - "status_code": 200, - "headers": { - "X-Foo": "baz" - }, - "body": "{\"Foo\": \"abc\"}" - } - } - ] - }, - { - "description": "Streaming payload", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for HttpResponseCode operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpResponseCodeOutput": { + "type": "structure", + "members": { + "Status": { + "shape": "Integer", + "location": "statusCode" + } + } + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "RestJsonHttpResponseCode", + "given": { + "name": "HttpResponseCode", + "http": { + "method": "PUT", + "requestUri": "/HttpResponseCode", + "responseCode": 200 + }, + "output": { + "shape": "HttpResponseCodeOutput" + }, + "idempotent": true + }, + "description": "Binds the http response code to an output structure. Note that\neven though all members are bound outside of the payload, an\nempty JSON object is serialized in the response. However,\nclients should be able to handle an empty JSON object or an\nempty payload without failing to deserialize a response.", + "result": { + "Status": 201 + }, + "response": { + "status_code": 201, + "headers": { + "Content-Type": "application/json" + }, + "body": "{}" + } + }, + { + "id": "RestJsonHttpResponseCodeWithNoPayload", + "given": { + "name": "HttpResponseCode", + "http": { + "method": "PUT", + "requestUri": "/HttpResponseCode", + "responseCode": 200 + }, + "output": { + "shape": "HttpResponseCodeOutput" + }, + "idempotent": true + }, + "description": "This test ensures that clients gracefully handle cases where\nthe service responds with no payload rather than an empty JSON\nobject.", + "result": { + "Status": 201 + }, + "response": { + "status_code": 201, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "payload": "Stream", - "members": { - "Stream": { - "shape": "Stream" - } - } - }, - "Stream": { - "type": "blob" - } + { + "description": "Test cases for HttpStringPayload operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "StringPayloadInput": { + "type": "structure", + "members": { + "payload": { + "shape": "String" + } + }, + "payload": "payload" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonStringPayloadResponse", + "given": { + "name": "HttpStringPayload", + "http": { + "method": "POST", + "requestUri": "/StringPayload", + "responseCode": 200 + }, + "output": { + "shape": "StringPayloadInput" + } + }, + "result": { + "payload": "rawstring" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/plain" + }, + "body": "rawstring" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Stream": "abc" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc" - } - } - ] - }, - { - "description": "JSON value trait", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for IgnoreQueryParamsInResponse operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "IgnoreQueryParamsInResponseOutput": { + "type": "structure", + "members": { + "baz": { + "shape": "String", + "location": "uri", + "locationName": "baz" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonIgnoreQueryParamsInResponse", + "given": { + "name": "IgnoreQueryParamsInResponse", + "http": { + "method": "GET", + "requestUri": "/IgnoreQueryParamsInResponse", + "responseCode": 200 + }, + "output": { + "shape": "IgnoreQueryParamsInResponseOutput" + }, + "documentation": "

This example ensures that query string bound request parameters are serialized in the body of responses if the structure is used in both the request and response.

" + }, + "description": "Query parameters must be ignored when serializing the output\nof an operation. As of January 2021, server implementations\nare expected to respond with a JSON object regardless of\nif the output parameters are empty.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{}" + } + }, + { + "id": "RestJsonIgnoreQueryParamsInResponseNoPayload", + "given": { + "name": "IgnoreQueryParamsInResponse", + "http": { + "method": "GET", + "requestUri": "/IgnoreQueryParamsInResponse", + "responseCode": 200 + }, + "output": { + "shape": "IgnoreQueryParamsInResponseOutput" + }, + "documentation": "

This example ensures that query string bound request parameters are serialized in the body of responses if the structure is used in both the request and response.

" + }, + "description": "This test is similar to RestJsonIgnoreQueryParamsInResponse,\nbut it ensures that clients gracefully handle responses from\nthe server that do not serialize an empty JSON object.", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Attr": { - "shape": "StringType", - "jsonvalue": true, - "location": "header", - "locationName": "X-Amz-Foo" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for InputAndOutputWithHeaders operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "InputAndOutputWithHeadersIO": { + "type": "structure", + "members": { + "headerString": { + "shape": "String", + "location": "header", + "locationName": "X-String" + }, + "headerByte": { + "shape": "Integer", + "location": "header", + "locationName": "X-Byte" + }, + "headerShort": { + "shape": "Integer", + "location": "header", + "locationName": "X-Short" + }, + "headerInteger": { + "shape": "Integer", + "location": "header", + "locationName": "X-Integer" + }, + "headerLong": { + "shape": "Long", + "location": "header", + "locationName": "X-Long" + }, + "headerFloat": { + "shape": "Float", + "location": "header", + "locationName": "X-Float" + }, + "headerDouble": { + "shape": "Double", + "location": "header", + "locationName": "X-Double" + }, + "headerTrueBool": { + "shape": "Boolean", + "location": "header", + "locationName": "X-Boolean1" + }, + "headerFalseBool": { + "shape": "Boolean", + "location": "header", + "locationName": "X-Boolean2" + }, + "headerStringList": { + "shape": "StringList", + "location": "header", + "locationName": "X-StringList" + }, + "headerStringSet": { + "shape": "StringSet", + "location": "header", + "locationName": "X-StringSet" + }, + "headerIntegerList": { + "shape": "IntegerList", + "location": "header", + "locationName": "X-IntegerList" + }, + "headerBooleanList": { + "shape": "BooleanList", + "location": "header", + "locationName": "X-BooleanList" + }, + "headerTimestampList": { + "shape": "TimestampList", + "location": "header", + "locationName": "X-TimestampList" + }, + "headerEnum": { + "shape": "FooEnum", + "location": "header", + "locationName": "X-Enum" + }, + "headerEnumList": { + "shape": "FooEnumList", + "location": "header", + "locationName": "X-EnumList" + }, + "headerIntegerEnum": { + "shape": "IntegerEnum", + "location": "header", + "locationName": "X-IntegerEnum" + }, + "headerIntegerEnumList": { + "shape": "IntegerEnumList", + "location": "header", + "locationName": "X-IntegerEnumList" + } + } + }, + "String": { + "type": "string" + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "Timestamp": { + "type": "timestamp" + } + }, + "cases": [ + { + "id": "RestJsonInputAndOutputWithStringHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with string header bindings", + "result": { + "headerString": "Hello", + "headerStringList": [ + "a", + "b", + "c" + ], + "headerStringSet": [ + "a", + "b", + "c" + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-String": "Hello", + "X-StringList": "a, b, c", + "X-StringSet": "a, b, c" + } + } + }, + { + "id": "RestJsonInputAndOutputWithQuotedStringHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with string list header bindings that require quoting", + "result": { + "headerStringList": [ + "b,c", + "\"def\"", + "a" + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-StringList": "\"b,c\", \"\\\"def\\\"\", a" + } + } + }, + { + "id": "RestJsonInputAndOutputWithNumericHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with numeric header bindings", + "result": { + "headerByte": 1, + "headerShort": 123, + "headerInteger": 123, + "headerLong": 123, + "headerFloat": 1.1, + "headerDouble": 1.1, + "headerIntegerList": [ + 1, + 2, + 3 + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Byte": "1", + "X-Double": "1.1", + "X-Float": "1.1", + "X-Integer": "123", + "X-IntegerList": "1, 2, 3", + "X-Long": "123", + "X-Short": "123" + } + } + }, + { + "id": "RestJsonInputAndOutputWithBooleanHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with boolean header bindings", + "result": { + "headerTrueBool": true, + "headerFalseBool": false, + "headerBooleanList": [ + true, + false, + true + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Boolean1": "true", + "X-Boolean2": "false", + "X-BooleanList": "true, false, true" + } + } + }, + { + "id": "RestJsonInputAndOutputWithTimestampHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with timestamp header bindings", + "result": { + "headerTimestampList": [ + 1576540098, + 1576540098 + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-TimestampList": "Mon, 16 Dec 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT" + } + } + }, + { + "id": "RestJsonInputAndOutputWithEnumHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with enum header bindings", + "result": { + "headerEnum": "Foo", + "headerEnumList": [ + "Foo", + "Bar", + "Baz" + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Enum": "Foo", + "X-EnumList": "Foo, Bar, Baz" + } + } + }, + { + "id": "RestJsonInputAndOutputWithIntEnumHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with intEnum header bindings", + "result": { + "headerIntegerEnum": 1, + "headerIntegerEnumList": [ + 1, + 2, + 3 + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-IntegerEnum": "1", + "X-IntegerEnumList": "1, 2, 3" + } + } + }, + { + "id": "RestJsonSupportsNaNFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling NaN float header values.", + "result": { + "headerFloat": "NaN", + "headerDouble": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "NaN", + "X-Float": "NaN" + } + } + }, + { + "id": "RestJsonSupportsInfinityFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling Infinity float header values.", + "result": { + "headerFloat": "Infinity", + "headerDouble": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "Infinity", + "X-Float": "Infinity" + } + } + }, + { + "id": "RestJsonSupportsNegativeInfinityFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling -Infinity float header values.", + "result": { + "headerFloat": "-Infinity", + "headerDouble": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "-Infinity", + "X-Float": "-Infinity" + } + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Attr": {"Foo":"Bar"} - }, - "response": { - "status_code": 200, - "headers": {"X-Amz-Foo": "eyJGb28iOiJCYXIifQ=="}, - "body": "" - } - } - ] - }, - { - "description": "Modeled exceptions", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for JsonBlobs operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonBlobsInputOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "RestJsonJsonBlobs", + "given": { + "name": "JsonBlobs", + "http": { + "method": "POST", + "requestUri": "/JsonBlobs", + "responseCode": 200 + }, + "output": { + "shape": "JsonBlobsInputOutput" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Blobs are base64 encoded", + "result": { + "data": "value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"data\": \"dmFsdWU=\"\n}" + } + } + ] }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "ImaHeader": { - "shape": "HeaderShape" - }, - "ImaHeaderLocation": { - "shape": "HeaderShape", - "locationName": "X-Foo" - }, - "Status": { - "shape": "StatusShape", - "location": "statusCode" - }, - "BodyMember": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "OtherExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - } - } - }, - "HeaderShape": { - "type": "string", - "location": "header" - }, - "StatusShape": { - "type": "integer" - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for JsonEnums operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonEnumsInputOutput": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonJsonEnums", + "given": { + "name": "JsonEnums", + "http": { + "method": "PUT", + "requestUri": "/JsonEnums", + "responseCode": 200 + }, + "output": { + "shape": "JsonEnumsInputOutput" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"fooEnum1\": \"Foo\",\n \"fooEnum2\": \"0\",\n \"fooEnum3\": \"1\",\n \"fooEnumList\": [\n \"Foo\",\n \"0\"\n ],\n \"fooEnumSet\": [\n \"Foo\",\n \"0\"\n ],\n \"fooEnumMap\": {\n \"hi\": \"Foo\",\n \"zero\": \"0\"\n }\n}" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Status": 400, - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Errortype": "ExceptionShape" - }, - "body": "{\"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Status": 400, - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "{ \"code\": \"ExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Status": 400, - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Errortype": "ExceptionShape" - }, - "body": "{ \"code\": \"OtherExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Errortype": "OtherExceptionShape" - }, - "body": "{ \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "{ \"code\": \"OtherExceptionShape\", \"BodyMember\": \"mybody\", \"Message\": \"mymessage\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": {}, - "errorCode": "UndefinedShape", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Errortype": "UndefinedShape" - }, - "body": "{ \"BodyMember\": \"mybody\"}" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": {}, - "errorCode": "UndefinedShape", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "{ \"code\": \"UndefinedShape\", \"BodyMember\": \"mybody\"}" - } - } - ] - }, - { - "description": "Serializes document with standalone primitive as part of the JSON response payload with no escaping.", - "metadata": { - "protocol": "rest-json", - "apiVersion": "2014-01-01" + { + "description": "Test cases for JsonIntEnums operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonIntEnumsInputOutput": { + "type": "structure", + "members": { + "integerEnum1": { + "shape": "IntegerEnum" + }, + "integerEnum2": { + "shape": "IntegerEnum" + }, + "integerEnum3": { + "shape": "IntegerEnum" + }, + "integerEnumList": { + "shape": "IntegerEnumList" + }, + "integerEnumSet": { + "shape": "IntegerEnumSet" + }, + "integerEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestJsonJsonIntEnums", + "given": { + "name": "JsonIntEnums", + "http": { + "method": "PUT", + "requestUri": "/JsonIntEnums", + "responseCode": 200 + }, + "output": { + "shape": "JsonIntEnumsInputOutput" + }, + "documentation": "

This example serializes intEnums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes intEnums as integers", + "result": { + "integerEnum1": 1, + "integerEnum2": 2, + "integerEnum3": 3, + "integerEnumList": [ + 1, + 2, + 3 + ], + "integerEnumSet": [ + 1, + 2 + ], + "integerEnumMap": { + "abc": 1, + "def": 2 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"integerEnum1\": 1,\n \"integerEnum2\": 2,\n \"integerEnum3\": 3,\n \"integerEnumList\": [\n 1,\n 2,\n 3\n ],\n \"integerEnumSet\": [\n 1,\n 2\n ],\n \"integerEnumMap\": {\n \"abc\": 1,\n \"def\": 2\n }\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "documentValue": { - "shape": "DocumentType" - } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + { + "description": "Test cases for JsonLists operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonListsInputOutput": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "RestJsonLists", + "given": { + "name": "JsonLists", + "http": { + "method": "PUT", + "requestUri": "/JsonLists", + "responseCode": 200 + }, + "output": { + "shape": "JsonListsInputOutput" + }, + "documentation": "

This test case serializes JSON lists for the following cases for both input and output:

  1. Normal JSON lists.
  2. Normal JSON sets.
  3. JSON lists of lists.
  4. Lists of structures.
", + "idempotent": true + }, + "description": "Serializes JSON lists", + "result": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238, + 1398796238 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringList\": [\n \"foo\",\n \"bar\"\n ],\n \"stringSet\": [\n \"foo\",\n \"bar\"\n ],\n \"integerList\": [\n 1,\n 2\n ],\n \"booleanList\": [\n true,\n false\n ],\n \"timestampList\": [\n 1398796238,\n 1398796238\n ],\n \"enumList\": [\n \"Foo\",\n \"0\"\n ],\n \"intEnumList\": [\n 1,\n 2\n ],\n \"nestedStringList\": [\n [\n \"foo\",\n \"bar\"\n ],\n [\n \"baz\",\n \"qux\"\n ]\n ],\n \"myStructureList\": [\n {\n \"value\": \"1\",\n \"other\": \"2\"\n },\n {\n \"value\": \"3\",\n \"other\": \"4\"\n }\n ]\n}" + } + }, + { + "id": "RestJsonListsEmpty", + "given": { + "name": "JsonLists", + "http": { + "method": "PUT", + "requestUri": "/JsonLists", + "responseCode": 200 + }, + "output": { + "shape": "JsonListsInputOutput" + }, + "documentation": "

This test case serializes JSON lists for the following cases for both input and output:

  1. Normal JSON lists.
  2. Normal JSON sets.
  3. JSON lists of lists.
  4. Lists of structures.
", + "idempotent": true + }, + "description": "Serializes empty JSON lists", + "result": { + "stringList": [] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringList\": []\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": "foo" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": \"foo\"}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": 123 - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": 123}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": 1.2 - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": 1.2}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": true - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": true}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": "" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": \"\"}" - } - } - ] - }, - { - "description": "Serializes inline documents as part of the JSON response payload with no escaping.", - "metadata": { - "protocol": "rest-json", - "apiVersion": "2014-01-01" + { + "description": "Test cases for JsonMaps operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonMapsInputOutput": { + "type": "structure", + "members": { + "denseStructMap": { + "shape": "DenseStructMap" + }, + "denseNumberMap": { + "shape": "DenseNumberMap" + }, + "denseBooleanMap": { + "shape": "DenseBooleanMap" + }, + "denseStringMap": { + "shape": "DenseStringMap" + }, + "denseSetMap": { + "shape": "DenseSetMap" + } + } + }, + "DenseStructMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "DenseNumberMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "Integer" + } + }, + "DenseBooleanMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "Boolean" + } + }, + "DenseStringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "DenseSetMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "StringSet" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "RestJsonJsonMaps", + "given": { + "name": "JsonMaps", + "http": { + "method": "POST", + "requestUri": "/JsonMaps", + "responseCode": 200 + }, + "output": { + "shape": "JsonMapsInputOutput" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "Deserializes JSON maps", + "result": { + "denseStructMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"denseStructMap\": {\n \"foo\": {\n \"hi\": \"there\"\n },\n \"baz\": {\n \"hi\": \"bye\"\n }\n }\n}" + } + }, + { + "id": "RestJsonDeserializesZeroValuesInMaps", + "given": { + "name": "JsonMaps", + "http": { + "method": "POST", + "requestUri": "/JsonMaps", + "responseCode": 200 + }, + "output": { + "shape": "JsonMapsInputOutput" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "result": { + "denseNumberMap": { + "x": 0 + }, + "denseBooleanMap": { + "x": false + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"denseNumberMap\": {\n \"x\": 0\n },\n \"denseBooleanMap\": {\n \"x\": false\n }\n}" + } + }, + { + "id": "RestJsonDeserializesDenseSetMap", + "given": { + "name": "JsonMaps", + "http": { + "method": "POST", + "requestUri": "/JsonMaps", + "responseCode": 200 + }, + "output": { + "shape": "JsonMapsInputOutput" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "A response that contains a dense map of sets.", + "result": { + "denseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"denseSetMap\": {\n \"x\": [],\n \"y\": [\"a\", \"b\"]\n }\n}" + } + }, + { + "id": "RestJsonDeserializesDenseSetMapAndSkipsNull", + "given": { + "name": "JsonMaps", + "http": { + "method": "POST", + "requestUri": "/JsonMaps", + "responseCode": 200 + }, + "output": { + "shape": "JsonMapsInputOutput" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "Clients SHOULD tolerate seeing a null value in a dense map, and they SHOULD\ndrop the null key-value pair.", + "result": { + "denseSetMap": { + "x": [], + "y": [ + "a", + "b" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"denseSetMap\": {\n \"x\": [],\n \"y\": [\"a\", \"b\"],\n \"z\": null\n }\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "documentValue": { - "shape": "DocumentType" - } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + { + "description": "Test cases for JsonTimestamps operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "JsonTimestampsInputOutput": { + "type": "structure", + "members": { + "normal": { + "shape": "Timestamp" + }, + "dateTime": { + "shape": "SyntheticTimestamp_date_time" + }, + "dateTimeOnTarget": { + "shape": "DateTime" + }, + "epochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds" + }, + "epochSecondsOnTarget": { + "shape": "EpochSeconds" + }, + "httpDate": { + "shape": "SyntheticTimestamp_http_date" + }, + "httpDateOnTarget": { + "shape": "HttpDate" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + } + }, + "cases": [ + { + "id": "RestJsonJsonTimestamps", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Tests how normal timestamps are serialized", + "result": { + "normal": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"normal\": 1398796238\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithDateTimeFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time works like normal timestamps", + "result": { + "dateTime": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"dateTime\": \"2014-04-29T18:30:38Z\"\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithDateTimeOnTargetFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time on the target shape works like normal timestamps", + "result": { + "dateTimeOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"dateTimeOnTarget\": \"2014-04-29T18:30:38Z\"\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithEpochSecondsFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds works", + "result": { + "epochSeconds": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"epochSeconds\": 1398796238\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithEpochSecondsOnTargetFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds on the target shape works", + "result": { + "epochSecondsOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"epochSecondsOnTarget\": 1398796238\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithHttpDateFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date works", + "result": { + "httpDate": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"httpDate\": \"Tue, 29 Apr 2014 18:30:38 GMT\"\n}" + } + }, + { + "id": "RestJsonJsonTimestampsWithHttpDateOnTargetFormat", + "given": { + "name": "JsonTimestamps", + "http": { + "method": "POST", + "requestUri": "/JsonTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "JsonTimestampsInputOutput" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date on the target shape works", + "result": { + "httpDateOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"httpDateOnTarget\": \"Tue, 29 Apr 2014 18:30:38 GMT\"\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": {"foo": "bar"} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": {\"foo\": \"bar\"}}" - } - } - ] - }, - { - "description": "Serializes aggregate documents as part of the JSON response payload with no escaping.", - "metadata": { - "protocol": "rest-json", - "apiVersion": "2014-01-01" + { + "description": "Test cases for JsonUnions operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "UnionInputOutput": { + "type": "structure", + "members": { + "contents": { + "shape": "MyUnion" + } + }, + "documentation": "

A shared structure that contains a single union member.

" + }, + "MyUnion": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "booleanValue": { + "shape": "Boolean" + }, + "numberValue": { + "shape": "Integer" + }, + "blobValue": { + "shape": "Blob" + }, + "timestampValue": { + "shape": "Timestamp" + }, + "enumValue": { + "shape": "FooEnum" + }, + "listValue": { + "shape": "StringList" + }, + "mapValue": { + "shape": "StringMap" + }, + "structureValue": { + "shape": "GreetingStruct" + }, + "renamedStructureValue": { + "shape": "RenamedGreeting" + } + }, + "documentation": "

A union with a representative set of types for members.

", + "union": true + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Blob": { + "type": "blob" + }, + "Timestamp": { + "type": "timestamp" + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "RenamedGreeting": { + "type": "structure", + "members": { + "salutation": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "RestJsonDeserializeStringUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a string union value", + "result": { + "contents": { + "stringValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"stringValue\": \"foo\"\n }\n}" + } + }, + { + "id": "RestJsonDeserializeBooleanUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a boolean union value", + "result": { + "contents": { + "booleanValue": true + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"booleanValue\": true\n }\n}" + } + }, + { + "id": "RestJsonDeserializeNumberUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a number union value", + "result": { + "contents": { + "numberValue": 1 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"numberValue\": 1\n }\n}" + } + }, + { + "id": "RestJsonDeserializeBlobUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a blob union value", + "result": { + "contents": { + "blobValue": "foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"blobValue\": \"Zm9v\"\n }\n}" + } + }, + { + "id": "RestJsonDeserializeTimestampUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a timestamp union value", + "result": { + "contents": { + "timestampValue": 1398796238 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"timestampValue\": 1398796238\n }\n}" + } + }, + { + "id": "RestJsonDeserializeEnumUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes an enum union value", + "result": { + "contents": { + "enumValue": "Foo" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"enumValue\": \"Foo\"\n }\n}" + } + }, + { + "id": "RestJsonDeserializeListUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a list union value", + "result": { + "contents": { + "listValue": [ + "foo", + "bar" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"listValue\": [\"foo\", \"bar\"]\n }\n}" + } + }, + { + "id": "RestJsonDeserializeMapUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a map union value", + "result": { + "contents": { + "mapValue": { + "foo": "bar", + "spam": "eggs" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"mapValue\": {\n \"foo\": \"bar\",\n \"spam\": \"eggs\"\n }\n }\n}" + } + }, + { + "id": "RestJsonDeserializeStructureUnionValue", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Deserializes a structure union value", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + }, + { + "id": "RestJsonDeserializeIgnoreType", + "given": { + "name": "JsonUnions", + "http": { + "method": "PUT", + "requestUri": "/JsonUnions", + "responseCode": 200 + }, + "output": { + "shape": "UnionInputOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "description": "Ignores an unrecognized __type property", + "result": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"contents\": {\n \"__type\": \"aws.protocoltests.json10#MyUnion\",\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "documentValue": { - "shape": "DocumentType" - } - } - }, - "DocumentType": { - "type": "structure", - "document": true - } + { + "description": "Test cases for MediaTypeHeader operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "MediaTypeHeaderOutput": { + "type": "structure", + "members": { + "json": { + "shape": "JsonValue", + "jsonvalue": true, + "location": "header", + "locationName": "X-Json" + } + } + }, + "JsonValue": { + "type": "string" + } + }, + "cases": [ + { + "id": "MediaTypeHeaderOutputBase64", + "given": { + "name": "MediaTypeHeader", + "http": { + "method": "GET", + "requestUri": "/MediaTypeHeader", + "responseCode": 200 + }, + "output": { + "shape": "MediaTypeHeaderOutput" + }, + "documentation": "

This example ensures that mediaType strings are base64 encoded in headers.

" + }, + "description": "Headers that target strings with a mediaType are base64 encoded", + "result": { + "json": "true" + }, + "response": { + "status_code": 200, + "headers": { + "X-Json": "dHJ1ZQ==" + } + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": { - "str": "test", - "num": 123, - "float": 1.2, - "bool": true, - "null": "", - "document": {"foo": false}, - "list": ["myname", 321, 1.3, true, "", {"nested": true}, [200, ""]] - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": {\"str\": \"test\", \"num\": 123, \"float\": 1.2, \"bool\": true, \"null\": \"\", \"document\": {\"foo\": false}, \"list\": [\"myname\", 321, 1.3, true, \"\", {\"nested\": true}, [200, \"\"]]}}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "documentValue": [ - "test", - 123, - 1.2, - true, - "", - {"str": "myname", "num": 321, "float": 1.3, "bool": true, "null": "", "document": {"nested": true}, "list": [200, ""]}, - ["foo", false] - ] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"documentValue\": [\"test\", 123, 1.2, true, \"\", {\"str\": \"myname\", \"num\": 321, \"float\": 1.3, \"bool\": true, \"null\": \"\", \"document\": {\"nested\": true}, \"list\": [200, \"\"]}, [\"foo\", false]]}" - } - } - ] - }, - { - "description": "Tagged Unions", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for NoInputAndNoOutput operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": {}, + "cases": [ + { + "id": "RestJsonNoInputAndNoOutput", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/NoInputAndNoOutput", + "responseCode": 200 + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output. While this should be rare, code generators must support this.

" + }, + "description": "When an operation does not define output, the service will respond\nwith an empty payload, and may optionally include the content-type\nheader.", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "UnionMember": { - "shape": "UnionType" - } - } - }, - "UnionType": { - "type": "structure", - "members": { - "S":{"shape":"StringType"}, - "L": {"shape": "ListType"} - }, - "union": true - }, - "ListType": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for NoInputAndOutput operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "RestJsonNoInputAndOutputWithJson", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/NoInputAndOutputOutput", + "responseCode": 200 + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input and the output is empty. While this should be rare, code generators must support this.

" + }, + "description": "Operations that define output and do not bind anything to\nthe payload return a JSON object in the response.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{}" + } + }, + { + "id": "RestJsonNoInputAndOutputNoPayload", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/NoInputAndOutputOutput", + "responseCode": 200 + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input and the output is empty. While this should be rare, code generators must support this.

" + }, + "description": "This test is similar to RestJsonNoInputAndOutputWithJson, but\nit ensures that clients can gracefully handle responses that\nomit a JSON payload.", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"S": "mystring"} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"UnionMember\": {\"S\": \"mystring\"}}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"L": ["a", "b"]} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"UnionMember\": {\"L\": [\"a\", \"b\"]}}" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"SDK_UNKNOWN_MEMBER": {"name": "SomeUnknownMember"}} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "{\"UnionMember\": {\"SomeUnknownMember\": \"foo\"}}" - } - } - ] - }, - { - "description": "List in header", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for PostUnionWithJsonName operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "PostUnionWithJsonNameOutput": { + "type": "structure", + "required": [ + "value" + ], + "members": { + "value": { + "shape": "UnionWithJsonName" + } + } + }, + "UnionWithJsonName": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "locationName": "FOO" + }, + "bar": { + "shape": "String" + }, + "baz": { + "shape": "String", + "locationName": "_baz" + } + }, + "union": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "PostUnionWithJsonNameResponse1", + "given": { + "name": "PostUnionWithJsonName", + "http": { + "method": "POST", + "requestUri": "/PostUnionWithJsonName", + "responseCode": 200 + }, + "output": { + "shape": "PostUnionWithJsonNameOutput" + }, + "documentation": "

This operation defines a union that uses jsonName on some members.

" + }, + "description": "Tests that jsonName works with union members.", + "result": { + "value": { + "foo": "hi" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"value\": {\n \"FOO\": \"hi\"\n }\n}" + } + }, + { + "id": "PostUnionWithJsonNameResponse2", + "given": { + "name": "PostUnionWithJsonName", + "http": { + "method": "POST", + "requestUri": "/PostUnionWithJsonName", + "responseCode": 200 + }, + "output": { + "shape": "PostUnionWithJsonNameOutput" + }, + "documentation": "

This operation defines a union that uses jsonName on some members.

" + }, + "description": "Tests that jsonName works with union members.", + "result": { + "value": { + "baz": "hi" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"value\": {\n \"_baz\": \"hi\"\n }\n}" + } + }, + { + "id": "PostUnionWithJsonNameResponse3", + "given": { + "name": "PostUnionWithJsonName", + "http": { + "method": "POST", + "requestUri": "/PostUnionWithJsonName", + "responseCode": 200 + }, + "output": { + "shape": "PostUnionWithJsonNameOutput" + }, + "documentation": "

This operation defines a union that uses jsonName on some members.

" + }, + "description": "Tests that jsonName works with union members.", + "result": { + "value": { + "bar": "hi" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"value\": {\n \"bar\": \"hi\"\n }\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape", - "location": "header", - "locationName": "x-amz-list-member" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "EnumType" - } - }, - "EnumType": { - "type": "string", - "enum": ["one", "two", "three"] - } + { + "description": "Test cases for RecursiveShapes operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "RecursiveShapesInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "RecursiveShapesInputOutputNested1" + } + } + }, + "RecursiveShapesInputOutputNested1": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "nested": { + "shape": "RecursiveShapesInputOutputNested2" + } + } + }, + "String": { + "type": "string" + }, + "RecursiveShapesInputOutputNested2": { + "type": "structure", + "members": { + "bar": { + "shape": "String" + }, + "recursiveMember": { + "shape": "RecursiveShapesInputOutputNested1" + } + } + } + }, + "cases": [ + { + "id": "RestJsonRecursiveShapes", + "given": { + "name": "RecursiveShapes", + "http": { + "method": "PUT", + "requestUri": "/RecursiveShapes", + "responseCode": 200 + }, + "output": { + "shape": "RecursiveShapesInputOutput" + }, + "documentation": "

Recursive shapes

", + "idempotent": true + }, + "description": "Serializes recursive structures", + "result": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"nested\": {\n \"foo\": \"Foo1\",\n \"nested\": {\n \"bar\": \"Bar1\",\n \"recursiveMember\": {\n \"foo\": \"Foo2\",\n \"nested\": {\n \"bar\": \"Bar2\"\n }\n }\n }\n }\n}" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["one", "two", "three"] - }, - "response": { - "status_code": 200, - "headers": { - "x-amz-list-member": " one,two , three " - }, - "body": "" - } - } - ] - }, - { - "description": "Number in header", - "metadata": { - "protocol": "rest-json" + { + "description": "Test cases for SimpleScalarProperties operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "SimpleScalarPropertiesInputOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "stringValue": { + "shape": "String" + }, + "trueBooleanValue": { + "shape": "Boolean" + }, + "falseBooleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double", + "locationName": "DoubleDribble" + } + } + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } + }, + "cases": [ + { + "id": "RestJsonSimpleScalarProperties", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + }, + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "foo": "Foo", + "stringValue": "string", + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json", + "X-Foo": "Foo" + }, + "body": "{\n \"stringValue\": \"string\",\n \"trueBooleanValue\": true,\n \"falseBooleanValue\": false,\n \"byteValue\": 1,\n \"shortValue\": 2,\n \"integerValue\": 3,\n \"longValue\": 4,\n \"floatValue\": 5.5,\n \"DoubleDribble\": 6.5\n}" + } + }, + { + "id": "RestJsonDoesntDeserializeNullStructureValues", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + }, + "idempotent": true + }, + "description": "Rest Json should not deserialize null structure values", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"stringValue\": null\n}" + } + }, + { + "id": "RestJsonSupportsNaNFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + }, + "idempotent": true + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"floatValue\": \"NaN\",\n \"DoubleDribble\": \"NaN\"\n}" + } + }, + { + "id": "RestJsonSupportsInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + }, + "idempotent": true + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"floatValue\": \"Infinity\",\n \"DoubleDribble\": \"Infinity\"\n}" + } + }, + { + "id": "RestJsonSupportsNegativeInfinityFloatInputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesInputOutput" + }, + "idempotent": true + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/json" + }, + "body": "{\n \"floatValue\": \"-Infinity\",\n \"DoubleDribble\": \"-Infinity\"\n}" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "IntegerMember": { - "shape": "IntegerShape", - "location": "header", - "locationName": "x-amz-integer-member" - }, - "LongMember": { - "shape": "LongShape", - "location": "header", - "locationName": "x-amz-long-member" - } - } - }, - "IntegerShape": { - "type": "integer" - }, - "LongShape": { - "type": "long" - } + { + "description": "Test cases for TimestampFormatHeaders operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "TimestampFormatHeadersIO": { + "type": "structure", + "members": { + "memberEpochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds", + "location": "header", + "locationName": "X-memberEpochSeconds" + }, + "memberHttpDate": { + "shape": "SyntheticTimestamp_http_date", + "location": "header", + "locationName": "X-memberHttpDate" + }, + "memberDateTime": { + "shape": "SyntheticTimestamp_date_time", + "location": "header", + "locationName": "X-memberDateTime" + }, + "defaultFormat": { + "shape": "Timestamp", + "location": "header", + "locationName": "X-defaultFormat" + }, + "targetEpochSeconds": { + "shape": "EpochSeconds", + "location": "header", + "locationName": "X-targetEpochSeconds" + }, + "targetHttpDate": { + "shape": "HttpDate", + "location": "header", + "locationName": "X-targetHttpDate" + }, + "targetDateTime": { + "shape": "DateTime", + "location": "header", + "locationName": "X-targetDateTime" + } + } + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "Timestamp": { + "type": "timestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "RestJsonTimestampFormatHeaders", + "given": { + "name": "TimestampFormatHeaders", + "http": { + "method": "POST", + "requestUri": "/TimestampFormatHeaders", + "responseCode": 200 + }, + "output": { + "shape": "TimestampFormatHeadersIO" + }, + "documentation": "

This example tests how timestamp request and response headers are serialized.

" + }, + "description": "Tests how timestamp response headers are serialized", + "result": { + "memberEpochSeconds": 1576540098, + "memberHttpDate": 1576540098, + "memberDateTime": 1576540098, + "defaultFormat": 1576540098, + "targetEpochSeconds": 1576540098, + "targetHttpDate": 1576540098, + "targetDateTime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "X-defaultFormat": "Mon, 16 Dec 2019 23:48:18 GMT", + "X-memberDateTime": "2019-12-16T23:48:18Z", + "X-memberEpochSeconds": "1576540098", + "X-memberHttpDate": "Mon, 16 Dec 2019 23:48:18 GMT", + "X-targetDateTime": "2019-12-16T23:48:18Z", + "X-targetEpochSeconds": "1576540098", + "X-targetHttpDate": "Mon, 16 Dec 2019 23:48:18 GMT" + } + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "IntegerMember": 123, - "LongMember": 200 - }, - "response": { - "status_code": 200, - "headers": { - "x-amz-integer-member": "123", - "x-amz-long-member": "200" - }, - "body": "" - } - } - ] - } + { + "description": "Test cases for UnitInputAndOutput operation", + "metadata": { + "protocol": "rest-json", + "protocols": [ + "rest-json" + ], + "apiVersion": "2019-12-16" + }, + "shapes": {}, + "cases": [ + { + "id": "RestJsonUnitInputAndOutputNoOutput", + "given": { + "name": "UnitInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/UnitInputAndOutput", + "responseCode": 200 + }, + "documentation": "

This test is similar to NoInputAndNoOutput, but uses explicit Unit types.

" + }, + "description": "When an operation defines Unit output, the service will respond\nwith an empty payload, and may optionally include the content-type\nheader.", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] + } ] diff --git a/tests/unit/protocols/output/rest-xml.json b/tests/unit/protocols/output/rest-xml.json index 8da4680960..9d2efabd01 100644 --- a/tests/unit/protocols/output/rest-xml.json +++ b/tests/unit/protocols/output/rest-xml.json @@ -1,1273 +1,4546 @@ [ - { - "description": "Scalar members", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for BodyWithXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "BodyWithXmlNameInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "PayloadWithXmlName" + } + }, + "locationName": "Ahoy" + }, + "PayloadWithXmlName": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + }, + "locationName": "Hello" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "BodyWithXmlName", + "given": { + "name": "BodyWithXmlName", + "http": { + "method": "PUT", + "requestUri": "/BodyWithXmlName", + "responseCode": 200 + }, + "output": { + "shape": "BodyWithXmlNameInputOutput" + }, + "documentation": "

The following example serializes a body that uses an XML name, changing the wrapper name.

", + "idempotent": true + }, + "description": "Serializes a payload using a wrapper name based on the xmlName", + "result": { + "nested": { + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "Phreddy" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ImaHeader": { - "shape": "HeaderShape" - }, - "ImaHeaderLocation": { - "shape": "HeaderShape", - "locationName": "X-Foo" - }, - "Str": { - "shape": "StringType" - }, - "Num": { - "shape": "IntegerType", - "locationName": "FooNum" - }, - "FalseBool": { - "shape": "BooleanType" - }, - "TrueBool": { - "shape": "BooleanType" - }, - "Float": { - "shape": "FloatType" - }, - "Double": { - "shape": "DoubleType" - }, - "Long": { - "shape": "LongType" - }, - "Char": { - "shape": "CharType" - }, - "Timestamp": { - "shape": "TimestampType" - } - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "FloatType": { - "type": "float" - }, - "DoubleType": { - "type": "double" - }, - "LongType": { - "type": "long" - }, - "CharType": { - "type": "character" - }, - "HeaderShape": { - "type": "string", - "location": "header" - }, - "StatusShape": { - "type": "integer", - "location": "statusCode" - }, - "TimestampType": { - "type": "timestamp" - } + { + "description": "Test cases for DatetimeOffsets operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "RestXmlDateTimeWithNegativeOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/DatetimeOffsets", + "responseCode": 200 + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2019-12-16T22:48:18-01:00\n\n" + } + }, + { + "id": "RestXmlDateTimeWithPositiveOffset", + "given": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/DatetimeOffsets", + "responseCode": 200 + }, + "output": { + "shape": "DatetimeOffsetsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", + "result": { + "datetime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2019-12-17T00:48:18+01:00\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Str": "myname", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a", - "Timestamp": 1422172800 - }, - "response": { - "status_code": 200, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "myname123falsetrue1.21.3200a2015-01-25T08:00:00Z" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Str": "", - "Num": 123, - "FalseBool": false, - "TrueBool": true, - "Float": 1.2, - "Double": 1.3, - "Long": 200, - "Char": "a", - "Timestamp": 1422172800 - }, - "response": { - "status_code": 200, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc" - }, - "body": "123falsetrue1.21.3200a2015-01-25T08:00:00Z" - } - } - ] - }, - { - "description": "Blob", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for EmptyInputAndEmptyOutput operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "EmptyInputAndEmptyOutput", + "given": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/EmptyInputAndEmptyOutput", + "responseCode": 200 + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has an empty input and empty output structure that reuses the same shape. While this should be rare, code generators must support this.

" + }, + "description": "Empty output serializes no payload", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Blob": { - "shape": "BlobType" - } - } - }, - "BlobType": { - "type": "blob" - } + { + "description": "Test cases for FlattenedXmlMap operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FlattenedXmlMapResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "FooEnumMap", + "flattened": true + } + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "FlattenedXmlMap", + "given": { + "name": "FlattenedXmlMap", + "http": { + "method": "POST", + "requestUri": "/FlattenedXmlMap", + "responseCode": 200 + }, + "output": { + "shape": "FlattenedXmlMapResponse" + }, + "documentation": "

Flattened maps

" + }, + "description": "Serializes flattened XML maps in responses", + "result": { + "myMap": { + "foo": "Foo", + "baz": "Baz" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n foo\n Foo\n \n \n baz\n Baz\n \n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Blob": "value" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "dmFsdWU=" - } - } - ] - }, - { - "description": "Lists", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for FlattenedXmlMapWithXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FlattenedXmlMapWithXmlNameResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "FlattenedXmlMapWithXmlNameInputOutputMap", + "flattened": true, + "locationName": "KVP" + } + } + }, + "FlattenedXmlMapWithXmlNameInputOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K" + }, + "value": { + "shape": "String", + "locationName": "V" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "FlattenedXmlMapWithXmlName", + "given": { + "name": "FlattenedXmlMapWithXmlName", + "http": { + "method": "POST", + "requestUri": "/FlattenedXmlMapWithXmlName", + "responseCode": 200 + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNameResponse" + }, + "documentation": "

Flattened maps with @xmlName

" + }, + "description": "Serializes flattened XML maps in responses that have xmlName on members", + "result": { + "myMap": { + "a": "A", + "b": "B" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n a\n A\n \n \n b\n B\n \n" + } + } + ] + }, + { + "description": "Test cases for FlattenedXmlMapWithXmlNamespace operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FlattenedXmlMapWithXmlNamespaceOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FlattenedXmlMapWithXmlNamespaceOutputMap", + "flattened": true, + "locationName": "KVP", + "xmlNamespace": "https://the-member.example.com" + } + } + }, + "FlattenedXmlMapWithXmlNamespaceOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K", + "xmlNamespace": "https://the-key.example.com" + }, + "value": { + "shape": "String", + "locationName": "V", + "xmlNamespace": "https://the-value.example.com" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestXmlFlattenedXmlMapWithXmlNamespace", + "given": { + "name": "FlattenedXmlMapWithXmlNamespace", + "http": { + "method": "POST", + "requestUri": "/FlattenedXmlMapWithXmlNamespace", + "responseCode": 200 + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNamespaceOutput" + }, + "documentation": "

Flattened maps with @xmlNamespace and @xmlName

" + }, + "description": "Serializes flattened XML maps in responses that have xmlNamespace and xmlName on members", + "result": { + "myMap": { + "a": "A", + "b": "B" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n a\n A\n \n \n b\n B\n \n" + } + } + ] + }, + { + "description": "Test cases for FractionalSeconds operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "RestXmlDateTimeWithFractionalSeconds", + "given": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/FractionalSeconds", + "responseCode": 200 + }, + "output": { + "shape": "FractionalSecondsOutput" + } + }, + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", + "result": { + "datetime": 9.46845296123E8 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2000-01-02T20:34:56.123Z\n\n" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String", + "location": "header", + "locationName": "X-Greeting" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "GreetingWithErrors", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true + }, + "description": "Ensures that operations with errors successfully know how to deserialize the successful response", + "result": { + "greeting": "Hello" + }, + "response": { + "status_code": 200, + "headers": { + "X-Greeting": "Hello" + }, + "body": "" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

This error is thrown when an invalid greeting value is provided.

", + "error": { + "httpStatusCode": 400, + "senderFault": true + }, + "exception": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "InvalidGreetingError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "InvalidGreeting" + } + ] + }, + "description": "Parses simple XML errors", + "errorCode": "InvalidGreeting", + "errorMessage": "Hi", + "error": { + "Message": "Hi" + }, + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n Sender\n InvalidGreeting\n Hi\n setting\n \n foo-id\n\n" + } + } + ] + }, + { + "description": "Test cases for GreetingWithErrors operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "ComplexError": { + "type": "structure", + "members": { + "Header": { + "shape": "String", + "location": "header", + "locationName": "X-Header" + }, + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "error": { + "httpStatusCode": 403, + "senderFault": true + }, + "exception": true + }, + "String": { + "type": "string" + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + } + }, + "cases": [ + { + "id": "ComplexError", + "given": { + "name": "GreetingWithErrors", + "http": { + "method": "PUT", + "requestUri": "/GreetingWithErrors", + "responseCode": 200 + }, + "documentation": "

This operation has three possible return values:

  1. A successful response in the form of GreetingWithErrorsOutput
  2. An InvalidGreeting error.
  3. A BadRequest error.

Implementations must be able to successfully take a response and properly (de)serialize successful and error responses based on the the presence of the

", + "idempotent": true, + "errors": [ + { + "shape": "ComplexError" + } + ] + }, + "errorCode": "ComplexError", + "error": { + "Header": "Header", + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + }, + "response": { + "status_code": 403, + "headers": { + "Content-Type": "application/xml", + "X-Header": "Header" + }, + "body": "\n \n Sender\n ComplexError\n Hi\n Top level\n \n bar\n \n \n foo-id\n\n" + } + } + ] + }, + { + "description": "Test cases for HttpEnumPayload operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "EnumPayloadInput": { + "type": "structure", + "members": { + "payload": { + "shape": "StringEnum" + } + }, + "payload": "payload" + }, + "StringEnum": { + "type": "string", + "enum": [ + "enumvalue" + ] + } + }, + "cases": [ + { + "id": "RestXmlEnumPayloadResponse", + "given": { + "name": "HttpEnumPayload", + "http": { + "method": "POST", + "requestUri": "/EnumPayload", + "responseCode": 200 + }, + "output": { + "shape": "EnumPayloadInput" + } + }, + "result": { + "payload": "enumvalue" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/plain" + }, + "body": "enumvalue" + } + } + ] + }, + { + "description": "Test cases for HttpPayloadTraits operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadTraitsInputOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "blob": { + "shape": "Blob" + } + }, + "payload": "blob" + }, + "String": { + "type": "string" + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "HttpPayloadTraitsWithBlob", + "given": { + "name": "HttpPayloadTraits", + "http": { + "method": "POST", + "requestUri": "/HttpPayloadTraits", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadTraitsInputOutput" + }, + "documentation": "

This example serializes a blob shape in the payload.

In this example, no XML document is synthesized because the payload is not a structure or a union type.

" + }, + "description": "Serializes a blob in the HTTP payload", + "result": { + "foo": "Foo", + "blob": "blobby blob blob" + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo" + }, + "body": "blobby blob blob" + } + }, + { + "id": "HttpPayloadTraitsWithNoBlobBody", + "given": { + "name": "HttpPayloadTraits", + "http": { + "method": "POST", + "requestUri": "/HttpPayloadTraits", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadTraitsInputOutput" + }, + "documentation": "

This example serializes a blob shape in the payload.

In this example, no XML document is synthesized because the payload is not a structure or a union type.

" + }, + "description": "Serializes an empty blob in the HTTP payload", + "result": { + "foo": "Foo" + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo" + }, + "body": "" + } + } + ] + }, + { + "description": "Test cases for HttpPayloadWithMemberXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithMemberXmlNameInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "PayloadWithXmlName", + "locationName": "Hola" + } + }, + "payload": "nested" + }, + "PayloadWithXmlName": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + }, + "locationName": "Hello" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPayloadWithMemberXmlName", + "given": { + "name": "HttpPayloadWithMemberXmlName", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithMemberXmlName", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithMemberXmlNameInputOutput" + }, + "documentation": "

The following example serializes a payload that uses an XML name on the member, changing the wrapper name.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload using a wrapper name based on member xmlName", + "result": { + "nested": { + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "Phreddy" + } + } + ] + }, + { + "description": "Test cases for HttpPayloadWithStructure operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithStructureInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "NestedPayload", + "locationName": "NestedPayload" + } + }, + "payload": "nested" + }, + "NestedPayload": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + }, + "name": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPayloadWithStructure", + "given": { + "name": "HttpPayloadWithStructure", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithStructure", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithStructureInputOutput" + }, + "documentation": "

This example serializes a structure in the payload.

Note that serializing a structure changes the wrapper element name to match the targeted structure.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload", + "result": { + "nested": { + "greeting": "hello", + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n hello\n Phreddy\n\n" + } + } + ] + }, + { + "description": "Test cases for HttpPayloadWithUnion operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithUnionInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "UnionPayload", + "locationName": "nested" + } + }, + "payload": "nested" + }, + "UnionPayload": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + }, + "union": true + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestXmlHttpPayloadWithUnion", + "given": { + "name": "HttpPayloadWithUnion", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithUnion", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithUnionInputOutput" + }, + "documentation": "

This example serializes a union in the payload.

", + "idempotent": true + }, + "description": "Serializes a union in the payload.", + "result": { + "nested": { + "greeting": "hello" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n hello\n" + } + }, + { + "id": "RestXmlHttpPayloadWithUnsetUnion", + "given": { + "name": "HttpPayloadWithUnion", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithUnion", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithUnionInputOutput" + }, + "documentation": "

This example serializes a union in the payload.

", + "idempotent": true + }, + "description": "No payload is sent if the union has no value.", + "result": {}, + "response": { + "status_code": 200, + "headers": { + "Content-Length": "0" + }, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for HttpPayloadWithXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithXmlNameInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "PayloadWithXmlName", + "locationName": "nested" + } + }, + "payload": "nested" + }, + "PayloadWithXmlName": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + }, + "locationName": "Hello" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPayloadWithXmlName", + "given": { + "name": "HttpPayloadWithXmlName", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithXmlName", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithXmlNameInputOutput" + }, + "documentation": "

The following example serializes a payload that uses an XML name, changing the wrapper name.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload using a wrapper name based on xmlName", + "result": { + "nested": { + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "Phreddy" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123" - } - } - ] - }, - { - "description": "List with custom member name", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for HttpPayloadWithXmlNamespace operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithXmlNamespaceInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "PayloadWithXmlNamespace", + "locationName": "nested" + } + }, + "payload": "nested" + }, + "PayloadWithXmlNamespace": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + }, + "xmlNamespace": "http://foo.com" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPayloadWithXmlNamespace", + "given": { + "name": "HttpPayloadWithXmlNamespace", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithXmlNamespace", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithXmlNamespaceInputOutput" + }, + "documentation": "

The following example serializes a payload that uses an XML namespace.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload using a wrapper with an XML namespace", + "result": { + "nested": { + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Phreddy\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "StringType", - "locationName": "item" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for HttpPayloadWithXmlNamespaceAndPrefix operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPayloadWithXmlNamespaceAndPrefixInputOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "PayloadWithXmlNamespaceAndPrefix", + "locationName": "nested" + } + }, + "payload": "nested" + }, + "PayloadWithXmlNamespaceAndPrefix": { + "type": "structure", + "members": { + "name": { + "shape": "String" + } + }, + "xmlNamespace": { + "prefix": "baz", + "uri": "http://foo.com" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "HttpPayloadWithXmlNamespaceAndPrefix", + "given": { + "name": "HttpPayloadWithXmlNamespaceAndPrefix", + "http": { + "method": "PUT", + "requestUri": "/HttpPayloadWithXmlNamespaceAndPrefix", + "responseCode": 200 + }, + "output": { + "shape": "HttpPayloadWithXmlNamespaceAndPrefixInputOutput" + }, + "documentation": "

The following example serializes a payload that uses an XML namespace.

", + "idempotent": true + }, + "description": "Serializes a structure in the payload using a wrapper with an XML namespace", + "result": { + "nested": { + "name": "Phreddy" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Phreddy\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123" - } - } - ] - }, - { - "description": "Flattened List", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for HttpPrefixHeaders operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpPrefixHeadersInputOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "fooMap": { + "shape": "FooPrefixHeaders", + "location": "headers", + "locationName": "X-Foo-" + } + } + }, + "String": { + "type": "string" + }, + "FooPrefixHeaders": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + } + }, + "cases": [ + { + "id": "HttpPrefixHeadersArePresent", + "given": { + "name": "HttpPrefixHeaders", + "http": { + "method": "GET", + "requestUri": "/HttpPrefixHeaders", + "responseCode": 200 + }, + "output": { + "shape": "HttpPrefixHeadersInputOutput" + }, + "documentation": "

This examples adds headers to the input of a request and response by prefix.

" + }, + "description": "Adds headers by prefix", + "result": { + "foo": "Foo", + "fooMap": { + "Abc": "Abc value", + "Def": "Def value" + } + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo", + "X-Foo-Abc": "Abc value", + "X-Foo-Def": "Def value" + }, + "body": "" + } + }, + { + "id": "HttpPrefixHeadersAreNotPresent", + "given": { + "name": "HttpPrefixHeaders", + "http": { + "method": "GET", + "requestUri": "/HttpPrefixHeaders", + "responseCode": 200 + }, + "output": { + "shape": "HttpPrefixHeadersInputOutput" + }, + "documentation": "

This examples adds headers to the input of a request and response by prefix.

" + }, + "description": "No prefix headers are serialized because the value is empty", + "result": { + "foo": "Foo", + "fooMap": {} + }, + "response": { + "status_code": 200, + "headers": { + "X-Foo": "Foo" + }, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "StringList", - "flattened": true - } - } - }, - "StringList": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for HttpResponseCode operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "HttpResponseCodeOutput": { + "type": "structure", + "members": { + "Status": { + "shape": "Integer", + "location": "statusCode" + } + } + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "RestXmlHttpResponseCode", + "given": { + "name": "HttpResponseCode", + "http": { + "method": "PUT", + "requestUri": "/HttpResponseCode", + "responseCode": 200 + }, + "output": { + "shape": "HttpResponseCodeOutput" + }, + "idempotent": true + }, + "description": "Binds the http response code to an output structure.", + "result": { + "Status": 201 + }, + "response": { + "status_code": 201, + "headers": { + "Content-Type": "application/xml" + }, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["abc", "123"] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc123" - } - } - ] - }, - { - "description": "Normal map", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for HttpStringPayload operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "StringPayloadInput": { + "type": "structure", + "members": { + "payload": { + "shape": "String" + } + }, + "payload": "payload" + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestXmlStringPayloadResponse", + "given": { + "name": "HttpStringPayload", + "http": { + "method": "POST", + "requestUri": "/StringPayload", + "responseCode": 200 + }, + "output": { + "shape": "StringPayloadInput" + } + }, + "result": { + "payload": "rawstring" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/plain" + }, + "body": "rawstring" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap" - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "SingleStructure" - } - }, - "SingleStructure": { - "type": "structure", - "members": { - "foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for IgnoreQueryParamsInResponse operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "IgnoreQueryParamsInResponseOutput": { + "type": "structure", + "members": { + "baz": { + "shape": "String", + "location": "uri", + "locationName": "baz" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "IgnoreQueryParamsInResponse", + "given": { + "name": "IgnoreQueryParamsInResponse", + "http": { + "method": "GET", + "requestUri": "/IgnoreQueryParamsInResponse", + "responseCode": 200 + }, + "output": { + "shape": "IgnoreQueryParamsInResponseOutput" + }, + "documentation": "

This example ensures that query string bound request parameters are serialized in the body of responses if the structure is used in both the request and response.

" + }, + "description": "Query parameters must be ignored when serializing the output of an operation", + "result": { + "baz": "bam" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "bam" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": { - "foo": "bar" - }, - "baz": { - "foo": "bam" - } - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbam" - } - } - ] - }, - { - "description": "Flattened map", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for InputAndOutputWithHeaders operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "InputAndOutputWithHeadersIO": { + "type": "structure", + "members": { + "headerString": { + "shape": "String", + "location": "header", + "locationName": "X-String" + }, + "headerByte": { + "shape": "Integer", + "location": "header", + "locationName": "X-Byte" + }, + "headerShort": { + "shape": "Integer", + "location": "header", + "locationName": "X-Short" + }, + "headerInteger": { + "shape": "Integer", + "location": "header", + "locationName": "X-Integer" + }, + "headerLong": { + "shape": "Long", + "location": "header", + "locationName": "X-Long" + }, + "headerFloat": { + "shape": "Float", + "location": "header", + "locationName": "X-Float" + }, + "headerDouble": { + "shape": "Double", + "location": "header", + "locationName": "X-Double" + }, + "headerTrueBool": { + "shape": "Boolean", + "location": "header", + "locationName": "X-Boolean1" + }, + "headerFalseBool": { + "shape": "Boolean", + "location": "header", + "locationName": "X-Boolean2" + }, + "headerStringList": { + "shape": "StringList", + "location": "header", + "locationName": "X-StringList" + }, + "headerStringSet": { + "shape": "StringSet", + "location": "header", + "locationName": "X-StringSet" + }, + "headerIntegerList": { + "shape": "IntegerList", + "location": "header", + "locationName": "X-IntegerList" + }, + "headerBooleanList": { + "shape": "BooleanList", + "location": "header", + "locationName": "X-BooleanList" + }, + "headerTimestampList": { + "shape": "TimestampList", + "location": "header", + "locationName": "X-TimestampList" + }, + "headerEnum": { + "shape": "FooEnum", + "location": "header", + "locationName": "X-Enum" + }, + "headerEnumList": { + "shape": "FooEnumList", + "location": "header", + "locationName": "X-EnumList" + } + } + }, + "String": { + "type": "string" + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "Timestamp": { + "type": "timestamp" + } + }, + "cases": [ + { + "id": "InputAndOutputWithStringHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with string header bindings", + "result": { + "headerString": "Hello", + "headerStringList": [ + "a", + "b", + "c" + ], + "headerStringSet": [ + "a", + "b", + "c" + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-String": "Hello", + "X-StringList": "a, b, c", + "X-StringSet": "a, b, c" + }, + "body": "" + } + }, + { + "id": "InputAndOutputWithNumericHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with numeric header bindings", + "result": { + "headerByte": 1, + "headerShort": 123, + "headerInteger": 123, + "headerLong": 123, + "headerFloat": 1.1, + "headerDouble": 1.1, + "headerIntegerList": [ + 1, + 2, + 3 + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Byte": "1", + "X-Double": "1.1", + "X-Float": "1.1", + "X-Integer": "123", + "X-IntegerList": "1, 2, 3", + "X-Long": "123", + "X-Short": "123" + }, + "body": "" + } + }, + { + "id": "InputAndOutputWithBooleanHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with boolean header bindings", + "result": { + "headerTrueBool": true, + "headerFalseBool": false, + "headerBooleanList": [ + true, + false, + true + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Boolean1": "true", + "X-Boolean2": "false", + "X-BooleanList": "true, false, true" + }, + "body": "" + } + }, + { + "id": "InputAndOutputWithTimestampHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with timestamp header bindings", + "result": { + "headerTimestampList": [ + 1576540098, + 1576540098 + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-TimestampList": "Mon, 16 Dec 2019 23:48:18 GMT, Mon, 16 Dec 2019 23:48:18 GMT" + }, + "body": "" + } + }, + { + "id": "InputAndOutputWithEnumHeaders", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Tests responses with enum header bindings", + "result": { + "headerEnum": "Foo", + "headerEnumList": [ + "Foo", + "Bar", + "Baz" + ] + }, + "response": { + "status_code": 200, + "headers": { + "X-Enum": "Foo", + "X-EnumList": "Foo, Bar, Baz" + }, + "body": "" + } + }, + { + "id": "RestXmlSupportsNaNFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling NaN float header values.", + "result": { + "headerFloat": "NaN", + "headerDouble": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "NaN", + "X-Float": "NaN" + }, + "body": "" + } + }, + { + "id": "RestXmlSupportsInfinityFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling Infinity float header values.", + "result": { + "headerFloat": "Infinity", + "headerDouble": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "Infinity", + "X-Float": "Infinity" + }, + "body": "" + } + }, + { + "id": "RestXmlSupportsNegativeInfinityFloatHeaderOutputs", + "given": { + "name": "InputAndOutputWithHeaders", + "http": { + "method": "POST", + "requestUri": "/InputAndOutputWithHeaders", + "responseCode": 200 + }, + "output": { + "shape": "InputAndOutputWithHeadersIO" + }, + "documentation": "

The example tests how requests and responses are serialized when there is no input or output payload but there are HTTP header bindings.

" + }, + "description": "Supports handling -Infinity float header values.", + "result": { + "headerFloat": "-Infinity", + "headerDouble": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "X-Double": "-Infinity", + "X-Float": "-Infinity" + }, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap", - "flattened": true - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType" - }, - "value": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for NestedXmlMaps operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "NestedXmlMapsResponse": { + "type": "structure", + "members": { + "nestedMap": { + "shape": "NestedMap" + }, + "flatNestedMap": { + "shape": "NestedMap", + "flattened": true + } + } + }, + "NestedMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnumMap" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "NestedXmlMapResponse", + "given": { + "name": "NestedXmlMaps", + "http": { + "method": "POST", + "requestUri": "/NestedXmlMaps", + "responseCode": 200 + }, + "output": { + "shape": "NestedXmlMapsResponse" + } + }, + "description": "Tests responses with nested maps.", + "result": { + "nestedMap": { + "foo": { + "bar": "Bar" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n foo\n \n \n bar\n Bar\n \n \n \n \n" + } + }, + { + "id": "FlatNestedXmlMapResponse", + "given": { + "name": "NestedXmlMaps", + "http": { + "method": "POST", + "requestUri": "/NestedXmlMaps", + "responseCode": 200 + }, + "output": { + "shape": "NestedXmlMapsResponse" + } + }, + "description": "Tests responses with nested flat maps. Since maps can only be\nflattened when they're structure members, only the outer map is flat.", + "result": { + "flatNestedMap": { + "foo": { + "bar": "Bar" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n foo\n \n \n bar\n Bar\n \n \n \n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbam" - } - } - ] - }, - { - "description": "Named map", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for NoInputAndNoOutput operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": {}, + "cases": [ + { + "id": "NoInputAndNoOutput", + "given": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/NoInputAndNoOutput", + "responseCode": 200 + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input or output. While this should be rare, code generators must support this.

" + }, + "description": "No output serializes no payload", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Map": { - "shape": "StringMap" - } - } - }, - "StringMap": { - "type": "map", - "key": { - "shape": "StringType", - "locationName": "foo" - }, - "value": { - "shape": "StringType", - "locationName": "bar" - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for NoInputAndOutput operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + } + }, + "cases": [ + { + "id": "NoInputAndOutput", + "given": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/NoInputAndOutputOutput", + "responseCode": 200 + }, + "output": { + "shape": "NoInputAndOutputOutput" + }, + "documentation": "

The example tests how requests and responses are serialized when there's no request or response payload because the operation has no input and the output is empty. While this should be rare, code generators must support this.

" + }, + "description": "Empty output serializes no payload", + "result": {}, + "response": { + "status_code": 200, + "body": "" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Map": { - "qux": "bar", - "baz": "bam" - } - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "quxbarbazbam" - } - } - ] - }, - { - "description": "XML payload", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for RecursiveShapes operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "RecursiveShapesResponse": { + "type": "structure", + "members": { + "nested": { + "shape": "RecursiveShapesInputOutputNested1" + } + } + }, + "RecursiveShapesInputOutputNested1": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "nested": { + "shape": "RecursiveShapesInputOutputNested2" + } + } + }, + "String": { + "type": "string" + }, + "RecursiveShapesInputOutputNested2": { + "type": "structure", + "members": { + "bar": { + "shape": "String" + }, + "recursiveMember": { + "shape": "RecursiveShapesInputOutputNested1" + } + } + } + }, + "cases": [ + { + "id": "RecursiveShapes", + "given": { + "name": "RecursiveShapes", + "http": { + "method": "PUT", + "requestUri": "/RecursiveShapes", + "responseCode": 200 + }, + "output": { + "shape": "RecursiveShapesResponse" + }, + "documentation": "

Recursive shapes

", + "idempotent": true + }, + "description": "Serializes recursive structures", + "result": { + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n Foo1\n \n Bar1\n \n Foo2\n \n Bar2\n \n \n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "payload": "Data", - "members": { - "Header": { - "shape": "StringType", - "location": "header", - "locationName": "X-Foo" - }, - "Data": { - "shape": "SingleStructure" - } - } - }, - "StringType": { - "type": "string" - }, - "SingleStructure": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - } + { + "description": "Test cases for SimpleScalarProperties operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "SimpleScalarPropertiesResponse": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "location": "header", + "locationName": "X-Foo" + }, + "stringValue": { + "shape": "String" + }, + "trueBooleanValue": { + "shape": "Boolean" + }, + "falseBooleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double", + "locationName": "DoubleDribble" + } + } + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + } + }, + "cases": [ + { + "id": "SimpleScalarProperties", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "foo": "Foo", + "stringValue": "string", + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n string\n true\n false\n 1\n 2\n 3\n 4\n 5.5\n 6.5\n\n" + } + }, + { + "id": "SimpleScalarPropertiesComplexEscapes", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes string with escaping.\n\nThis validates the three escape types: literal, decimal and hexadecimal. It also validates that unescaping properly\nhandles the case where unescaping an & produces a newly formed escape sequence (this should not be re-unescaped).\n\nServers may produce different output, this test is designed different unescapes clients must handle\n", + "result": { + "foo": "Foo", + "stringValue": "escaped data: <\r\n" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n escaped data: &lt; \n\n" + } + }, + { + "id": "SimpleScalarPropertiesWithEscapedCharacter", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes string with escaping", + "result": { + "foo": "Foo", + "stringValue": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n <string>\n\n" + } + }, + { + "id": "SimpleScalarPropertiesWithXMLPreamble", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes simple scalar properties with xml preamble, comments and CDATA", + "result": { + "foo": "Foo", + "stringValue": "string" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n\n \n string\n \n\n" + } + }, + { + "id": "SimpleScalarPropertiesWithWhiteSpace", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes string containing white space", + "result": { + "foo": "Foo", + "stringValue": " string with white space " + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n\n string with white space \n\n" + } + }, + { + "id": "SimpleScalarPropertiesPureWhiteSpace", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Serializes string containing white space", + "result": { + "foo": "Foo", + "stringValue": " " + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml", + "X-Foo": "Foo" + }, + "body": "\n\n \n\n" + } + }, + { + "id": "RestXmlSupportsNaNFloatOutputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Supports handling NaN float values.", + "result": { + "floatValue": "NaN", + "doubleValue": "NaN" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n NaN\n NaN\n\n" + } + }, + { + "id": "RestXmlSupportsInfinityFloatOutputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Supports handling Infinity float values.", + "result": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Infinity\n Infinity\n\n" + } + }, + { + "id": "RestXmlSupportsNegativeInfinityFloatOutputs", + "given": { + "name": "SimpleScalarProperties", + "http": { + "method": "PUT", + "requestUri": "/SimpleScalarProperties", + "responseCode": 200 + }, + "output": { + "shape": "SimpleScalarPropertiesResponse" + }, + "idempotent": true + }, + "description": "Supports handling -Infinity float values.", + "result": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n -Infinity\n -Infinity\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Header": "baz", - "Data": { - "Foo": "abc" - } - }, - "response": { - "status_code": 200, - "headers": { - "X-Foo": "baz" - }, - "body": "abc" - } - } - ] - }, - { - "description": "Streaming payload", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for TimestampFormatHeaders operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "TimestampFormatHeadersIO": { + "type": "structure", + "members": { + "memberEpochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds", + "location": "header", + "locationName": "X-memberEpochSeconds" + }, + "memberHttpDate": { + "shape": "SyntheticTimestamp_http_date", + "location": "header", + "locationName": "X-memberHttpDate" + }, + "memberDateTime": { + "shape": "SyntheticTimestamp_date_time", + "location": "header", + "locationName": "X-memberDateTime" + }, + "defaultFormat": { + "shape": "Timestamp", + "location": "header", + "locationName": "X-defaultFormat" + }, + "targetEpochSeconds": { + "shape": "EpochSeconds", + "location": "header", + "locationName": "X-targetEpochSeconds" + }, + "targetHttpDate": { + "shape": "HttpDate", + "location": "header", + "locationName": "X-targetHttpDate" + }, + "targetDateTime": { + "shape": "DateTime", + "location": "header", + "locationName": "X-targetDateTime" + } + } + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "Timestamp": { + "type": "timestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + } + }, + "cases": [ + { + "id": "TimestampFormatHeaders", + "given": { + "name": "TimestampFormatHeaders", + "http": { + "method": "POST", + "requestUri": "/TimestampFormatHeaders", + "responseCode": 200 + }, + "output": { + "shape": "TimestampFormatHeadersIO" + }, + "documentation": "

The example tests how timestamp request and response headers are serialized.

" + }, + "description": "Tests how timestamp response headers are serialized", + "result": { + "memberEpochSeconds": 1576540098, + "memberHttpDate": 1576540098, + "memberDateTime": 1576540098, + "defaultFormat": 1576540098, + "targetEpochSeconds": 1576540098, + "targetHttpDate": 1576540098, + "targetDateTime": 1576540098 + }, + "response": { + "status_code": 200, + "headers": { + "X-defaultFormat": "Mon, 16 Dec 2019 23:48:18 GMT", + "X-memberDateTime": "2019-12-16T23:48:18Z", + "X-memberEpochSeconds": "1576540098", + "X-memberHttpDate": "Mon, 16 Dec 2019 23:48:18 GMT", + "X-targetDateTime": "2019-12-16T23:48:18Z", + "X-targetEpochSeconds": "1576540098", + "X-targetHttpDate": "Mon, 16 Dec 2019 23:48:18 GMT" + }, + "body": "" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "payload": "Stream", - "members": { - "Stream": { - "shape": "BlobStream" - } - } - }, - "BlobStream": { - "type": "blob" - } + { + "description": "Test cases for XmlAttributes operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlAttributesResponse": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "attr": { + "shape": "String", + "locationName": "test", + "xmlAttribute": true + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlAttributes", + "given": { + "name": "XmlAttributes", + "http": { + "method": "PUT", + "requestUri": "/XmlAttributes", + "responseCode": 200 + }, + "output": { + "shape": "XmlAttributesResponse" + }, + "documentation": "

This example serializes an XML attributes on synthesized document.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "foo": "hi", + "attr": "test" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n hi\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Stream": "abc" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "abc" - } - } - ] - }, - { - "description": "Scalar members in headers", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlAttributesOnPayload operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlAttributesOnPayloadResponse": { + "type": "structure", + "members": { + "payload": { + "shape": "XmlAttributesPayloadResponse" + } + }, + "payload": "payload" + }, + "XmlAttributesPayloadResponse": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "attr": { + "shape": "String", + "locationName": "test", + "xmlAttribute": true + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlAttributesOnPayload", + "given": { + "name": "XmlAttributesOnPayload", + "http": { + "method": "PUT", + "requestUri": "/XmlAttributesOnPayload", + "responseCode": 200 + }, + "output": { + "shape": "XmlAttributesOnPayloadResponse" + }, + "documentation": "

This example serializes an XML attributes on a document targeted by httpPayload.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "payload": { + "foo": "hi", + "attr": "test" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n hi\n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Str": { - "locationName": "x-str", - "shape": "StringHeaderType" - }, - "Integer": { - "locationName": "x-int", - "shape": "IntegerHeaderType" - }, - "TrueBool": { - "locationName": "x-true-bool", - "shape": "BooleanHeaderType" - }, - "FalseBool": { - "locationName": "x-false-bool", - "shape": "BooleanHeaderType" - }, - "Float": { - "locationName": "x-float", - "shape": "FloatHeaderType" - }, - "Double": { - "locationName": "x-double", - "shape": "DoubleHeaderType" - }, - "Long": { - "locationName": "x-long", - "shape": "LongHeaderType" - }, - "Char": { - "locationName": "x-char", - "shape": "CharHeaderType" - }, - "Timestamp": { - "locationName": "x-timestamp", - "shape": "TimestampHeaderType" - } - } - }, - "StringHeaderType": { - "location": "header", - "type": "string" - }, - "IntegerHeaderType": { - "location": "header", - "type": "integer" - }, - "BooleanHeaderType": { - "location": "header", - "type": "boolean" - }, - "FloatHeaderType": { - "location": "header", - "type": "float" - }, - "DoubleHeaderType": { - "location": "header", - "type": "double" - }, - "LongHeaderType": { - "location": "header", - "type": "long" - }, - "CharHeaderType": { - "location": "header", - "type": "character" - }, - "TimestampHeaderType": { - "location": "header", - "type": "timestamp" - } + { + "description": "Test cases for XmlBlobs operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlBlobsResponse": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "XmlBlobs", + "given": { + "name": "XmlBlobs", + "http": { + "method": "POST", + "requestUri": "/XmlBlobs", + "responseCode": 200 + }, + "output": { + "shape": "XmlBlobsResponse" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Blobs are base64 encoded", + "result": { + "data": "value" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n dmFsdWU=\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Str": "string", - "Integer": 1, - "TrueBool": true, - "FalseBool": false, - "Float": 1.5, - "Double": 1.5, - "Long": 100, - "Char": "a", - "Timestamp": 1422172800 - }, - "response": { - "status_code": 200, - "headers": { - "x-str": "string", - "x-int": "1", - "x-true-bool": "true", - "x-false-bool": "false", - "x-float": "1.5", - "x-double": "1.5", - "x-long": "100", - "x-char": "a", - "x-timestamp": "Sun, 25 Jan 2015 08:00:00 GMT" - }, - "body": "" - } - } - ] - }, - { - "description": "Empty string", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlEmptyBlobs operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlEmptyBlobsResponse": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "Blob": { + "type": "blob" + } + }, + "cases": [ + { + "id": "XmlEmptyBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/XmlEmptyBlobs", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyBlobsResponse" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Empty blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + }, + { + "id": "XmlEmptySelfClosedBlobs", + "given": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/XmlEmptyBlobs", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyBlobsResponse" + }, + "documentation": "

Blobs are base64 encoded

" + }, + "description": "Empty self closed blobs are deserialized as empty string", + "result": { + "data": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Foo": { - "shape": "StringType" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlEmptyLists operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlEmptyListsResponse": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + }, + "flattenedStructureList": { + "shape": "StructureList", + "flattened": true + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "XmlEmptyLists", + "given": { + "name": "XmlEmptyLists", + "http": { + "method": "PUT", + "requestUri": "/XmlEmptyLists", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyListsResponse" + }, + "idempotent": true + }, + "description": "Deserializes Empty XML lists", + "result": { + "stringList": [], + "stringSet": [] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Foo": "" - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "requestid" - } - } - ] - }, - { - "description": "JSON value trait", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlEmptyMaps operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlEmptyMapsResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsInputOutputMap" + } + } + }, + "XmlMapsInputOutputMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlEmptyMaps", + "given": { + "name": "XmlEmptyMaps", + "http": { + "method": "POST", + "requestUri": "/XmlEmptyMaps", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyMapsResponse" + } + }, + "description": "Deserializes Empty XML maps", + "result": { + "myMap": {} + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + }, + { + "id": "XmlEmptySelfClosedMaps", + "given": { + "name": "XmlEmptyMaps", + "http": { + "method": "POST", + "requestUri": "/XmlEmptyMaps", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyMapsResponse" + } + }, + "description": "Deserializes Empty Self-closed XML maps", + "result": { + "myMap": {} + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Attr": { - "shape": "StringType", - "jsonvalue": true, - "location": "header", - "locationName": "X-Amz-Foo" - } - } - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlEmptyStrings operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlEmptyStringsResponse": { + "type": "structure", + "members": { + "emptyString": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlEmptyStrings", + "given": { + "name": "XmlEmptyStrings", + "http": { + "method": "PUT", + "requestUri": "/XmlEmptyStrings", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyStringsResponse" + }, + "idempotent": true + }, + "description": "Deserializes xml empty strings", + "result": { + "emptyString": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + }, + { + "id": "XmlEmptySelfClosedStrings", + "given": { + "name": "XmlEmptyStrings", + "http": { + "method": "PUT", + "requestUri": "/XmlEmptyStrings", + "responseCode": 200 + }, + "output": { + "shape": "XmlEmptyStringsResponse" + }, + "idempotent": true + }, + "description": "Empty self closed string are deserialized as empty string", + "result": { + "emptyString": "" + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Attr": {"Foo":"Bar"} - }, - "response": { - "status_code": 200, - "headers": {"X-Amz-Foo": "eyJGb28iOiJCYXIifQ=="}, - "body": "" - } - } - ] - }, - { - "description": "Timestamp members", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlEnums operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlEnumsResponse": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlEnums", + "given": { + "name": "XmlEnums", + "http": { + "method": "PUT", + "requestUri": "/XmlEnums", + "responseCode": 200 + }, + "output": { + "shape": "XmlEnumsResponse" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Foo\n 0\n 1\n \n Foo\n 0\n \n \n Foo\n 0\n \n \n \n hi\n Foo\n \n \n zero\n 0\n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "TimeArg": { - "shape": "TimestampType" - }, - "TimeArgInHeader": { - "shape": "TimestampType", - "location": "header", - "locationName": "x-amz-timearg" - }, - "TimeCustom": { - "timestampFormat": "rfc822", - "shape": "TimestampType" - }, - "TimeCustomInHeader": { - "timestampFormat": "unixTimestamp", - "shape": "TimestampType", - "location": "header", - "locationName": "x-amz-timecustom" - }, - "TimeFormat": { - "shape": "TimestampFormatType" - }, - "TimeFormatInHeader": { - "shape": "TimestampFormatType", - "location": "header", - "locationName": "x-amz-timeformat" - }, - "StructMember": { - "shape": "TimeContainer" - } - } - }, - "TimeContainer": { - "type": "structure", - "members": { - "foo": { - "shape": "TimestampType" - }, - "bar": { - "shape": "TimestampFormatType" - } - } - }, - "TimestampFormatType": { - "timestampFormat": "unixTimestamp", - "type": "timestamp" - }, - "TimestampType": { - "type": "timestamp" - } + { + "description": "Test cases for XmlIntEnums operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlIntEnumsResponse": { + "type": "structure", + "members": { + "intEnum1": { + "shape": "IntegerEnum" + }, + "intEnum2": { + "shape": "IntegerEnum" + }, + "intEnum3": { + "shape": "IntegerEnum" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "intEnumSet": { + "shape": "IntegerEnumSet" + }, + "intEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlIntEnums", + "given": { + "name": "XmlIntEnums", + "http": { + "method": "PUT", + "requestUri": "/XmlIntEnums", + "responseCode": 200 + }, + "output": { + "shape": "XmlIntEnumsResponse" + }, + "documentation": "

This example serializes enums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "intEnum1": 1, + "intEnum2": 2, + "intEnum3": 3, + "intEnumList": [ + 1, + 2 + ], + "intEnumSet": [ + 1, + 2 + ], + "intEnumMap": { + "a": 1, + "b": 2 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 1\n 2\n 3\n \n 1\n 2\n \n \n 1\n 2\n \n \n \n a\n 1\n \n \n b\n 2\n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "TimeArg": 1398796238, - "TimeArgInHeader": 1398796238, - "TimeCustom": 1398796238, - "TimeCustomInHeader": 1398796238, - "TimeFormat": 1398796238, - "TimeFormatInHeader": 1398796238, - "StructMember": { - "foo": 1398796238, - "bar": 1398796238 - } - }, - "response": { - "status_code": 200, - "headers": { - "x-amz-timearg": "Tue, 29 Apr 2014 18:30:38 GMT", - "x-amz-timecustom": "1398796238", - "x-amz-timeformat": "1398796238" - }, - "body": "2014-04-29T18:30:38+00:0013987962382014-04-29T18:30:38+00:00Tue, 29 Apr 2014 18:30:38 GMT1398796238requestid" - } - } - ] - }, - { - "description": "REST XML Event Stream", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlLists operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlListsResponse": { + "type": "structure", + "members": { + "stringList": { + "shape": "StringList" + }, + "stringSet": { + "shape": "StringSet" + }, + "integerList": { + "shape": "IntegerList" + }, + "booleanList": { + "shape": "BooleanList" + }, + "timestampList": { + "shape": "TimestampList" + }, + "enumList": { + "shape": "FooEnumList" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "nestedStringList": { + "shape": "NestedStringList" + }, + "renamedListMembers": { + "shape": "RenamedListMembers", + "locationName": "renamed" + }, + "flattenedList": { + "shape": "RenamedListMembers", + "flattened": true + }, + "flattenedList2": { + "shape": "RenamedListMembers", + "flattened": true, + "locationName": "customName" + }, + "flattenedListWithMemberNamespace": { + "shape": "ListWithMemberNamespace", + "flattened": true + }, + "flattenedListWithNamespace": { + "shape": "ListWithNamespace", + "flattened": true + }, + "structureList": { + "shape": "StructureList", + "locationName": "myStructureList" + }, + "flattenedStructureList": { + "shape": "StructureList", + "flattened": true + } + } + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + }, + "documentation": "

A list of lists of strings.

" + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "ListWithMemberNamespace": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "https://xml-member.example.com" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "ListWithNamespace": { + "type": "list", + "member": { + "shape": "String" + }, + "xmlNamespace": "https://xml-list.example.com" + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "String": { + "type": "string" + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "Timestamp": { + "type": "timestamp" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + } + }, + "cases": [ + { + "id": "XmlLists", + "given": { + "name": "XmlLists", + "http": { + "method": "PUT", + "requestUri": "/XmlLists", + "responseCode": 200 + }, + "output": { + "shape": "XmlListsResponse" + }, + "documentation": "

This test case serializes XML lists for the following cases for both input and output:

  1. Normal XML lists.
  2. Normal XML sets.
  3. XML lists of lists.
  4. XML lists with @xmlName on its members
  5. Flattened XML lists.
  6. Flattened XML lists with @xmlName.
  7. Flattened XML lists with @xmlNamespace.
  8. Lists of structures.
  9. Flattened XML list of structures
", + "idempotent": true + }, + "description": "Tests for XML list serialization", + "result": { + "stringList": [ + "foo", + "bar" + ], + "stringSet": [ + "foo", + "bar" + ], + "integerList": [ + 1, + 2 + ], + "booleanList": [ + true, + false + ], + "timestampList": [ + 1398796238, + 1398796238 + ], + "enumList": [ + "Foo", + "0" + ], + "intEnumList": [ + 1, + 2 + ], + "nestedStringList": [ + [ + "foo", + "bar" + ], + [ + "baz", + "qux" + ] + ], + "renamedListMembers": [ + "foo", + "bar" + ], + "flattenedList": [ + "hi", + "bye" + ], + "flattenedList2": [ + "yep", + "nope" + ], + "flattenedListWithMemberNamespace": [ + "a", + "b" + ], + "flattenedListWithNamespace": [ + "a", + "b" + ], + "structureList": [ + { + "a": "1", + "b": "2" + }, + { + "a": "3", + "b": "4" + } + ], + "flattenedStructureList": [ + { + "a": "5", + "b": "6" + }, + { + "a": "7", + "b": "8" + } + ] + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n foo\n bar\n \n \n foo\n bar\n \n \n 1\n 2\n \n \n true\n false\n \n \n 2014-04-29T18:30:38Z\n 2014-04-29T18:30:38Z\n \n \n Foo\n 0\n \n \n 1\n 2\n \n \n \n foo\n bar\n \n \n baz\n qux\n \n \n \n foo\n bar\n \n hi\n bye\n yep\n nope\n a\n b\n a\n b\n \n \n 1\n 2\n \n \n 3\n 4\n \n \n \n 5\n 6\n \n \n 7\n 8\n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "Payload": {"shape": "EventStream"} - }, - "payload": "Payload" - }, - "EventStream": { - "type": "structure", - "eventstream": true, - "members": { - "TypeA": {"shape": "TypeAEvent"}, - "TypeB": {"shape": "TypeBEvent"}, - "TypeC": {"shape": "TypeCEvent"} - } - }, - "TypeAEvent": { - "type": "structure", - "event": true, - "members": { - "Payload": { - "shape": "BlobType", - "eventpayload": true - } - } - }, - "TypeBEvent": { - "type": "structure", - "event": true, - "members": { - "Details": { - "shape": "Details", - "eventpayload": true - } - } - }, - "TypeCEvent": { - "type": "structure", - "event": true, - "members": { - "Details": { - "shape": "Details", - "eventpayload": true - }, - "Boolean": { - "shape": "BooleanType", - "eventheader": true - }, - "Integer": { - "shape": "IntegerType", - "eventheader": true - }, - "Blob": { - "shape": "BlobType", - "eventheader": true - }, - "String": { - "shape": "StringType", - "eventheader": true - }, - "Timestamp": { - "shape": "TimestampType", - "eventheader": true - } - } - }, - "Details": { - "type": "structure", - "members": { - "StringField": {"shape": "StringType"}, - "IntegerField": {"shape": "IntegerType"} - } - }, - "StringType": { - "type": "string" - }, - "IntegerType": { - "type": "integer" - }, - "BooleanType": { - "type": "boolean" - }, - "TimestampType": { - "type": "timestamp" - }, - "BlobType": { - "type": "blob" - } + { + "description": "Test cases for XmlMaps operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlMapsResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsInputOutputMap" + } + } + }, + "XmlMapsInputOutputMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlMaps", + "given": { + "name": "XmlMaps", + "http": { + "method": "POST", + "requestUri": "/XmlMaps", + "responseCode": 200 + }, + "output": { + "shape": "XmlMapsResponse" + }, + "documentation": "

The example tests basic map serialization.

" + }, + "description": "Tests for XML map serialization", + "result": { + "myMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n foo\n \n there\n \n \n \n baz\n \n bye\n \n \n \n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Payload": [ - { - "TypeA": {"Payload": "somebytes"} - }, - { - "TypeB": { - "Details": { - "StringField": "somestring", - "IntegerField": 123 - } - } - } - ] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "AAAAbAAAAFPLgkVrDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVR5cGVBDTpjb250ZW50LXR5cGUHABhhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1zb21lYnl0ZXMesj2HAAAAsAAAAEOaMMdXDTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVR5cGVCDTpjb250ZW50LXR5cGUHAAh0ZXh0L3htbDxUeXBlQiB4bWxucz0iIj48U3RyaW5nRmllbGQ+c29tZXN0cmluZzwvU3RyaW5nRmllbGQ+PEludGVnZXJGaWVsZD4xMjM8L0ludGVnZXJGaWVsZD48L1R5cGVCPiwthPo=" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Payload": [ - { - "TypeC": { - "Boolean": true, - "Integer": 123, - "Blob": "someblob", - "String": "somestring", - "Timestamp": 1422172800, - "Details": { - "StringField": "somestring", - "IntegerField": 123 - } - } - } - ] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "AAABAQAAAJBjEbY4DTptZXNzYWdlLXR5cGUHAAVldmVudAs6ZXZlbnQtdHlwZQcABVR5cGVDDTpjb250ZW50LXR5cGUHAAh0ZXh0L3htbAdCb29sZWFuAAdJbnRlZ2VyBAAAAHsEQmxvYgYACHNvbWVibG9iBlN0cmluZwcACnNvbWVzdHJpbmcJVGltZXN0YW1wCAAAAUsgGsQAPERldGFpbHMgeG1sbnM9IiI+PFN0cmluZ0ZpZWxkPnNvbWVzdHJpbmc8L1N0cmluZ0ZpZWxkPjxJbnRlZ2VyRmllbGQ+MTIzPC9JbnRlZ2VyRmllbGQ+PC9EZXRhaWxzPhGUvKo=" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "Payload": [] - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "" - } - } - ] - }, - { - "description": "Modeled exceptions", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlMapsXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlMapsXmlNameResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsXmlNameInputOutputMap" + } + } + }, + "XmlMapsXmlNameInputOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "Attribute" + }, + "value": { + "shape": "GreetingStruct", + "locationName": "Setting" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "XmlMapsXmlName", + "given": { + "name": "XmlMapsXmlName", + "http": { + "method": "POST", + "requestUri": "/XmlMapsXmlName", + "responseCode": 200 + }, + "output": { + "shape": "XmlMapsXmlNameResponse" + } + }, + "description": "Serializes XML lists", + "result": { + "myMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n foo\n \n there\n \n \n \n baz\n \n bye\n \n \n \n\n" + } + } + ] }, - "shapes": { - "ExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "ImaHeader": { - "shape": "HeaderShape" - }, - "ImaHeaderLocation": { - "shape": "HeaderShape", - "locationName": "X-Foo" - }, - "Status": { - "shape": "StatusShape", - "location": "statusCode" - }, - "BodyMember": { - "shape": "StringType" - }, - "Message": { - "shape": "StringType" - } - } - }, - "OtherExceptionShape": { - "exception": true, - "type": "structure", - "members": { - "BodyMember": { - "shape": "StringType" - } - } - }, - "HeaderShape": { - "type": "string", - "location": "header" - }, - "StatusShape": { - "type": "integer" - }, - "StringType": { - "type": "string" - } + { + "description": "Test cases for XmlMapWithXmlNamespace operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlMapWithXmlNamespaceResponse": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapWithXmlNamespaceInputOutputMap", + "locationName": "KVP", + "xmlNamespace": "https://the-member.example.com" + } + } + }, + "XmlMapWithXmlNamespaceInputOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K", + "xmlNamespace": "https://the-key.example.com" + }, + "value": { + "shape": "String", + "locationName": "V", + "xmlNamespace": "https://the-value.example.com" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "RestXmlXmlMapWithXmlNamespace", + "given": { + "name": "XmlMapWithXmlNamespace", + "http": { + "method": "POST", + "requestUri": "/XmlMapWithXmlNamespace", + "responseCode": 200 + }, + "output": { + "shape": "XmlMapWithXmlNamespaceResponse" + }, + "documentation": "

Maps with @xmlNamespace and @xmlName

" + }, + "description": "Serializes XML maps in responses that have xmlNamespace and xmlName on members", + "result": { + "myMap": { + "a": "A", + "b": "B" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n a\n A\n \n \n b\n B\n \n \n" + } + } + ] }, - "cases": [ - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "ImaHeader": "test", - "ImaHeaderLocation": "abc", - "Status": 400, - "BodyMember": "mybody", - "Message": "mymessage" - }, - "errorCode": "ExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Requestid": "foo-id" - }, - "body": "SomeTypeExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": { - "BodyMember": "mybody" - }, - "errorCode": "OtherExceptionShape", - "errorMessage": "mymessage", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Requestid": "foo-id" - }, - "body": "SomeTypeOtherExceptionShapemymessagemybody" - } - }, - { - "given": { - "errors": [ - {"shape": "ExceptionShape"} - ], - "name": "OperationName" - }, - "error": {}, - "errorCode": "UndefinedShape", - "response": { - "status_code": 400, - "headers": { - "ImaHeader": "test", - "X-Foo": "abc", - "X-Amzn-Requestid": "foo-id" - }, - "body": "SomeTypeUndefinedShapemybody" - } - } - ] - }, - { - "description": "Unions", - "metadata": { - "protocol": "rest-xml" - }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "UnionMember": { - "shape": "UnionType" - } - } - }, - "UnionType": { - "type": "structure", - "members": { - "S":{"shape":"StringType"}, - "L": {"shape": "ListType"} - }, - "union": true - }, - "ListType": { - "type": "list", - "member": { - "shape": "StringType" - } - }, - "StringType": { - "type": "string" - } - }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"S": "string value"} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "string value" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"L": ["a", "b"]} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "ab" - } - }, - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "UnionMember": {"SDK_UNKNOWN_MEMBER": {"name": "SomeUnknownMember"}} - }, - "response": { - "status_code": 200, - "headers": {}, - "body": "foo" - } - } - ] - }, - { - "description": "List in header", - "metadata": { - "protocol": "rest-xml" + { + "description": "Test cases for XmlNamespaces operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlNamespacesResponse": { + "type": "structure", + "members": { + "nested": { + "shape": "XmlNamespaceNested" + } + }, + "xmlNamespace": "http://foo.com" + }, + "XmlNamespaceNested": { + "type": "structure", + "members": { + "foo": { + "shape": "String", + "xmlNamespace": { + "prefix": "baz", + "uri": "http://baz.com" + } + }, + "values": { + "shape": "XmlNamespacedList", + "xmlNamespace": "http://qux.com" + } + }, + "xmlNamespace": "http://foo.com" + }, + "String": { + "type": "string" + }, + "XmlNamespacedList": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "http://bux.com" + } + } + }, + "cases": [ + { + "id": "XmlNamespaces", + "given": { + "name": "XmlNamespaces", + "http": { + "method": "POST", + "requestUri": "/XmlNamespaces", + "responseCode": 200 + }, + "output": { + "shape": "XmlNamespacesResponse" + } + }, + "description": "Serializes XML namespaces", + "result": { + "nested": { + "foo": "Foo", + "values": [ + "Bar", + "Baz" + ] + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n Foo\n \n Bar\n Baz\n \n \n\n" + } + } + ] }, - "shapes": { - "OutputShape": { - "type": "structure", - "members": { - "ListMember": { - "shape": "ListShape", - "location": "header", - "locationName": "x-amz-list-member" - } - } - }, - "ListShape": { - "type": "list", - "member": { - "shape": "EnumType" - } - }, - "EnumType": { - "type": "string", - "enum": ["one", "two", "three"] - } + { + "description": "Test cases for XmlTimestamps operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlTimestampsResponse": { + "type": "structure", + "members": { + "normal": { + "shape": "Timestamp" + }, + "dateTime": { + "shape": "SyntheticTimestamp_date_time" + }, + "dateTimeOnTarget": { + "shape": "DateTime" + }, + "epochSeconds": { + "shape": "SyntheticTimestamp_epoch_seconds" + }, + "epochSecondsOnTarget": { + "shape": "EpochSeconds" + }, + "httpDate": { + "shape": "SyntheticTimestamp_http_date" + }, + "httpDateOnTarget": { + "shape": "HttpDate" + } + } + }, + "Timestamp": { + "type": "timestamp" + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + } + }, + "cases": [ + { + "id": "XmlTimestamps", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Tests how normal timestamps are serialized", + "result": { + "normal": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2014-04-29T18:30:38Z\n\n" + } + }, + { + "id": "XmlTimestampsWithDateTimeFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time works like normal timestamps", + "result": { + "dateTime": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2014-04-29T18:30:38Z\n\n" + } + }, + { + "id": "XmlTimestampsWithDateTimeOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of date-time on the target shape works like normal timestamps", + "result": { + "dateTimeOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 2014-04-29T18:30:38Z\n\n" + } + }, + { + "id": "XmlTimestampsWithEpochSecondsFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds works", + "result": { + "epochSeconds": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 1398796238\n\n" + } + }, + { + "id": "XmlTimestampsWithEpochSecondsOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of epoch-seconds on the target shape works", + "result": { + "epochSecondsOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n 1398796238\n\n" + } + }, + { + "id": "XmlTimestampsWithHttpDateFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date works", + "result": { + "httpDate": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Tue, 29 Apr 2014 18:30:38 GMT\n\n" + } + }, + { + "id": "XmlTimestampsWithHttpDateOnTargetFormat", + "given": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/XmlTimestamps", + "responseCode": 200 + }, + "output": { + "shape": "XmlTimestampsResponse" + }, + "documentation": "

This tests how timestamps are serialized, including using the default format of date-time and various @timestampFormat trait values.

" + }, + "description": "Ensures that the timestampFormat of http-date on the target shape works", + "result": { + "httpDateOnTarget": 1398796238 + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n Tue, 29 Apr 2014 18:30:38 GMT\n\n" + } + } + ] }, - "cases": [ - { - "given": { - "output": { - "shape": "OutputShape" - }, - "name": "OperationName" - }, - "result": { - "ListMember": ["one", "two", "three"] - }, - "response": { - "status_code": 200, - "headers": { - "x-amz-list-member": " one,two , three " - }, - "body": "" - } - } - ] - } + { + "description": "Test cases for XmlUnions operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "XmlUnionsResponse": { + "type": "structure", + "members": { + "unionValue": { + "shape": "XmlUnionShape" + } + } + }, + "XmlUnionShape": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "booleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + }, + "unionValue": { + "shape": "XmlUnionShape" + }, + "structValue": { + "shape": "XmlNestedUnionStruct" + } + }, + "union": true + }, + "String": { + "type": "string" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "Integer": { + "type": "integer", + "box": true + }, + "Long": { + "type": "long", + "box": true + }, + "Float": { + "type": "float", + "box": true + }, + "Double": { + "type": "double", + "box": true + }, + "XmlNestedUnionStruct": { + "type": "structure", + "members": { + "stringValue": { + "shape": "String" + }, + "booleanValue": { + "shape": "Boolean" + }, + "byteValue": { + "shape": "Integer" + }, + "shortValue": { + "shape": "Integer" + }, + "integerValue": { + "shape": "Integer" + }, + "longValue": { + "shape": "Long" + }, + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + } + } + } + }, + "cases": [ + { + "id": "XmlUnionsWithStructMember", + "given": { + "name": "XmlUnions", + "http": { + "method": "PUT", + "requestUri": "/XmlUnions", + "responseCode": 200 + }, + "output": { + "shape": "XmlUnionsResponse" + }, + "idempotent": true + }, + "description": "Serializes union struct member", + "result": { + "unionValue": { + "structValue": { + "stringValue": "string", + "booleanValue": true, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n string\n true\n 1\n 2\n 3\n 4\n 5.5\n 6.5\n \n \n\n" + } + }, + { + "id": "XmlUnionsWithStringMember", + "given": { + "name": "XmlUnions", + "http": { + "method": "PUT", + "requestUri": "/XmlUnions", + "responseCode": 200 + }, + "output": { + "shape": "XmlUnionsResponse" + }, + "idempotent": true + }, + "description": "Serializes union string member", + "result": { + "unionValue": { + "stringValue": "some string" + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n some string\n \n\n" + } + }, + { + "id": "XmlUnionsWithBooleanMember", + "given": { + "name": "XmlUnions", + "http": { + "method": "PUT", + "requestUri": "/XmlUnions", + "responseCode": 200 + }, + "output": { + "shape": "XmlUnionsResponse" + }, + "idempotent": true + }, + "description": "Serializes union boolean member", + "result": { + "unionValue": { + "booleanValue": true + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n true\n \n\n" + } + }, + { + "id": "XmlUnionsWithUnionMember", + "given": { + "name": "XmlUnions", + "http": { + "method": "PUT", + "requestUri": "/XmlUnions", + "responseCode": 200 + }, + "output": { + "shape": "XmlUnionsResponse" + }, + "idempotent": true + }, + "description": "Serializes union member", + "result": { + "unionValue": { + "unionValue": { + "booleanValue": true + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": "\n \n \n true\n \n \n\n" + } + } + ] + } ] From 568fe0169bcdee3a3c859b4841ccee5e6623ecfe Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Wed, 10 Jul 2024 10:29:06 -0700 Subject: [PATCH 2/9] Fix minor typos in test_protocols.py --- tests/unit/test_protocols.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 253ec5f7a5..5b13ade230 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -37,11 +37,11 @@ To run tests from only a single file, you can set the BOTOCORE_TEST env var:: - BOTOCORE_TEST=tests/unit/compliance/input/json.json pytest tests/unit/test_protocols.py + BOTOCORE_TEST=tests/unit/protocols/input/json.json pytest tests/unit/test_protocols.py To run a single test suite you can set the BOTOCORE_TEST_ID env var: - BOTOCORE_TEST=tests/unit/compliance/input/json.json BOTOCORE_TEST_ID=5 \ + BOTOCORE_TEST=tests/unit/protocols/input/json.json BOTOCORE_TEST_ID=5 \ pytest tests/unit/test_protocols.py To run a single test case in a suite (useful when debugging a single test), you @@ -431,7 +431,7 @@ def _walk_files(): def _load_cases(full_path): - # During developement, you can set the BOTOCORE_TEST_ID + # During development, you can set the BOTOCORE_TEST_ID # to run a specific test suite or even a specific test case. # The format is BOTOCORE_TEST_ID=suite_id:test_id or # BOTOCORE_TEST_ID=suite_id @@ -462,7 +462,7 @@ def _get_suite_test_id(): if len(split) == 2: suite_id, test_id = int(split[0]), int(split[1]) else: - suite_id = int(split([0])) + suite_id = int(split[0]) except TypeError: # Same exception, just give a better error message. raise TypeError( From 244f146fc617f10672378e329cc0d1d9080eee46 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Fri, 6 Sep 2024 03:50:26 -0700 Subject: [PATCH 3/9] Implement granular protocol tests ignore list --- .../protocols/protocol-tests-ignore-list.json | 65 +++++++++++++++++++ tests/unit/test_protocols.py | 49 +++++++++++++- 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 tests/unit/protocols/protocol-tests-ignore-list.json diff --git a/tests/unit/protocols/protocol-tests-ignore-list.json b/tests/unit/protocols/protocol-tests-ignore-list.json new file mode 100644 index 0000000000..ea30dd5c7b --- /dev/null +++ b/tests/unit/protocols/protocol-tests-ignore-list.json @@ -0,0 +1,65 @@ +{ + "general": { + }, + "protocols": { + "ec2" : { + "output": { + "cases": [ + "Ec2ComplexError" + ] + } + }, + "query" : { + "output": { + "cases": [ + "QueryEmptyInputAndEmptyOutput", + "QueryCustomizedError", + "QueryComplexError", + "QueryNoInputAndNoOutput", + "QueryNoInputAndOutput" + ] + } + }, + "json" : { + "output" : { + "cases": [ + "AwsJson11FooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "AwsJson11FooErrorUsingXAmznErrorTypeWithUri" + ] + } + }, + "json_1_0" : { + "output" : { + "cases": [ + "AwsJson10FooErrorUsingXAmznErrorType", + "AwsJson10FooErrorUsingXAmznErrorTypeWithUri", + "AwsJson10FooErrorUsingXAmznErrorTypeWithUriAndNamespace" + ] + } + }, + "rest-json" : { + "output" : { + "cases": [ + "RestJsonFooErrorUsingXAmznErrorType", + "RestJsonFooErrorUsingXAmznErrorTypeWithUri", + "RestJsonFooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "RestJsonHttpPayloadTraitsWithNoBlobBody", + "RestJsonHttpPayloadWithUnsetUnion", + "RestJsonInputAndOutputWithTimestampHeaders", + "RestJsonDeserializesDenseSetMapAndSkipsNull" + ] + } + }, + "rest-xml": { + "output": { + "cases": [ + "InputAndOutputWithTimestampHeaders", + "RestXmlHttpPayloadWithUnsetUnion", + "HttpPayloadTraitsWithNoBlobBody", + "ComplexError", + "BodyWithXmlName" + ] + } + } + } +} \ No newline at end of file diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 5b13ade230..13b5571ae0 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -98,7 +98,10 @@ 'rest-json': RestJSONParser, 'rest-xml': RestXMLParser, } -PROTOCOL_TEST_BLACKLIST = ['Idempotency token auto fill'] +IGNORE_LIST_FILENAME = "protocol-tests-ignore-list.json" +PROTOCOL_TEST_IGNORE_LIST_PATH = os.path.join(TEST_DIR, IGNORE_LIST_FILENAME) +with open(PROTOCOL_TEST_IGNORE_LIST_PATH) as f: + PROTOCOL_TEST_IGNORE_LIST = json.load(f) class TestType(Enum): @@ -116,7 +119,13 @@ def _compliance_tests(test_type=None): for full_path in _walk_files(): if full_path.endswith('.json'): for model, case, basename in _load_cases(full_path): - if model.get('description') in PROTOCOL_TEST_BLACKLIST: + protocol = basename.replace('.json', '') + if _should_ignore_test( + protocol, + "input" if inp else "output", + model['description'], + case['id'], + ): continue if 'params' in case and inp: yield model, case, basename @@ -427,6 +436,8 @@ def _walk_files(): else: for root, _, filenames in os.walk(TEST_DIR): for filename in filenames: + if filename == IGNORE_LIST_FILENAME: + continue yield os.path.join(root, filename) @@ -471,3 +482,37 @@ def _get_suite_test_id(): "integers." ) return suite_id, test_id + + +def _should_ignore_test(protocol, test_type, suite, case): + """ + Determines if a protocol test should be ignored. + :type protocol: str + :param protocol: The protocol name as represented by its corresponding + protocol test file name (without the .json extension). + :type test_type: str + :param test_type: The protocol test type ("input" or "output"). + :type suite: str + :param suite: The "description" attribute of a protocol test suite. + :type case: str + :param case: The "id" attribute of a specific protocol test case. + :return: True if the protocol test should be ignored, False otherwise. + :rtype: bool + """ + ignore_list = PROTOCOL_TEST_IGNORE_LIST.get('general', {}).get( + test_type, {} + ) + ignore_suites = ignore_list.get('suites', []) + ignore_cases = ignore_list.get('cases', []) + + if suite in ignore_suites or case in ignore_cases: + return True + + protocol_ignore_list = ( + PROTOCOL_TEST_IGNORE_LIST.get('protocols', {}) + .get(protocol, {}) + .get(test_type, {}) + ) + protocol_ignore_suites = protocol_ignore_list.get('suites', []) + protocol_ignore_cases = protocol_ignore_list.get('cases', []) + return suite in protocol_ignore_suites or case in protocol_ignore_cases From f9acd2bb6355d549e0519ac66ccaa6aea7b9ea6c Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Fri, 6 Sep 2024 03:55:30 -0700 Subject: [PATCH 4/9] Implement granular protocol tests ignore list --- botocore/parsers.py | 37 ++++++++++++++++++++++--------- tests/unit/test_protocols.py | 42 +++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/botocore/parsers.py b/botocore/parsers.py index 0c7a34f218..95ffd0336d 100644 --- a/botocore/parsers.py +++ b/botocore/parsers.py @@ -201,6 +201,10 @@ class ResponseParser: DEFAULT_ENCODING = 'utf-8' EVENT_STREAM_PARSER_CLS = None + # This is a list of known values for the "location" key in the + # serialization dict. The location key tells us where in the response + # to parse the value. + KNOWN_LOCATIONS = ('statusCode', 'header', 'headers') def __init__(self, timestamp_parser=None, blob_parser=None): if timestamp_parser is None: @@ -356,6 +360,9 @@ def _has_unknown_tagged_union_member(self, shape, value): if shape.is_tagged_union: cleaned_value = value.copy() cleaned_value.pop("__type", None) + cleaned_value = { + k: v for k, v in cleaned_value.items() if v is not None + } if len(cleaned_value) != 1: error_msg = ( "Invalid service response: %s must have one and only " @@ -363,7 +370,11 @@ def _has_unknown_tagged_union_member(self, shape, value): ) raise ResponseParserError(error_msg % shape.name) tag = self._get_first_key(cleaned_value) - if tag not in shape.members: + serialized_member_names = [ + shape.members[member].serialization.get('name', member) + for member in shape.members + ] + if tag not in serialized_member_names: msg = ( "Received a tagged union response with member " "unknown to client: %s. Please upgrade SDK for full " @@ -427,11 +438,12 @@ def _handle_structure(self, shape, node): return self._handle_unknown_tagged_union_member(tag) for member_name in members: member_shape = members[member_name] + location = member_shape.serialization.get('location') if ( - 'location' in member_shape.serialization + location in self.KNOWN_LOCATIONS or member_shape.serialization.get('eventheader') ): - # All members with locations have already been handled, + # All members with known locations have already been handled, # so we don't need to parse these members. continue xml_name = self._member_key_name(member_shape, member_name) @@ -577,7 +589,7 @@ def _do_parse(self, response, shape): return self._parse_body_as_xml(response, shape, inject_metadata=True) def _parse_body_as_xml(self, response, shape, inject_metadata=True): - xml_contents = response['body'] + xml_contents = response['body'] or b'' root = self._parse_xml_string_to_dom(xml_contents) parsed = {} if shape is not None: @@ -707,8 +719,10 @@ def _do_error_parse(self, response, shape): # code has a couple forms as well: # * "com.aws.dynamodb.vAPI#ProvisionedThroughputExceededException" # * "ResourceNotFoundException" + if ':' in code: + code = code.split(':', 1)[0] if '#' in code: - code = code.rsplit('#', 1)[1] + code = code.split('#', 1)[1] if 'x-amzn-query-error' in headers: code = self._do_query_compatible_error_parse( code, headers, error @@ -1020,14 +1034,17 @@ def _inject_error_code(self, error, response): # The "Code" value can come from either a response # header or a value in the JSON body. body = self._initial_body_parse(response['body']) + code = None if 'x-amzn-errortype' in response['headers']: code = response['headers']['x-amzn-errortype'] - # Could be: - # x-amzn-errortype: ValidationException: - code = code.split(':')[0] - error['Error']['Code'] = code elif 'code' in body or 'Code' in body: - error['Error']['Code'] = body.get('code', body.get('Code', '')) + code = body.get('code', body.get('Code', '')) + if code is not None: + if ':' in code: + code = code.split(':', 1)[0] + if '#' in code: + code = code.split('#', 1)[1] + error['Error']['Code'] = code def _handle_integer(self, shape, value): return int(value) diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 13b5571ae0..a5447ce9ed 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -190,7 +190,7 @@ def stream(self): ) def test_output_compliance(json_description, case, basename): service_description = copy.deepcopy(json_description) - operation_name = case.get('name', 'OperationName') + operation_name = case.get('given', {}).get('name', 'OperationName') service_description['operations'] = { operation_name: case, } @@ -198,16 +198,23 @@ def test_output_compliance(json_description, case, basename): try: model = ServiceModel(service_description) operation_model = OperationModel(case['given'], model) - parser = PROTOCOL_PARSERS[model.metadata['protocol']]( + protocol = model.metadata['protocol'] + parser = PROTOCOL_PARSERS[protocol]( timestamp_parser=_compliance_timestamp_parser ) # We load the json as utf-8, but the response parser is at the # botocore boundary, so it expects to work with bytes. - body_bytes = case['response']['body'].encode('utf-8') - case['response']['body'] = body_bytes + # If a test case doesn't define a response body, set it to `None`. + if 'body' in case['response']: + body_bytes = case['response']['body'].encode('utf-8') + case['response']['body'] = body_bytes + else: + case['response']['body'] = b'' # We need the headers to be case insensitive - headers = HeadersDict(case['response']['headers']) - case['response']['headers'] = headers + # If a test case doesn't define response headers, set it to an empty `HeadersDict`. + case['response']['headers'] = HeadersDict( + case['response'].get('headers', {}) + ) # If this is an event stream fake the raw streamed response if operation_model.has_event_stream_output: case['response']['body'] = MockRawResponse(body_bytes) @@ -215,7 +222,8 @@ def test_output_compliance(json_description, case, basename): output_shape = operation_model.output_shape parsed = parser.parse(case['response'], output_shape) try: - error_shape = model.shape_for(parsed['Error']['Code']) + error_code = parsed.get("Error", {}).get("Code") + error_shape = model.shape_for_error_code(error_code) except NoShapeFoundError: error_shape = None if error_shape is not None: @@ -223,6 +231,8 @@ def test_output_compliance(json_description, case, basename): parsed.update(error_parse) else: output_shape = operation_model.output_shape + if protocol == 'query' and output_shape and output_shape.members: + output_shape.serialization['resultWrapper'] = f'{operation_name}Result' parsed = parser.parse(case['response'], output_shape) parsed = _fixup_parsed_result(parsed) except Exception as e: @@ -288,6 +298,11 @@ def _fixup_parsed_result(parsed): for key in error_keys: if key not in ['Code', 'Message']: del parsed['Error'][key] + # 5. Special float types. In the protocol test suite, certain special float + # types are represented as strings: "Infinity", "-Infinity", and "NaN". + # However, we parse these values as actual floats types, so we need to convert + # them back to their string representation. + parsed = _convert_special_floats_to_string(parsed) return parsed @@ -308,12 +323,23 @@ def _convert_bytes_to_str(parsed): return parsed +def _convert_special_floats_to_string(parsed): + for key, value in parsed.items(): + if value == float('Infinity'): + parsed[key] = 'Infinity' + elif value == float('-Infinity'): + parsed[key] = '-Infinity' + elif value != value: + parsed[key] = 'NaN' + return parsed + + def _compliance_timestamp_parser(value): datetime = parse_timestamp(value) # Convert from our time zone to UTC datetime = datetime.astimezone(tzutc()) # Convert to epoch. - return int(timegm(datetime.timetuple())) + return datetime.timestamp() def _output_failure_message( From 72d05f13635fa524218719634cc21cd95ea4a61e Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Fri, 6 Sep 2024 08:21:49 -0700 Subject: [PATCH 5/9] * Support old ignore list for serializer tests * Update ignore list * Resolve some parser issues --- botocore/parsers.py | 8 +++++ .../protocols/protocol-tests-ignore-list.json | 35 +++++++++++-------- tests/unit/test_protocols.py | 17 +++++---- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/botocore/parsers.py b/botocore/parsers.py index 95ffd0336d..819dbfd8bb 100644 --- a/botocore/parsers.py +++ b/botocore/parsers.py @@ -124,6 +124,7 @@ from botocore.compat import ETree, XMLParseError from botocore.eventstream import EventStream, NoInitialResponseError from botocore.utils import ( + ensure_boolean, is_json_value_header, lowercase_dict, merge_dicts, @@ -1046,10 +1047,17 @@ def _inject_error_code(self, error, response): code = code.split('#', 1)[1] error['Error']['Code'] = code + def _handle_boolean(self, shape, value): + return ensure_boolean(value) + def _handle_integer(self, shape, value): return int(value) + def _handle_float(self, shape, value): + return float(value) + _handle_long = _handle_integer + _handle_double = _handle_float class RestXMLParser(BaseRestParser, BaseXMLResponseParser): diff --git a/tests/unit/protocols/protocol-tests-ignore-list.json b/tests/unit/protocols/protocol-tests-ignore-list.json index ea30dd5c7b..f8cb9944a8 100644 --- a/tests/unit/protocols/protocol-tests-ignore-list.json +++ b/tests/unit/protocols/protocol-tests-ignore-list.json @@ -1,30 +1,31 @@ { - "general": { - }, + "general": {}, "protocols": { - "ec2" : { + "query" : { "output": { "cases": [ - "Ec2ComplexError" + "QueryXmlLists", + "QueryComplexError" ] } }, - "query" : { + "ec2" : { "output": { "cases": [ - "QueryEmptyInputAndEmptyOutput", - "QueryCustomizedError", - "QueryComplexError", - "QueryNoInputAndNoOutput", - "QueryNoInputAndOutput" + "Ec2XmlLists", + "Ec2ComplexError" ] } }, "json" : { "output" : { "cases": [ + "AwsJson11FooErrorUsingXAmznErrorType", + "AwsJson11FooErrorUsingXAmznErrorTypeWithUri", "AwsJson11FooErrorUsingXAmznErrorTypeWithUriAndNamespace", - "AwsJson11FooErrorUsingXAmznErrorTypeWithUri" + "AwsJson11FooErrorUsingCode", + "AwsJson11FooErrorUsingCodeAndNamespace", + "AwsJson11FooErrorUsingCodeUriAndNamespace" ] } }, @@ -33,7 +34,10 @@ "cases": [ "AwsJson10FooErrorUsingXAmznErrorType", "AwsJson10FooErrorUsingXAmznErrorTypeWithUri", - "AwsJson10FooErrorUsingXAmznErrorTypeWithUriAndNamespace" + "AwsJson10FooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "AwsJson10FooErrorUsingCode", + "AwsJson10FooErrorUsingCodeAndNamespace", + "AwsJson10FooErrorUsingCodeUriAndNamespace" ] } }, @@ -46,7 +50,9 @@ "RestJsonHttpPayloadTraitsWithNoBlobBody", "RestJsonHttpPayloadWithUnsetUnion", "RestJsonInputAndOutputWithTimestampHeaders", - "RestJsonDeserializesDenseSetMapAndSkipsNull" + "RestJsonInputAndOutputWithQuotedStringHeaders", + "RestJsonDeserializesDenseSetMapAndSkipsNull", + "MediaTypeHeaderOutputBase64" ] } }, @@ -57,7 +63,8 @@ "RestXmlHttpPayloadWithUnsetUnion", "HttpPayloadTraitsWithNoBlobBody", "ComplexError", - "BodyWithXmlName" + "BodyWithXmlName", + "XmlLists" ] } } diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index a5447ce9ed..743036a73c 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -98,6 +98,7 @@ 'rest-json': RestJSONParser, 'rest-xml': RestXMLParser, } +PROTOCOL_TEST_BLACKLIST = ['Idempotency token auto fill'] IGNORE_LIST_FILENAME = "protocol-tests-ignore-list.json" PROTOCOL_TEST_IGNORE_LIST_PATH = os.path.join(TEST_DIR, IGNORE_LIST_FILENAME) with open(PROTOCOL_TEST_IGNORE_LIST_PATH) as f: @@ -120,16 +121,18 @@ def _compliance_tests(test_type=None): if full_path.endswith('.json'): for model, case, basename in _load_cases(full_path): protocol = basename.replace('.json', '') - if _should_ignore_test( - protocol, - "input" if inp else "output", - model['description'], - case['id'], - ): - continue if 'params' in case and inp: + if model.get('description') in PROTOCOL_TEST_BLACKLIST: + continue yield model, case, basename elif 'response' in case and out: + if _should_ignore_test( + protocol, + "output", + model['description'], + case['id'], + ): + continue yield model, case, basename From 8a12dbe0529d6f5213782c21a68d2fe8dd86ec3c Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Fri, 6 Sep 2024 08:22:40 -0700 Subject: [PATCH 6/9] Run formatter --- .../unit/protocols/protocol-tests-ignore-list.json | 2 +- tests/unit/test_protocols.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/unit/protocols/protocol-tests-ignore-list.json b/tests/unit/protocols/protocol-tests-ignore-list.json index f8cb9944a8..46f1d445af 100644 --- a/tests/unit/protocols/protocol-tests-ignore-list.json +++ b/tests/unit/protocols/protocol-tests-ignore-list.json @@ -69,4 +69,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 743036a73c..9a35f5aa69 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -54,7 +54,6 @@ import copy import os from base64 import b64decode -from calendar import timegm from enum import Enum import pytest @@ -127,10 +126,10 @@ def _compliance_tests(test_type=None): yield model, case, basename elif 'response' in case and out: if _should_ignore_test( - protocol, - "output", - model['description'], - case['id'], + protocol, + "output", + model['description'], + case['id'], ): continue yield model, case, basename @@ -235,7 +234,9 @@ def test_output_compliance(json_description, case, basename): else: output_shape = operation_model.output_shape if protocol == 'query' and output_shape and output_shape.members: - output_shape.serialization['resultWrapper'] = f'{operation_name}Result' + output_shape.serialization['resultWrapper'] = ( + f'{operation_name}Result' + ) parsed = parser.parse(case['response'], output_shape) parsed = _fixup_parsed_result(parsed) except Exception as e: From 69ec28a56426bc4c34c3a898ec748b28d515c696 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Fri, 6 Sep 2024 08:54:23 -0700 Subject: [PATCH 7/9] Fix docstring spacing. --- tests/unit/test_protocols.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 9a35f5aa69..dcb3fee127 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -517,15 +517,20 @@ def _get_suite_test_id(): def _should_ignore_test(protocol, test_type, suite, case): """ Determines if a protocol test should be ignored. + :type protocol: str :param protocol: The protocol name as represented by its corresponding protocol test file name (without the .json extension). + :type test_type: str :param test_type: The protocol test type ("input" or "output"). + :type suite: str :param suite: The "description" attribute of a protocol test suite. + :type case: str :param case: The "id" attribute of a specific protocol test case. + :return: True if the protocol test should be ignored, False otherwise. :rtype: bool """ From 5d9bb32463fcec88a95f9b9fd23f3474cbe00f67 Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Wed, 8 Jan 2025 15:51:01 -0500 Subject: [PATCH 8/9] Update to the latest protocol test models --- tests/unit/protocols/output/json.json | 108 +++++++++++++++++++++ tests/unit/protocols/output/rest-json.json | 22 ++--- tests/unit/protocols/output/rest-xml.json | 97 ++++++++++++++++-- 3 files changed, 208 insertions(+), 19 deletions(-) diff --git a/tests/unit/protocols/output/json.json b/tests/unit/protocols/output/json.json index 8b2ab6a13a..158b3747f4 100644 --- a/tests/unit/protocols/output/json.json +++ b/tests/unit/protocols/output/json.json @@ -732,6 +732,114 @@ } ] }, + { + "description": "Test cases for JsonIntEnums operation", + "metadata": { + "protocol": "json", + "protocols": [ + "json" + ], + "apiVersion": "2018-01-01", + "jsonVersion": "1.1", + "targetPrefix": "JsonProtocol" + }, + "shapes": { + "JsonIntEnumsInputOutput": { + "type": "structure", + "members": { + "intEnum1": { + "shape": "IntegerEnum" + }, + "intEnum2": { + "shape": "IntegerEnum" + }, + "intEnum3": { + "shape": "IntegerEnum" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "intEnumSet": { + "shape": "IntegerEnumSet" + }, + "intEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "AwsJson11IntEnums", + "given": { + "name": "JsonIntEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "JsonIntEnumsInputOutput" + }, + "documentation": "

This example serializes intEnums as top level properties, in lists, sets, and maps.

", + "idempotent": true + }, + "description": "Serializes simple scalar properties", + "result": { + "intEnum1": 1, + "intEnum2": 2, + "intEnum3": 3, + "intEnumList": [ + 1, + 2 + ], + "intEnumSet": [ + 1, + 2 + ], + "intEnumMap": { + "a": 1, + "b": 2 + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.1", + "X-Amz-Target": "JsonProtocol.JsonIntEnums" + }, + "body": "{\n \"intEnum1\": 1,\n \"intEnum2\": 2,\n \"intEnum3\": 3,\n \"intEnumList\": [\n 1,\n 2\n ],\n \"intEnumSet\": [\n 1,\n 2\n ],\n \"intEnumMap\": {\n \"a\": 1,\n \"b\": 2\n }\n}" + } + } + ] + }, { "description": "Test cases for JsonUnions operation", "metadata": { diff --git a/tests/unit/protocols/output/rest-json.json b/tests/unit/protocols/output/rest-json.json index c7e9f46a32..bf69fd944d 100644 --- a/tests/unit/protocols/output/rest-json.json +++ b/tests/unit/protocols/output/rest-json.json @@ -1360,12 +1360,12 @@ "foo": { "shape": "String", "location": "header", - "locationName": "X-Foo" + "locationName": "x-foo" }, "fooMap": { "shape": "StringMap", "location": "headers", - "locationName": "X-Foo-" + "locationName": "x-foo-" } } }, @@ -1401,16 +1401,16 @@ "result": { "foo": "Foo", "fooMap": { - "Abc": "Abc value", - "Def": "Def value" + "abc": "Abc value", + "def": "Def value" } }, "response": { "status_code": 200, "headers": { - "X-Foo": "Foo", - "X-Foo-Abc": "Abc value", - "X-Foo-Def": "Def value" + "x-foo": "Foo", + "x-foo-abc": "Abc value", + "x-foo-def": "Def value" } } } @@ -1467,15 +1467,15 @@ "description": "(de)serializes all response headers", "result": { "prefixHeaders": { - "X-Foo": "Foo", - "Hello": "Hello" + "x-foo": "Foo", + "hello": "Hello" } }, "response": { "status_code": 200, "headers": { - "Hello": "Hello", - "X-Foo": "Foo" + "hello": "Hello", + "x-foo": "Foo" } } } diff --git a/tests/unit/protocols/output/rest-xml.json b/tests/unit/protocols/output/rest-xml.json index 9d2efabd01..c048fedfe8 100644 --- a/tests/unit/protocols/output/rest-xml.json +++ b/tests/unit/protocols/output/rest-xml.json @@ -1214,12 +1214,12 @@ "foo": { "shape": "String", "location": "header", - "locationName": "X-Foo" + "locationName": "x-foo" }, "fooMap": { "shape": "FooPrefixHeaders", "location": "headers", - "locationName": "X-Foo-" + "locationName": "x-foo-" } } }, @@ -1255,16 +1255,16 @@ "result": { "foo": "Foo", "fooMap": { - "Abc": "Abc value", - "Def": "Def value" + "abc": "Abc value", + "def": "Def value" } }, "response": { "status_code": 200, "headers": { - "X-Foo": "Foo", - "X-Foo-Abc": "Abc value", - "X-Foo-Def": "Def value" + "x-foo": "Foo", + "x-foo-abc": "Abc value", + "x-foo-def": "Def value" }, "body": "" } @@ -1291,7 +1291,7 @@ "response": { "status_code": 200, "headers": { - "X-Foo": "Foo" + "x-foo": "Foo" }, "body": "" } @@ -1999,6 +1999,87 @@ } ] }, + { + "description": "Test cases for NestedXmlMapWithXmlName operation", + "metadata": { + "protocol": "rest-xml", + "protocols": [ + "rest-xml" + ], + "apiVersion": "2019-12-16" + }, + "shapes": { + "NestedXmlMapWithXmlNameInputOutput": { + "type": "structure", + "members": { + "nestedXmlMapWithXmlNameMap": { + "shape": "NestedXmlMapWithXmlNameMap" + } + } + }, + "NestedXmlMapWithXmlNameMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "OuterKey" + }, + "value": { + "shape": "NestedXmlMapWithXmlNameInnerMap" + } + }, + "NestedXmlMapWithXmlNameInnerMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "InnerKey" + }, + "value": { + "shape": "String", + "locationName": "InnerValue" + } + }, + "String": { + "type": "string" + } + }, + "cases": [ + { + "id": "NestedXmlMapWithXmlNameDeserializes", + "given": { + "name": "NestedXmlMapWithXmlName", + "http": { + "method": "POST", + "requestUri": "/NestedXmlMapWithXmlName", + "responseCode": 200 + }, + "output": { + "shape": "NestedXmlMapWithXmlNameInputOutput" + }, + "documentation": "

Nested Xml Maps with key/values with @xmlName

" + }, + "description": "Serializes nested XML maps in responses that have xmlName on members", + "result": { + "nestedXmlMapWithXmlNameMap": { + "foo": { + "bar": "Baz", + "fizz": "Buzz" + }, + "qux": { + "foobar": "Bar", + "fizzbuzz": "Buzz" + } + } + }, + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/xml" + }, + "body": " \n \n \n foo\n \n \n bar\n Baz\n \n \n fizz\n Buzz\n \n \n \n \n qux\n \n \n foobar\n Bar\n \n \n fizzbuzz\n Buzz\n \n \n \n \n \n" + } + } + ] + }, { "description": "Test cases for NoInputAndNoOutput operation", "metadata": { From 843f61cb317ae98f142c73194fae11ab277319ae Mon Sep 17 00:00:00 2001 From: jonathan343 Date: Mon, 3 Feb 2025 10:38:49 -0500 Subject: [PATCH 9/9] Clean up and PR feedback. --- botocore/parsers.py | 8 ++++---- tests/unit/test_protocols.py | 39 +++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/botocore/parsers.py b/botocore/parsers.py index 819dbfd8bb..7393fb51dd 100644 --- a/botocore/parsers.py +++ b/botocore/parsers.py @@ -204,7 +204,7 @@ class ResponseParser: EVENT_STREAM_PARSER_CLS = None # This is a list of known values for the "location" key in the # serialization dict. The location key tells us where in the response - # to parse the value. + # to parse the value. Locations not in this list will be ignored. KNOWN_LOCATIONS = ('statusCode', 'header', 'headers') def __init__(self, timestamp_parser=None, blob_parser=None): @@ -590,7 +590,7 @@ def _do_parse(self, response, shape): return self._parse_body_as_xml(response, shape, inject_metadata=True) def _parse_body_as_xml(self, response, shape, inject_metadata=True): - xml_contents = response['body'] or b'' + xml_contents = response['body'] root = self._parse_xml_string_to_dom(xml_contents) parsed = {} if shape is not None: @@ -723,7 +723,7 @@ def _do_error_parse(self, response, shape): if ':' in code: code = code.split(':', 1)[0] if '#' in code: - code = code.split('#', 1)[1] + code = code.rsplit('#', 1)[1] if 'x-amzn-query-error' in headers: code = self._do_query_compatible_error_parse( code, headers, error @@ -1044,7 +1044,7 @@ def _inject_error_code(self, error, response): if ':' in code: code = code.split(':', 1)[0] if '#' in code: - code = code.split('#', 1)[1] + code = code.rsplit('#', 1)[1] error['Error']['Code'] = code def _handle_boolean(self, shape, value): diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index dcb3fee127..a2b85790c9 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -47,7 +47,7 @@ To run a single test case in a suite (useful when debugging a single test), you can set the BOTOCORE_TEST_ID env var with the ``suite_id:test_id`` syntax. - BOTOCORE_TEST_ID=5:1 pytest test/unit/test_protocols.py + BOTOCORE_TEST_ID=5:1 pytest tests/unit/test_protocols.py """ @@ -99,9 +99,6 @@ } PROTOCOL_TEST_BLACKLIST = ['Idempotency token auto fill'] IGNORE_LIST_FILENAME = "protocol-tests-ignore-list.json" -PROTOCOL_TEST_IGNORE_LIST_PATH = os.path.join(TEST_DIR, IGNORE_LIST_FILENAME) -with open(PROTOCOL_TEST_IGNORE_LIST_PATH) as f: - PROTOCOL_TEST_IGNORE_LIST = json.load(f) class TestType(Enum): @@ -112,6 +109,12 @@ class TestType(Enum): OUTPUT = "output" +def get_protocol_test_ignore_list(): + ignore_list_path = os.path.join(TEST_DIR, IGNORE_LIST_FILENAME) + with open(ignore_list_path) as f: + return json.load(f) + + def _compliance_tests(test_type=None): inp = test_type is None or test_type is TestType.INPUT out = test_type is None or test_type is TestType.OUTPUT @@ -211,7 +214,9 @@ def test_output_compliance(json_description, case, basename): body_bytes = case['response']['body'].encode('utf-8') case['response']['body'] = body_bytes else: - case['response']['body'] = b'' + case['response']['body'] = ( + b'' if protocol != "query" else b'' + ) # We need the headers to be case insensitive # If a test case doesn't define response headers, set it to an empty `HeadersDict`. case['response']['headers'] = HeadersDict( @@ -534,20 +539,18 @@ def _should_ignore_test(protocol, test_type, suite, case): :return: True if the protocol test should be ignored, False otherwise. :rtype: bool """ - ignore_list = PROTOCOL_TEST_IGNORE_LIST.get('general', {}).get( - test_type, {} - ) - ignore_suites = ignore_list.get('suites', []) - ignore_cases = ignore_list.get('cases', []) - - if suite in ignore_suites or case in ignore_cases: + # Get test suites and cases to ignore for all protocols. + ignore_list = get_protocol_test_ignore_list() + general_ignore_list = ignore_list.get('general', {}).get(test_type, {}) + general_suites = general_ignore_list.get('suites', []) + general_cases = general_ignore_list.get('cases', []) + if suite in general_suites or case in general_cases: return True + # Get test suites and cases to ignore for a specific protocol. protocol_ignore_list = ( - PROTOCOL_TEST_IGNORE_LIST.get('protocols', {}) - .get(protocol, {}) - .get(test_type, {}) + ignore_list.get('protocols', {}).get(protocol, {}).get(test_type, {}) ) - protocol_ignore_suites = protocol_ignore_list.get('suites', []) - protocol_ignore_cases = protocol_ignore_list.get('cases', []) - return suite in protocol_ignore_suites or case in protocol_ignore_cases + protocol_suites = protocol_ignore_list.get('suites', []) + protocol_cases = protocol_ignore_list.get('cases', []) + return suite in protocol_suites or case in protocol_cases