diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/XmlNamespace.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/XmlNamespace.java index 7b50141d4a93..84cad896fb02 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/XmlNamespace.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/XmlNamespace.java @@ -18,9 +18,16 @@ public class XmlNamespace { private String prefix; - private String uri; + public XmlNamespace() { + + } + + public XmlNamespace(String uri) { + this.uri = uri; + } + public String getPrefix() { return prefix; } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java index efb230313efb..d56469a58799 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java @@ -302,6 +302,11 @@ public String getEnumValueName(String enumValue) { // Special cases result = result.replace("textORcsv", "TEXT_OR_CSV"); + // leading digits, add a prefix + if (result.matches("^\\d.*")) { + result = "VALUE_" + result; + } + // Split into words result = String.join("_", splitOnWordBoundaries(result)); diff --git a/test/protocol-tests-core/pom.xml b/test/protocol-tests-core/pom.xml index ace915861fcf..f88274225739 100644 --- a/test/protocol-tests-core/pom.xml +++ b/test/protocol-tests-core/pom.xml @@ -137,6 +137,10 @@ com.fasterxml.jackson.core jackson-annotations + + com.fasterxml.jackson.dataformat + jackson-dataformat-cbor + diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/CborBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/CborBodyAssertion.java new file mode 100644 index 000000000000..f3d4e54c84e0 --- /dev/null +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/CborBodyAssertion.java @@ -0,0 +1,71 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocol.asserts.marshalling; + +import static org.junit.Assert.assertEquals; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.DoubleNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.cbor.CBORFactory; +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import java.util.Base64; + +/** + * Asserts on the body (expected to be CBOR) of the marshalled request. + */ +public class CborBodyAssertion extends MarshallingAssertion { + private static final ObjectMapper MAPPER = new ObjectMapper(new CBORFactory()); + + private final String cborEquals; + + public CborBodyAssertion(String cborEquals) { + this.cborEquals = cborEquals; + } + + @Override + protected void doAssert(LoggedRequest actual) throws Exception { + JsonNode expected = normalizeToDoubles(MAPPER.readTree(Base64.getDecoder().decode(cborEquals))); + JsonNode actualJson = normalizeToDoubles(MAPPER.readTree(actual.getBody())); + assertEquals(expected, actualJson); + } + + /** + * CBOR allows serializing floating point numbers to different sizes (eg, float16/32/64). + * However, in assertEquals float and double nodes will never be equal so we convert them + * all to doubles. + */ + private JsonNode normalizeToDoubles(JsonNode node) { + if (node.isFloat() || node.isDouble()) { + return DoubleNode.valueOf(node.doubleValue()); + } + if (node.isArray()) { + ArrayNode array = MAPPER.createArrayNode(); + for (JsonNode item : node) { + array.add(normalizeToDoubles(item)); + } + return array; + } + if (node.isObject()) { + ObjectNode obj = MAPPER.createObjectNode(); + node.fields().forEachRemaining(entry -> obj.set(entry.getKey(), normalizeToDoubles(entry.getValue()))); + return obj; + } + return node; + } +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/HeadersAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/HeadersAssertion.java index 07b3f7ec1ea6..a751e9829e6e 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/HeadersAssertion.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/HeadersAssertion.java @@ -21,6 +21,7 @@ import com.github.tomakehurst.wiremock.http.HttpHeaders; import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -32,6 +33,7 @@ public class HeadersAssertion extends MarshallingAssertion { private Map> contains; private List doesNotContain; + private List mustContain; public void setContains(Map> contains) { this.contains = contains; @@ -41,6 +43,10 @@ public void setDoesNotContain(List doesNotContain) { this.doesNotContain = doesNotContain; } + public void setMustContain(List mustContain) { + this.mustContain = mustContain; + } + @Override protected void doAssert(LoggedRequest actual) throws Exception { if (contains != null) { @@ -49,6 +55,9 @@ protected void doAssert(LoggedRequest actual) throws Exception { if (doesNotContain != null) { assertDoesNotContainHeaders(actual.getHeaders()); } + if (mustContain != null) { + assertMustContainHeaders(actual.getHeaders()); + } } private void assertHeadersContains(HttpHeaders actual) { @@ -56,6 +65,10 @@ private void assertHeadersContains(HttpHeaders actual) { assertTrue(String.format("Header '%s' was expected to be present. Actual headers: %s", expectedKey, actual), actual.getHeader(expectedKey).isPresent()); List actualValues = actual.getHeader(expectedKey).values(); + // the Java SDK adds charset to content-type. This is valid but not included in the protocol tests + if (expectedKey.equalsIgnoreCase("Content-Type") && actualValues.size() == 1) { + actualValues = Collections.singletonList(actualValues.get(0).replace("; charset=UTF-8", "")); + } assertEquals(expectedValues, actualValues); }); } @@ -66,4 +79,11 @@ private void assertDoesNotContainHeaders(HttpHeaders actual) { actual.getHeader(headerName).isPresent()); }); } + + private void assertMustContainHeaders(HttpHeaders actual) { + mustContain.forEach(headerName -> { + assertTrue(String.format("Header '%s' was expected to be present", headerName), + actual.getHeader(headerName).isPresent()); + }); + } } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/JsonBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/JsonBodyAssertion.java index 240e21f19192..5341879d9462 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/JsonBodyAssertion.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/JsonBodyAssertion.java @@ -19,6 +19,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.LongNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.tomakehurst.wiremock.verification.LoggedRequest; /** @@ -37,8 +41,39 @@ public JsonBodyAssertion(String jsonEquals) { @Override protected void doAssert(LoggedRequest actual) throws Exception { JsonNode expected = MAPPER.readTree(jsonEquals); - JsonNode actualJson = MAPPER.readTree(actual.getBodyAsString()); + JsonNode actualJson = convertWholeNumberDoubleToLong(MAPPER.readTree(actual.getBodyAsString())); assertEquals(expected, actualJson); } + /** + * We serialize some numbers (in particular epoch timestamps) as doubles such as 123.000. + * In protocol tests, these values are parsed as longs. This conversion insures that + * 123.000 will equal 123. + */ + public static JsonNode convertWholeNumberDoubleToLong(JsonNode node) { + if (node.isDouble()) { + double value = node.doubleValue(); + if (value % 1 == 0) { + if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) { + return new IntNode((int) value); + } + return new LongNode((long) value); + } + } + if (node.isObject()) { + ObjectNode obj = (ObjectNode) node; + ObjectNode result = obj.objectNode(); + obj.fieldNames().forEachRemaining(field -> result.set(field, convertWholeNumberDoubleToLong(obj.get(field)))); + return result; + } + if (node.isArray()) { + ArrayNode array = (ArrayNode) node; + ArrayNode result = array.arrayNode(); + for (JsonNode item : array) { + result.add(convertWholeNumberDoubleToLong(item)); + } + return result; + } + return node; + } } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryBodyAssertion.java new file mode 100644 index 000000000000..25ffd4ece8a9 --- /dev/null +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryBodyAssertion.java @@ -0,0 +1,79 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocol.asserts.marshalling; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static software.amazon.awssdk.protocol.asserts.marshalling.QueryUtils.parseQueryParams; +import static software.amazon.awssdk.protocol.asserts.marshalling.QueryUtils.parseQueryParamsFromBody; + +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class QueryBodyAssertion extends MarshallingAssertion { + private final String queryEquals; + + public QueryBodyAssertion(String queryEquals) { + this.queryEquals = queryEquals; + } + + @Override + protected void doAssert(LoggedRequest actual) throws Exception { + Map> expectedParams = parseQueryParamsFromBody(queryEquals); + try { + Map> actualParams = parseQueryParams(actual); + doAssert(expectedParams, actualParams); + } catch (AssertionError error) { + // We may send the query params in the body if there is no other content. Try + // decoding body as params and rerun the assertions. + Map> actualParams = parseQueryParamsFromBody( + actual.getBodyAsString()); + doAssert(expectedParams, actualParams); + } + } + + private void doAssert(Map> expectedParams, Map> actualParams) { + assertThat(actualParams.keySet(), equalTo(expectedParams.keySet())); + expectedParams.forEach((key, value) -> assertParamsEqual(actualParams.get(key), value)); + } + + private void assertParamsEqual(List actual, List expected) { + if (expected.stream().allMatch(QueryBodyAssertion::isNumeric)) { + assertThat( + actual.stream().map(Double::parseDouble).collect(Collectors.toList()), + containsInAnyOrder(expected.stream().map(Double::parseDouble).toArray())); + } else { + assertThat(actual, containsInAnyOrder(expected.toArray())); + } + } + + public static boolean isNumeric(String str) { + if (str == null || str.isEmpty()) { + return false; + } + try { + Double.parseDouble(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryParamsAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryParamsAssertion.java index abed2aefda25..c7ec71861692 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryParamsAssertion.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryParamsAssertion.java @@ -15,22 +15,18 @@ package software.amazon.awssdk.protocol.asserts.marshalling; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.collection.IsMapContaining.hasKey; -import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertNotNull; +import static software.amazon.awssdk.protocol.asserts.marshalling.QueryUtils.parseQueryParams; +import static software.amazon.awssdk.protocol.asserts.marshalling.QueryUtils.parseQueryParamsFromBody; import com.github.tomakehurst.wiremock.verification.LoggedRequest; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; -import software.amazon.awssdk.utils.StringUtils; /** * Asserts on the query parameters of the marshalled request. @@ -40,6 +36,7 @@ public class QueryParamsAssertion extends MarshallingAssertion { private Map> contains; private Map> containsOnly; private List doesNotContain; + private List mustContain; public void setContains(Map> contains) { this.contains = contains; @@ -53,6 +50,10 @@ public void setDoesNotContain(List doesNotContain) { this.doesNotContain = doesNotContain; } + public void setMustContain(List mustContain) { + this.mustContain = mustContain; + } + @Override protected void doAssert(LoggedRequest actual) throws Exception { try { @@ -68,6 +69,8 @@ protected void doAssert(LoggedRequest actual) throws Exception { } private void doAssert(Map> actualParams) { + assertNotNull(actualParams); + if (contains != null) { assertContains(actualParams); } @@ -79,44 +82,29 @@ private void doAssert(Map> actualParams) { if (containsOnly != null) { assertContainsOnly(actualParams); } - } - private Map> parseQueryParamsFromBody(String body) { - return toQueryParamMap(URLEncodedUtils.parse(body, StandardCharsets.UTF_8)); - } - - private Map> parseQueryParams(LoggedRequest actual) { - return toQueryParamMap(parseNameValuePairsFromQuery(actual)); - } - - /** - * Group the list of {@link NameValuePair} by parameter name. - */ - private Map> toQueryParamMap(List queryParams) { - return queryParams.stream().collect(Collectors.groupingBy(NameValuePair::getName, Collectors - .mapping(NameValuePair::getValue, Collectors.toList()))); - } - - private List parseNameValuePairsFromQuery(LoggedRequest actual) { - String queryParams = URI.create(actual.getUrl()).getQuery(); - if (StringUtils.isEmpty(queryParams)) { - return Collections.emptyList(); + if (mustContain != null) { + assertMustContain(actualParams); } - return URLEncodedUtils.parse(queryParams, StandardCharsets.UTF_8); } + private void assertContains(Map> actualParams) { - contains.entrySet().forEach(e -> assertThat(actualParams.get(e.getKey()), containsInAnyOrder(e.getValue().toArray()))); + contains.forEach((key, value) -> assertThat(actualParams.get(key), containsInAnyOrder(value.toArray()))); } private void assertDoesNotContain(Map> actualParams) { doesNotContain.forEach(key -> assertThat(actualParams, not(hasKey(key)))); } + private void assertMustContain(Map> actualParams) { + doesNotContain.forEach(key -> assertThat(actualParams, hasKey(key))); + } + private void assertContainsOnly(Map> actualParams) { assertThat(actualParams.keySet(), equalTo(containsOnly.keySet())); - containsOnly.entrySet().forEach(e -> assertThat( - actualParams.get(e.getKey()), containsInAnyOrder(e.getValue().toArray()) + containsOnly.forEach((key, value) -> assertThat( + actualParams.get(key), containsInAnyOrder(value.toArray()) )); } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryUtils.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryUtils.java new file mode 100644 index 000000000000..7a5cc51c5724 --- /dev/null +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/QueryUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocol.asserts.marshalling; + +import com.github.tomakehurst.wiremock.verification.LoggedRequest; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import software.amazon.awssdk.utils.StringUtils; + +public final class QueryUtils { + private QueryUtils() { + } + + public static Map> parseQueryParamsFromBody(String body) { + return toQueryParamMap(URLEncodedUtils.parse(body, StandardCharsets.UTF_8)); + } + + public static Map> parseQueryParams(LoggedRequest actual) { + return toQueryParamMap(parseNameValuePairsFromQuery(actual)); + } + + /** + * Group the list of {@link NameValuePair} by parameter name. + */ + private static Map> toQueryParamMap(List queryParams) { + return queryParams.stream().collect(Collectors.groupingBy(NameValuePair::getName, Collectors + .mapping(NameValuePair::getValue, Collectors.toList()))); + } + + private static List parseNameValuePairsFromQuery(LoggedRequest actual) { + String queryParams = URI.create(actual.getUrl()).getQuery(); + if (StringUtils.isEmpty(queryParams)) { + return Collections.emptyList(); + } + return URLEncodedUtils.parse(queryParams, StandardCharsets.UTF_8); + } +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java index 1a1301c7bc55..769d88047d1a 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/RequestBodyAssertion.java @@ -33,6 +33,14 @@ public void setXmlEquals(String xmlEquals) { addAssertion(new XmlBodyAssertion(xmlEquals)); } + public void setQueryEquals(String queryEquals) { + addAssertion(new QueryBodyAssertion(queryEquals)); + } + + public void setCborEquals(String cborEquals) { + addAssertion(new CborBodyAssertion(cborEquals)); + } + public void setEquals(String equals) { addAssertion(new RawBodyAssertion(equals)); } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/ResolvedHostAssertion.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/ResolvedHostAssertion.java new file mode 100644 index 000000000000..65049e4f8b94 --- /dev/null +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/ResolvedHostAssertion.java @@ -0,0 +1,36 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocol.asserts.marshalling; + +import static org.junit.Assert.assertEquals; + +import com.github.tomakehurst.wiremock.verification.LoggedRequest; + +/** + * Asserts the resolved host of a marshalled request. + */ +public class ResolvedHostAssertion extends MarshallingAssertion { + private final String expectedHost; + + public ResolvedHostAssertion(String host) { + this.expectedHost = host; + } + + @Override + protected void doAssert(LoggedRequest actual) throws Exception { + assertEquals(expectedHost, actual.getHost()); + } +} diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/SerializedAs.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/SerializedAs.java index e34d9979f7e7..ae048bc48b40 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/SerializedAs.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/SerializedAs.java @@ -37,6 +37,10 @@ public void setUri(String uri) { addAssertion(new UriAssertion(uri)); } + public void setResolvedHost(String resolvedHost) { + addAssertion(new ResolvedHostAssertion(resolvedHost)); + } + @JsonDeserialize(using = SdkHttpMethodDeserializer.class) public void setMethod(SdkHttpMethod method) { addAssertion(new HttpMethodAssertion(method)); diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Given.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Given.java index 325e1c48f0e6..051dd81ec129 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Given.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Given.java @@ -24,6 +24,8 @@ public class Given { private GivenResponse response; + private String host; + public JsonNode getInput() { return input; } @@ -39,4 +41,12 @@ public GivenResponse getResponse() { public void setResponse(GivenResponse response) { this.response = response; } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/TestCase.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/TestCase.java index c7f9127552c1..7b2d5d00b6c8 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/TestCase.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/TestCase.java @@ -66,7 +66,11 @@ public void setThen(Then then) { @Override public String toString() { - return id; + if (id != null) { + return id + ": " + description; + } else { + return description; + } } } diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Then.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Then.java index ce24a5a47de0..a26bfdd76bcc 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Then.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/model/Then.java @@ -56,7 +56,6 @@ public UnmarshallingAssertion getUnmarshallingAssertion() { } /** - * * @return The assertion object to use for error unmarshalling tests */ public UnmarshallingAssertion getErrorUnmarshallingAssertion() { @@ -64,8 +63,7 @@ public UnmarshallingAssertion getErrorUnmarshallingAssertion() { } /** - * - * @return The errorCode String to use for error unmarshalling tests + * @return The error code to assert. */ public String getErrorCode() { return errorCode; diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ClientReflector.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ClientReflector.java index 4ec4433087c3..b465f6cb7c2e 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ClientReflector.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ClientReflector.java @@ -65,7 +65,7 @@ private Class getInterfaceClass() { public Object invokeMethod(TestCase testCase, Object... params) throws Exception { String operationName = testCase.getWhen().getOperationName(); Method operationMethod = getOperationMethod(operationName, params); - return operationMethod.invoke(client, params); + return operationMethod.invoke(getRequestClient(testCase), params); } /** @@ -80,7 +80,15 @@ public Object invokeStreamingMethod(TestCase testCase, ResponseTransformer responseHandler) throws Exception { String operationName = testCase.getWhen().getOperationName(); Method operationMethod = getOperationMethod(operationName, requestObject.getClass(), ResponseTransformer.class); - return operationMethod.invoke(client, requestObject, responseHandler); + return operationMethod.invoke(getRequestClient(testCase), requestObject, responseHandler); + } + + private Object getRequestClient(TestCase testCase) { + Object requestClient = this.client; + if (testCase.getGiven().getHost() != null) { + requestClient = createClientWithEndpoint("https://" + testCase.getGiven().getHost()); + } + return requestClient; } @Override @@ -94,13 +102,20 @@ public void close() { * Create the sync client to use in the tests. */ private Object createClient() { + return createClientWithEndpoint(getEndpoint()); + } + + /** + * Create the sync client to use in the tests. + */ + private Object createClientWithEndpoint(String endpoint) { try { // Reflectively create a builder, configure it, and then create the client. Object untypedBuilder = interfaceClass.getMethod("builder").invoke(null); AwsClientBuilder builder = (AwsClientBuilder) untypedBuilder; return builder.credentialsProvider(getMockCredentials()) .region(Region.US_EAST_1) - .endpointOverride(URI.create(getEndpoint())) + .endpointOverride(URI.create(endpoint)) .build(); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java index c39a12ebf0e8..a0bd6c18e78f 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/reflect/ShapeModelReflector.java @@ -41,6 +41,7 @@ */ public class ShapeModelReflector { + public static final long EPOCH_SECONDS_2050 = 2524680000L; private final IntermediateModel model; private final String shapeName; private final JsonNode input; @@ -250,7 +251,7 @@ private Object getSimpleMemberValue(JsonNode currentNode, MemberModel memberMode case "Double": return currentNode.asDouble(); case "Instant": - return Instant.ofEpochMilli(currentNode.asLong()); + return getInstant(currentNode); case "SdkBytes": return SdkBytes.fromUtf8String(currentNode.asText()); case "Float": @@ -265,6 +266,26 @@ private Object getSimpleMemberValue(JsonNode currentNode, MemberModel memberMode } } + private static Instant getInstant(JsonNode currentNode) { + if (currentNode.isFloatingPointNumber()) { + double fractionalEpoch = currentNode.asDouble(); + long seconds = (long) fractionalEpoch; + long nanos = (long) ((fractionalEpoch - seconds) * 1_000_000_000L); + //truncate to ms + return Instant.ofEpochSecond(seconds, (nanos / 1_000_000) * 1_000_000); + } else { + // attempt to infer if this value should be epoch seconds or milliseconds + long epoch = currentNode.asLong(); + // smithy protocol tests occasionally uses small epoch seconds in tests (<10000) + // interpret those as seconds. Additionally, anything that would be past 2050 as seconds, + // consider epoch ms. + if (epoch < 10000L || epoch > EPOCH_SECONDS_2050) { + return Instant.ofEpochMilli(epoch); + } + return Instant.ofEpochSecond(currentNode.asLong()); + } + } + private Character asCharacter(JsonNode currentNode) { String text = currentNode.asText(); if (text != null && text.length() > 1) { diff --git a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/MarshallingTestRunner.java b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/MarshallingTestRunner.java index 6f01690e5e10..32872aa44800 100644 --- a/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/MarshallingTestRunner.java +++ b/test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/runners/MarshallingTestRunner.java @@ -15,6 +15,7 @@ package software.amazon.awssdk.protocol.runners; + import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.any; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; @@ -26,8 +27,13 @@ import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.verification.LoggedRequest; import java.util.List; +import software.amazon.awssdk.awscore.AwsRequest; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.core.interceptor.Context; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.protocol.model.TestCase; import software.amazon.awssdk.protocol.reflect.ClientReflector; import software.amazon.awssdk.protocol.reflect.ShapeModelReflector; @@ -40,33 +46,28 @@ class MarshallingTestRunner { private final IntermediateModel model; private final ClientReflector clientReflector; + private final LocalhostOnlyForWiremockInterceptor localhostOnlyForWiremockInterceptor; MarshallingTestRunner(IntermediateModel model, ClientReflector clientReflector) { this.model = model; this.clientReflector = clientReflector; - } - - /** - * @return LoggedRequest that wire mock captured. - */ - private static LoggedRequest getLoggedRequest() { - List requests = WireMockUtils.findAllLoggedRequests(); - assertEquals(1, requests.size()); - return requests.get(0); + this.localhostOnlyForWiremockInterceptor = new LocalhostOnlyForWiremockInterceptor(); } void runTest(TestCase testCase) throws Exception { resetWireMock(); ShapeModelReflector shapeModelReflector = createShapeModelReflector(testCase); + AwsRequest request = createRequest(shapeModelReflector); + if (!model.getShapes().get(testCase.getWhen().getOperationName() + "Request").isHasStreamingMember()) { - clientReflector.invokeMethod(testCase, shapeModelReflector.createShapeObject()); + clientReflector.invokeMethod(testCase, request); } else { clientReflector.invokeMethod(testCase, - shapeModelReflector.createShapeObject(), + request, RequestBody.fromString(shapeModelReflector.getStreamingMemberValue())); } - LoggedRequest actualRequest = getLoggedRequest(); - testCase.getThen().getMarshallingAssertion().assertMatches(actualRequest); + testCase.getThen().getMarshallingAssertion() + .assertMatches(localhostOnlyForWiremockInterceptor.getLoggedRequestWithOriginalHost()); } /** @@ -83,6 +84,16 @@ private void resetWireMock() { stubFor(any(urlMatching(".*")).willReturn(responseDefBuilder)); } + private AwsRequest createRequest(ShapeModelReflector shapeModelReflector) { + return ((AwsRequest) shapeModelReflector.createShapeObject()) + .toBuilder() + .overrideConfiguration(requestConfiguration -> requestConfiguration + .addPlugin(config -> { + config.overrideConfiguration(c -> c.addExecutionInterceptor(localhostOnlyForWiremockInterceptor)); + })) + .build(); + } + private ShapeModelReflector createShapeModelReflector(TestCase testCase) { String operationName = testCase.getWhen().getOperationName(); String requestClassName = getOperationRequestClassName(operationName); @@ -97,4 +108,49 @@ private String getOperationRequestClassName(String operationName) { return operationName + "Request"; } + /** + * Wiremock requires that requests use "localhost" as the host - any prefixes such as "foo.localhost" will + * result in a DNS lookup that will fail. This interceptor modifies the request to ensure this and captures + * the original host. + */ + private static final class LocalhostOnlyForWiremockInterceptor implements ExecutionInterceptor { + private String originalHost; + private String originalProtocol; + private int originalPort; + + @Override + public SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes) { + originalHost = context.httpRequest().host(); + originalProtocol = context.httpRequest().protocol(); + originalPort = context.httpRequest().port(); + + return context.httpRequest().toBuilder() + .host("localhost") + .port(WireMockUtils.port()) + .protocol("http") + .build(); + } + + /** + * @return LoggedRequest that wire mock captured modified with the original host captured by this + * interceptor. + */ + public LoggedRequest getLoggedRequestWithOriginalHost() { + List requests = WireMockUtils.findAllLoggedRequests(); + assertEquals(1, requests.size()); + LoggedRequest loggedRequest = requests.get(0); + return new LoggedRequest( + loggedRequest.getUrl(), + originalProtocol + "://" + originalHost + ":" + originalPort, + loggedRequest.getMethod(), + loggedRequest.getClientIp(), + loggedRequest.getHeaders(), + loggedRequest.getCookies(), + loggedRequest.isBrowserProxyRequest(), + loggedRequest.getLoggedDate(), + loggedRequest.getBody(), + loggedRequest.getParts() + ); + } + } } diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-input.json new file mode 100644 index 000000000000..1e55c01d5b03 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-input.json @@ -0,0 +1,617 @@ +[ + { + "id": "AwsJson10EmptyInputAndEmptyOutput", + "description": "Clients must always send an empty object if input is modeled.", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "EmptyInputAndEmptyOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.EmptyInputAndEmptyOutput", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10EndpointTrait", + "description": "Operations can prepend to the given host if they define the\nendpoint trait.", + "given": { + "input": {}, + "host": "example.com" + }, + "when": { + "action": "marshall", + "operation": "EndpointOperation" + }, + "then": { + "serializedAs": { + "method": "POST", + "body": { + "jsonEquals": "{}" + }, + "uri": "/", + "resolvedHost": "foo.example.com" + } + } + }, + { + "id": "AwsJson10EndpointTraitWithHostLabel", + "description": "Operations can prepend to the given host if they define the\nendpoint trait, and can use the host label trait to define\nfurther customization based on user input.", + "given": { + "input": { + "label": "bar" + }, + "host": "example.com" + }, + "when": { + "action": "marshall", + "operation": "EndpointWithHostLabelOperation" + }, + "then": { + "serializedAs": { + "method": "POST", + "body": { + "jsonEquals": "{\"label\": \"bar\"}" + }, + "uri": "/", + "resolvedHost": "foo.bar.example.com" + } + } + }, + { + "id": "AwsJson10HostWithPath", + "description": "Custom endpoints supplied by users can have paths", + "given": { + "input": {}, + "host": "example.com/custom" + }, + "when": { + "action": "marshall", + "operation": "HostWithPathOperation" + }, + "then": { + "serializedAs": { + "method": "POST", + "body": { + "jsonEquals": "{}" + }, + "uri": "/custom/" + } + } + }, + { + "id": "AwsJson10SerializeStringUnionValue", + "description": "Serializes a string union value", + "given": { + "input": { + "contents": { + "stringValue": "foo" + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"stringValue\": \"foo\"\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeBooleanUnionValue", + "description": "Serializes a boolean union value", + "given": { + "input": { + "contents": { + "booleanValue": true + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"booleanValue\": true\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeNumberUnionValue", + "description": "Serializes a number union value", + "given": { + "input": { + "contents": { + "numberValue": 1 + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"numberValue\": 1\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeBlobUnionValue", + "description": "Serializes a blob union value", + "given": { + "input": { + "contents": { + "blobValue": "foo" + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"blobValue\": \"Zm9v\"\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeTimestampUnionValue", + "description": "Serializes a timestamp union value", + "given": { + "input": { + "contents": { + "timestampValue": 1398796238 + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"timestampValue\": 1398796238\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeEnumUnionValue", + "description": "Serializes an enum union value", + "given": { + "input": { + "contents": { + "enumValue": "Foo" + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"enumValue\": \"Foo\"\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeIntEnumUnionValue", + "description": "Serializes an intEnum union value", + "given": { + "input": { + "contents": { + "intEnumValue": 1 + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"intEnumValue\": 1\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeListUnionValue", + "description": "Serializes a list union value", + "given": { + "input": { + "contents": { + "listValue": [ + "foo", + "bar" + ] + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"listValue\": [\"foo\", \"bar\"]\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeMapUnionValue", + "description": "Serializes a map union value", + "given": { + "input": { + "contents": { + "mapValue": { + "foo": "bar", + "spam": "eggs" + } + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"mapValue\": {\n \"foo\": \"bar\",\n \"spam\": \"eggs\"\n }\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SerializeStructureUnionValue", + "description": "Serializes a structure union value", + "given": { + "input": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + } + }, + "when": { + "action": "marshall", + "operation": "JsonUnions" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.JsonUnions", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"contents\": {\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10MustAlwaysSendEmptyJsonPayload", + "description": "Clients must always send an empty JSON object payload for\noperations with no input (that is, `{}`). While AWS service\nimplementations support requests with no payload or requests\nthat send `{}`, always sending `{}` from the client is\npreferred for forward compatibility in case input is ever\nadded to an operation.", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.NoInputAndNoOutput", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10NoInputAndOutput", + "description": "A client should always send and empty JSON object payload.", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "NoInputAndOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.NoInputAndOutput", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{}" + }, + "uri": "/" + } + } + }, + { + "id": "SDKAppliedContentEncoding_awsJson1_0", + "description": "Compression algorithm encoding is appended to the Content-Encoding header.", + "given": { + "input": { + "data": "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\n" + } + }, + "when": { + "action": "marshall", + "operation": "PutWithContentEncoding" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Encoding": "gzip" + } + }, + "uri": "/" + } + } + }, + { + "id": "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", + "description": "Compression algorithm encoding is appended to the Content-Encoding header, and the\nuser-provided content-encoding is NOT in the Content-Encoding header since HTTP binding\ntraits are ignored in the awsJson1_0 protocol.\n", + "given": { + "input": { + "encoding": "custom", + "data": "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\n" + } + }, + "when": { + "action": "marshall", + "operation": "PutWithContentEncoding" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Encoding": "gzip" + } + }, + "uri": "/" + } + } + }, + { + "id": "NonQueryCompatibleAwsJson10ForbidsQueryModeHeader", + "description": "The query mode header MUST NOT be set on non-query-compatible services.", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "QueryIncompatibleOperation" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.QueryIncompatibleOperation", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SupportsNaNFloatInputs", + "description": "Supports handling NaN float values.", + "given": { + "input": { + "floatValue": "NaN", + "doubleValue": "NaN" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.SimpleScalarProperties", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"floatValue\": \"NaN\",\n \"doubleValue\": \"NaN\"\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SupportsInfinityFloatInputs", + "description": "Supports handling Infinity float values.", + "given": { + "input": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.SimpleScalarProperties", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"floatValue\": \"Infinity\",\n \"doubleValue\": \"Infinity\"\n}" + }, + "uri": "/" + } + } + }, + { + "id": "AwsJson10SupportsNegativeInfinityFloatInputs", + "description": "Supports handling -Infinity float values.", + "given": { + "input": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "X-Amz-Target": "JsonRpc10.SimpleScalarProperties", + "Content-Type": "application/x-amz-json-1.0" + } + }, + "body": { + "jsonEquals": "{\n \"floatValue\": \"-Infinity\",\n \"doubleValue\": \"-Infinity\"\n}" + }, + "uri": "/" + } + } + } +] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-output.json new file mode 100644 index 000000000000..1a64ba1a8793 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/json10-output.json @@ -0,0 +1,727 @@ +[ + { + "id": "AwsJson10EmptyInputAndEmptyOutputSendJsonObject", + "description": "A service will always return a JSON object for operations with modeled output.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + }, + "when": { + "action": "unmarshall", + "operation": "EmptyInputAndEmptyOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10InvalidGreetingError", + "description": "Parses simple JSON errors", + "given": { + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#InvalidGreeting\",\n \"Message\": \"Hi\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "InvalidGreeting" + }, + "then": { + "deserializedAs": { + "Message": "Hi" + } + } + }, + { + "id": "AwsJson10ComplexError", + "description": "Parses a complex error with no message member", + "given": { + "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}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "ComplexError" + }, + "then": { + "deserializedAs": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + } + } + }, + { + "id": "AwsJson10EmptyComplexError", + "description": "Parses a complex error with an empty body", + "given": { + "response": { + "status_code": 400, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#ComplexError\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "ComplexError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingXAmznErrorType", + "description": "Serializes the X-Amzn-ErrorType header. For an example service, see Amazon EKS.", + "given": { + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError" + } + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingXAmznErrorTypeWithUri", + "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.", + "given": { + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingXAmznErrorTypeWithUriAndNamespace", + "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.", + "given": { + "response": { + "status_code": 500, + "headers": { + "X-Amzn-Errortype": "aws.protocoltests.json10#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/" + } + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingCode", + "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.", + "given": { + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"code\": \"FooError\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingCodeAndNamespace", + "description": "Some services serialize errors using code, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "given": { + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"code\": \"aws.protocoltests.json10#FooError\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorUsingCodeUriAndNamespace", + "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.", + "given": { + "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}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorWithDunderType", + "description": "Some services serialize errors using __type.", + "given": { + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"FooError\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorWithDunderTypeAndNamespace", + "description": "Some services serialize errors using __type, and it might contain a namespace. Clients should just take the last part of the string after '#'.", + "given": { + "response": { + "status_code": 500, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"__type\": \"aws.protocoltests.json10#FooError\"\n}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10FooErrorWithDunderTypeUriAndNamespace", + "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.", + "given": { + "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}" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "FooError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10DeserializeStringUnionValue", + "description": "Deserializes a string union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"stringValue\": \"foo\"\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "stringValue": "foo" + } + } + } + }, + { + "id": "AwsJson10DeserializeBooleanUnionValue", + "description": "Deserializes a boolean union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"booleanValue\": true\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "booleanValue": true + } + } + } + }, + { + "id": "AwsJson10DeserializeNumberUnionValue", + "description": "Deserializes a number union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"numberValue\": 1\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "numberValue": 1 + } + } + } + }, + { + "id": "AwsJson10DeserializeBlobUnionValue", + "description": "Deserializes a blob union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"blobValue\": \"Zm9v\"\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "blobValue": "foo" + } + } + } + }, + { + "id": "AwsJson10DeserializeTimestampUnionValue", + "description": "Deserializes a timestamp union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"timestampValue\": 1398796238\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "timestampValue": 1398796238 + } + } + } + }, + { + "id": "AwsJson10DeserializeEnumUnionValue", + "description": "Deserializes an enum union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"enumValue\": \"Foo\"\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "enumValue": "Foo" + } + } + } + }, + { + "id": "AwsJson10DeserializeIntEnumUnionValue", + "description": "Deserializes an intEnum union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"intEnumValue\": 1\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "intEnumValue": 1 + } + } + } + }, + { + "id": "AwsJson10DeserializeListUnionValue", + "description": "Deserializes a list union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"listValue\": [\"foo\", \"bar\"]\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "listValue": [ + "foo", + "bar" + ] + } + } + } + }, + { + "id": "AwsJson10DeserializeMapUnionValue", + "description": "Deserializes a map union value", + "given": { + "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}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "mapValue": { + "foo": "bar", + "spam": "eggs" + } + } + } + } + }, + { + "id": "AwsJson10DeserializeStructureUnionValue", + "description": "Deserializes a structure union value", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"contents\": {\n \"structureValue\": {\n \"hi\": \"hello\"\n }\n }\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + } + } + }, + { + "id": "AwsJson10DeserializeIgnoreType", + "description": "Ignores an unrecognized __type property", + "given": { + "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}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + } + } + }, + { + "id": "AwsJson10DeserializeAllowNulls", + "description": "Allows for `: null` to be set for all unset fields", + "given": { + "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}" + } + }, + "when": { + "action": "unmarshall", + "operation": "JsonUnions" + }, + "then": { + "deserializedAs": { + "contents": { + "structureValue": { + "hi": "hello" + } + } + } + } + }, + { + "id": "AwsJson10HandlesEmptyOutputShape", + "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.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10HandlesUnexpectedJsonOutput", + "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.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"foo\": true\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10ServiceRespondsWithNoPayload", + "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.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "" + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10NoInputAndOutput", + "description": "Empty output always serializes an empty object payload.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{}" + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "AwsJson10SupportsNaNFloatInputs", + "description": "Supports handling NaN float values.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"NaN\",\n \"doubleValue\": \"NaN\"\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "floatValue": "NaN", + "doubleValue": "NaN" + } + } + }, + { + "id": "AwsJson10SupportsInfinityFloatInputs", + "description": "Supports handling Infinity float values.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"Infinity\",\n \"doubleValue\": \"Infinity\"\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + } + } + }, + { + "id": "AwsJson10SupportsNegativeInfinityFloatInputs", + "description": "Supports handling -Infinity float values.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "application/x-amz-json-1.0" + }, + "body": "{\n \"floatValue\": \"-Infinity\",\n \"doubleValue\": \"-Infinity\"\n}" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarProperties" + }, + "then": { + "deserializedAs": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + } + } + } +] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-input.json index fc9683dcd37b..01d47d54d6f0 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-input.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-input.json @@ -1,466 +1,1109 @@ [ { - "description": "Asserts Action (operation) and Version are in query params", + "id": "QueryEmptyInputAndEmptyOutput", + "description": "Empty input serializes no extra query params", "given": { - "input": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "EmptyInputAndEmptyOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + } + }, + "body": { + "queryEquals": "Action=EmptyInputAndEmptyOutput&Version=2020-01-08" + }, + "uri": "/" } + } + }, + { + "id": "AwsQueryEndpointTrait", + "description": "Operations can prepend to the given host if they define the\nendpoint trait.", + "given": { + "input": {}, + "host": "example.com" }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "EndpointOperation" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "Action": "AllTypes", - "Version": "2016-03-11" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=EndpointOperation&Version=2020-01-08" + }, + "uri": "/", + "resolvedHost": "foo.example.com" } } }, { - "description": "Streaming payload member is marshalled correctly", + "id": "AwsQueryEndpointTraitWithHostLabel", + "description": "Operations can prepend to the given host if they define the\nendpoint trait, and can use the host label trait to define\nfurther customization based on user input.", "given": { "input": { - "StreamingMember": "contents" - } + "label": "bar" + }, + "host": "example.com" }, "when": { "action": "marshall", - "operation": "StreamingInputOperation" + "operation": "EndpointWithHostLabelOperation" }, "then": { "serializedAs": { + "method": "POST", "headers": { "contains": { - "Content-Length": "8" + "Content-Type": "application/x-www-form-urlencoded" } }, "body": { - "equals": "contents" - } + "queryEquals": "Action=EndpointWithHostLabelOperation&Version=2020-01-08&label=bar" + }, + "uri": "/", + "resolvedHost": "foo.bar.example.com" } } }, { - "description": "Scalar Members are marshalled correctly into the query params", + "id": "NestedStructures", + "description": "Serializes nested structures using dots", "given": { "input": { - "stringMember": "val1", - "integerMember": 50, - "floatMember": 1.234, - "doubleMember": 5.678, - "longMember": 100, - "shortMember": 4 + "Nested": { + "StringArg": "foo", + "OtherArg": true, + "RecursiveArg": { + "StringArg": "baz" + } + } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "NestedStructures" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "stringMember": "val1", - "integerMember": 50, - "floatMember": 1.234, - "doubleMember": 5.678, - "longMember": 100, - "shortMember": 4 + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=NestedStructures&Version=2020-01-08&Nested.StringArg=foo&Nested.OtherArg=true&Nested.RecursiveArg.StringArg=baz" + }, + "uri": "/" + } + } + }, + { + "id": "QueryNoInputAndNoOutput", + "description": "No input serializes no additional query params", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=NoInputAndNoOutput&Version=2020-01-08" + }, + "uri": "/" + } + } + }, + { + "id": "QueryNoInputAndOutput", + "description": "No input serializes no payload", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "NoInputAndOutput" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + } + }, + "body": { + "queryEquals": "Action=NoInputAndOutput&Version=2020-01-08" + }, + "uri": "/" } } }, { - "description": "Input with true boolean member is marshalled correctly into the query params", + "id": "SDKAppliedContentEncoding_awsQuery", + "description": "Compression algorithm encoding is appended to the Content-Encoding header.", "given": { "input": { - "booleanMember": true + "data": "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\n" } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "PutWithContentEncoding" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "booleanMember": "true" + "Content-Encoding": "gzip" } - } + }, + "uri": "/" } } }, { - "description": "Input with false boolean member is marshalled correctly into the query params", + "id": "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", + "description": "Compression algorithm encoding is appended to the Content-Encoding header, and the\nuser-provided content-encoding is NOT in the Content-Encoding header since HTTP binding\ntraits are ignored in the awsQuery protocol.\n", "given": { "input": { - "booleanMember": false + "encoding": "custom", + "data": "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\n" } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "PutWithContentEncoding" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "booleanMember": "false" + "Content-Encoding": "gzip" } - } + }, + "uri": "/" + } + } + }, + { + "id": "QueryProtocolIdempotencyTokenAutoFill", + "description": "Automatically adds idempotency token when not set", + "given": { + "input": {} + }, + "when": { + "action": "marshall", + "operation": "QueryIdempotencyTokenAutoFill" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=QueryIdempotencyTokenAutoFill&Version=2020-01-08&token=00000000-0000-4000-8000-000000000000" + }, + "uri": "/" } } }, { - "description": "A simple struct is marshalled correctly into the query params", + "id": "QueryProtocolIdempotencyTokenAutoFillIsSet", + "description": "Uses the given idempotency token as-is", "given": { "input": { - "simpleStructMember": { - "StringMember": "foo" - } + "token": "00000000-0000-4000-8000-000000000123" } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryIdempotencyTokenAutoFill" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "simpleStructMember.StringMember": "foo" - } - } + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=QueryIdempotencyTokenAutoFill&Version=2020-01-08&token=00000000-0000-4000-8000-000000000123" + }, + "uri": "/" } } }, { - "description": "A list of strings is marshalled correctly into the query params", + "id": "QueryLists", + "description": "Serializes query lists", "given": { "input": { - "simpleList": [ + "ListArg": [ "foo", "bar", "baz" + ], + "ComplexListArg": [ + { + "hi": "hello" + }, + { + "hi": "hola" + } ] } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "simpleList.member.1": "foo", - "simpleList.member.2": "bar", - "simpleList.member.3": "baz" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&ListArg.member.1=foo&ListArg.member.2=bar&ListArg.member.3=baz&ComplexListArg.member.1.hi=hello&ComplexListArg.member.2.hi=hola" + }, + "uri": "/" } } }, { - "description": "An empty list is marshalled as an empty string in the query params", + "id": "EmptyQueryLists", + "description": "Serializes empty query lists", "given": { "input": { - "simpleList": [] + "ListArg": [] } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "simpleList": "" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&ListArg=" + }, + "uri": "/" } } }, { - "description": "A flattened list of strings is marshalled correctly into the query params", + "id": "FlattenedQueryLists", + "description": "Flattens query lists by repeating the member name and removing the member element", "given": { "input": { - "FlattenedListOfStrings": [ - "foo", - "bar", - "baz" + "FlattenedListArg": [ + "A", + "B" ] } }, "when": { "action": "marshall", - "operation": "QueryTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "FlattenedListOfStrings.1": "foo", - "FlattenedListOfStrings.2": "bar", - "FlattenedListOfStrings.3": "baz" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&FlattenedListArg.1=A&FlattenedListArg.2=B" + }, + "uri": "/" } } }, { - "description": "A flattened list of strings with non default location name is marshalled correctly", + "id": "QueryListArgWithXmlNameMember", + "description": "Changes the member of lists using xmlName trait", "given": { "input": { - "FlattenedListWithLocation": [ - "foo", - "bar", - "baz" + "ListArgWithXmlNameMember": [ + "A", + "B" ] } }, "when": { "action": "marshall", - "operation": "QueryTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "item.1": "foo", - "item.2": "bar", - "item.3": "baz" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&ListArgWithXmlNameMember.item.1=A&ListArgWithXmlNameMember.item.2=B" + }, + "uri": "/" } } }, { - "description": "A non flattened list with non default location name is marshalled correctly", + "id": "QueryFlattenedListArgWithXmlName", + "description": "Changes the name of flattened lists using xmlName trait on the structure member", "given": { "input": { - "NonFlattenedListWithLocation": [ - "foo", - "bar", - "baz" + "FlattenedListArgWithXmlName": [ + "A", + "B" ] } }, "when": { "action": "marshall", - "operation": "QueryTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "NonFlattenedListWithLocation.item.1": "foo", - "NonFlattenedListWithLocation.item.2": "bar", - "NonFlattenedListWithLocation.item.3": "baz" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&Hi.1=A&Hi.2=B" + }, + "uri": "/" } } }, { - "description": "A flattened map of string to string is marshalled correctly", + "id": "QueryNestedStructWithList", + "description": "Nested structure with a list member", "given": { "input": { - "FlattenedMap": { - "key1": "val1", - "key2": "val2" + "NestedWithList": { + "ListArg": [ + "A", + "B" + ] } } }, "when": { "action": "marshall", - "operation": "QueryTypes" + "operation": "QueryLists" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "FlattenedMap.1.key": "key1", - "FlattenedMap.1.value": "val1", - "FlattenedMap.2.key": "key2", - "FlattenedMap.2.value": "val2" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryLists&Version=2020-01-08&NestedWithList.ListArg.member.1=A&NestedWithList.ListArg.member.2=B" + }, + "uri": "/" } } }, { - "description": "A non flattened map of string to string is marshalled correctly", + "id": "QuerySimpleQueryMaps", + "description": "Serializes query maps", "given": { "input": { - "mapOfStringToString": { - "key1": "val1", - "key2": "val2" + "MapArg": { + "bar": "Bar", + "foo": "Foo" } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "mapOfStringToString.entry.1.key": "key1", - "mapOfStringToString.entry.1.value": "val1", - "mapOfStringToString.entry.2.key": "key2", - "mapOfStringToString.entry.2.value": "val2" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&MapArg.entry.1.key=bar&MapArg.entry.1.value=Bar&MapArg.entry.2.key=foo&MapArg.entry.2.value=Foo" + }, + "uri": "/" } } }, { - "description": "A non flattened list with location name for key and value is marshalled correctly", + "id": "QuerySimpleQueryMapsWithXmlName", + "description": "Serializes query maps and uses xmlName", "given": { "input": { - "NonFlattenedMapWithLocation": { - "key1": "val1", - "key2": "val2" + "RenamedMapArg": { + "foo": "Foo" } } }, "when": { "action": "marshall", - "operation": "QueryTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "themap.entry.1.thekey": "key1", - "themap.entry.1.thevalue": "val1", - "themap.entry.2.thekey": "key2", - "themap.entry.2.thevalue": "val2" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&Foo.entry.1.key=foo&Foo.entry.1.value=Foo" + }, + "uri": "/" } } }, { - "description": "A blob member is marshalled as Base64 encoded text into the query params", + "id": "QueryComplexQueryMaps", + "description": "Serializes complex query maps", "given": { "input": { - "blobArg": "foo" + "ComplexMapArg": { + "bar": { + "hi": "Bar" + }, + "foo": { + "hi": "Foo" + } + } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "blobArg": "Zm9v" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&ComplexMapArg.entry.1.key=bar&ComplexMapArg.entry.1.value.hi=Bar&ComplexMapArg.entry.2.key=foo&ComplexMapArg.entry.2.value.hi=Foo" + }, + "uri": "/" } } }, { - "description": "A blob list member is marshalled as Base64 encoded text into the query params", + "id": "QueryEmptyQueryMaps", + "description": "Does not serialize empty query maps", "given": { "input": { - "listOfBlobs": [ - "foo", - "bar" - ] + "MapArg": {} } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "listOfBlobs.member.1": "Zm9v", - "listOfBlobs.member.2": "YmFy" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08" + }, + "uri": "/" } } }, { - "description": "A blob map value member is marshalled as Base64 encoded text into the query params", + "id": "QueryQueryMapWithMemberXmlName", + "description": "Serializes query maps where the member has an xmlName trait", "given": { "input": { - "blobMap": { - "key1": "foo" + "MapWithXmlMemberName": { + "bar": "Bar", + "foo": "Foo" } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "blobMap.entry.1.key": "key1", - "blobMap.entry.1.value": "Zm9v" + "Content-Type": "application/x-www-form-urlencoded" } - } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&MapWithXmlMemberName.entry.1.K=bar&MapWithXmlMemberName.entry.1.V=Bar&MapWithXmlMemberName.entry.2.K=foo&MapWithXmlMemberName.entry.2.V=Foo" + }, + "uri": "/" } } }, { - "description": "A timestamp is marshalled as an ISO8601 date with millisecond precision", + "id": "QueryFlattenedQueryMaps", + "description": "Serializes flattened query maps", "given": { "input": { - "timestampMember": 1422172800123 + "FlattenedMap": { + "bar": "Bar", + "foo": "Foo" + } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { + "method": "POST", + "headers": { "contains": { - "timestampMember": "2015-01-25T08:00:00.123Z" + "Content-Type": "application/x-www-form-urlencoded" } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&FlattenedMap.1.key=bar&FlattenedMap.1.value=Bar&FlattenedMap.2.key=foo&FlattenedMap.2.value=Foo" + }, + "uri": "/" + } + } + }, + { + "id": "QueryFlattenedQueryMapsWithXmlName", + "description": "Serializes flattened query maps that use an xmlName", + "given": { + "input": { + "FlattenedMapWithXmlName": { + "bar": "Bar", + "foo": "Foo" } } + }, + "when": { + "action": "marshall", + "operation": "QueryMaps" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&Hi.1.K=bar&Hi.1.V=Bar&Hi.2.K=foo&Hi.2.V=Foo" + }, + "uri": "/" + } } }, { - "description": "No parameters set, does not set query request params", + "id": "QueryQueryMapOfLists", + "description": "Serializes query map of lists", "given": { "input": { + "MapOfLists": { + "bar": [ + "C", + "D" + ], + "foo": [ + "A", + "B" + ] + } } }, "when": { "action": "marshall", - "operation": "AllTypes" + "operation": "QueryMaps" }, "then": { "serializedAs": { - "params": { - "containsOnly": { - "Action": "AllTypes", - "Version": "2016-03-11" + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&MapOfLists.entry.1.key=bar&MapOfLists.entry.1.value.member.1=C&MapOfLists.entry.1.value.member.2=D&MapOfLists.entry.2.key=foo&MapOfLists.entry.2.value.member.1=A&MapOfLists.entry.2.value.member.2=B" + }, + "uri": "/" + } + } + }, + { + "id": "QueryNestedStructWithMap", + "description": "Serializes nested struct with map member", + "given": { + "input": { + "NestedStructWithMap": { + "MapArg": { + "bar": "Bar", + "foo": "Foo" } } } + }, + "when": { + "action": "marshall", + "operation": "QueryMaps" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + } + }, + "body": { + "queryEquals": "Action=QueryMaps&Version=2020-01-08&NestedStructWithMap.MapArg.entry.1.key=bar&NestedStructWithMap.MapArg.entry.1.value=Bar&NestedStructWithMap.MapArg.entry.2.key=foo&NestedStructWithMap.MapArg.entry.2.value=Foo" + }, + "uri": "/" + } + } + }, + { + "id": "QueryTimestampsInput", + "description": "Serializes timestamps", + "given": { + "input": { + "normalFormat": 1422172800, + "epochMember": 1422172800, + "epochTarget": 1422172800 + } + }, + "when": { + "action": "marshall", + "operation": "QueryTimestamps" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=QueryTimestamps&Version=2020-01-08&normalFormat=2015-01-25T08%3A00%3A00Z&epochMember=1422172800&epochTarget=1422172800" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsStrings", + "description": "Serializes strings", + "given": { + "input": { + "Foo": "val1", + "Bar": "val2" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Foo=val1&Bar=val2" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsStringAndBooleanTrue", + "description": "Serializes booleans that are true", + "given": { + "input": { + "Foo": "val1", + "Baz": true + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Foo=val1&Baz=true" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsStringsAndBooleanFalse", + "description": "Serializes booleans that are false", + "given": { + "input": { + "Baz": false + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Baz=false" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsInteger", + "description": "Serializes integers", + "given": { + "input": { + "Bam": 10 + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Bam=10" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsFloat", + "description": "Serializes floats", + "given": { + "input": { + "Boo": 10.8 + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Boo=10.8" + }, + "uri": "/" + } + } + }, + { + "id": "QuerySimpleInputParamsBlob", + "description": "Blobs are base64 encoded in the query string", + "given": { + "input": { + "Qux": "value" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&Qux=dmFsdWU%3D" + }, + "uri": "/" + } + } + }, + { + "id": "QueryEnums", + "description": "Serializes enums in the query string", + "given": { + "input": { + "FooEnum": "Foo" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&FooEnum=Foo" + }, + "uri": "/" + } + } + }, + { + "id": "QueryIntEnums", + "description": "Serializes intEnums in the query string", + "given": { + "input": { + "IntegerEnum": 1 + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&IntegerEnum=1" + }, + "uri": "/" + } + } + }, + { + "id": "AwsQuerySupportsNaNFloatInputs", + "description": "Supports handling NaN float values.", + "given": { + "input": { + "FloatValue": "NaN", + "Boo": "NaN" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&FloatValue=NaN&Boo=NaN" + }, + "uri": "/" + } + } + }, + { + "id": "AwsQuerySupportsInfinityFloatInputs", + "description": "Supports handling Infinity float values.", + "given": { + "input": { + "FloatValue": "Infinity", + "Boo": "Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&FloatValue=Infinity&Boo=Infinity" + }, + "uri": "/" + } + } + }, + { + "id": "AwsQuerySupportsNegativeInfinityFloatInputs", + "description": "Supports handling -Infinity float values.", + "given": { + "input": { + "FloatValue": "-Infinity", + "Boo": "-Infinity" + } + }, + "when": { + "action": "marshall", + "operation": "SimpleInputParams" + }, + "then": { + "serializedAs": { + "method": "POST", + "headers": { + "contains": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "queryEquals": "Action=SimpleInputParams&Version=2020-01-08&FloatValue=-Infinity&Boo=-Infinity" + }, + "uri": "/" + } } } - // TODO the current implementation of query marshallers cannot easily support recursion ] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-output.json index ae115affc126..16fa56d0d814 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-output.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/query-output.json @@ -1,394 +1,974 @@ [ { - "description": "Tests that simple scalar members are unmarshalled correctly", + "id": "AwsQueryDateTimeWithNegativeOffset", + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", "given": { "response": { "status_code": 200, - "body": "stringVal421.2345.678900152015-01-25T08:00:12Zrequest-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2019-12-16T22:48:18-01:00\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "DatetimeOffsets" }, "then": { "deserializedAs": { - "stringMember": "stringVal", - "integerMember": 42, - "floatMember": 1.234, - "doubleMember": 5.678, - "longMember": 9001, - "shortMember": 5, - "timestampMember": 1422172812000 + "datetime": 1576540098 } } }, { - "description": "Tests that a boolean member with value false in unmarshalled correctly", + "id": "AwsQueryDateTimeWithPositiveOffset", + "description": "Ensures that clients can correctly parse datetime (timestamps) with offsets", "given": { "response": { "status_code": 200, - "body": "falserequest-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2019-12-17T00:48:18+01:00\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "DatetimeOffsets" }, "then": { "deserializedAs": { - "booleanMember": false + "datetime": 1576540098 } } }, { - "description": "Tests that a boolean member with value true in unmarshalled correctly", + "id": "QueryEmptyInputAndEmptyOutput", + "description": "Empty output", + "given": { + "response": { + "status_code": 200 + } + }, + "when": { + "action": "unmarshall", + "operation": "EmptyInputAndEmptyOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "QueryQueryFlattenedXmlMap", + "description": "Serializes flattened XML maps in responses", "given": { "response": { "status_code": 200, - "body": "truerequest-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n foo\n Foo\n \n \n baz\n Baz\n \n \n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "FlattenedXmlMap" }, "then": { "deserializedAs": { - "booleanMember": true + "myMap": { + "foo": "Foo", + "baz": "Baz" + } } } }, { - "description": "Tests that a Base64 encoded blob in the payload is unmarshalled and decoded correctly", + "id": "QueryQueryFlattenedXmlMapWithXmlName", + "description": "Serializes flattened XML maps in responses that have xmlName on members", "given": { "response": { "status_code": 200, - "body": "dmFsdWU=request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n a\n A\n \n \n b\n B\n \n \n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "FlattenedXmlMapWithXmlName" }, "then": { "deserializedAs": { - "blobArg": "value" + "myMap": { + "a": "A", + "b": "B" + } } } }, { - "description": "Tests that a list of strings in the payload is unmarshalled correctly", + "id": "QueryQueryFlattenedXmlMapWithXmlNamespace", + "description": "Serializes flattened XML maps in responses that have xmlNamespace and xmlName on members", "given": { "response": { "status_code": 200, - "body": "val1val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n a\n A\n \n \n b\n B\n \n \n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "FlattenedXmlMapWithXmlNamespace" }, "then": { "deserializedAs": { - "simpleList": [ - "val1", - "val2" - ] + "myMap": { + "a": "A", + "b": "B" + } } } }, { - "description": "Tests that a list of strings with an non default location name is unmarshalled correctly", + "id": "AwsQueryDateTimeWithFractionalSeconds", + "description": "Ensures that clients can correctly parse datetime timestamps with fractional seconds", "given": { "response": { "status_code": 200, - "body": "val1val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2000-01-02T20:34:56.123Z\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "FractionalSeconds" }, "then": { "deserializedAs": { - "NonFlattenedListWithLocation": [ - "val1", - "val2" - ] + "datetime": 9.46845296123E8 } } }, { - "description": "Tests that a flattened list with default location name is unmarshalled correctly", + "id": "QueryGreetingWithErrors", + "description": "Ensures that operations with errors successfully know how to deserialize the successful response", "given": { "response": { "status_code": 200, - "body": "val1val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Hello\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "GreetingWithErrors" }, "then": { "deserializedAs": { - "FlattenedListOfStrings": [ - "val1", - "val2" - ] + "greeting": "Hello" } } }, { - "description": "Tests that a flattened list with a single element and with default location name is unmarshalled correctly", + "id": "QueryInvalidGreetingError", + "description": "Parses simple XML errors", + "given": { + "response": { + "status_code": 400, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Sender\n InvalidGreeting\n Hi\n \n foo-id\n\n" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "InvalidGreeting" + }, + "then": { + "deserializedAs": { + "Message": "Hi" + } + } + }, + { + "id": "QueryComplexError", + "given": { + "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" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "ComplexError" + }, + "then": { + "deserializedAs": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" + } + } + } + }, + { + "id": "QueryCustomizedError", + "description": "Parses customized XML errors", + "given": { + "response": { + "status_code": 402, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Sender\n Customized\n Hi\n \n foo-id\n\n" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "CustomCodeError" + }, + "then": { + "deserializedAs": { + "Message": "Hi" + }, + "errorCode": "Customized" + } + }, + { + "id": "QueryIgnoresWrappingXmlName", + "description": "The xmlName trait on the output structure is ignored in AWS Query", "given": { "response": { "status_code": 200, - "body": "val1request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n bar\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "IgnoresWrappingXmlName" }, "then": { "deserializedAs": { - "FlattenedListOfStrings": [ - "val1" - ] + "foo": "bar" + } + } + }, + { + "id": "QueryNoInputAndNoOutput", + "description": "Empty output. Note that no assertion is made on the output body itself.", + "given": { + "response": { + "status_code": 200 + } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndNoOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "QueryNoInputAndOutput", + "description": "Empty output", + "given": { + "response": { + "status_code": 200 } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputAndOutput" + }, + "then": { + "deserializedAs": {} } }, { - "description": "Tests that a non-flattened list with no element is unmarshalled as empty list", + "id": "QueryRecursiveShapes", + "description": "Serializes recursive structures", "given": { "response": { "status_code": 200, - "body": "request-id" + "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" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "RecursiveXmlShapes" }, "then": { "deserializedAs": { - "NonFlattenedListWithLocation": [ - ] + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } + } } } }, { - "description": "Tests that a non-flattened list of structs with no element is unmarshalled as empty list", + "id": "QuerySimpleScalarProperties", + "description": "Serializes simple scalar properties", "given": { "response": { "status_code": 200, - "body": "request-id" + "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" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "SimpleScalarXmlProperties" }, "then": { "deserializedAs": { - "listOfStructs": [ - ] + "stringValue": "string", + "emptyStringValue": "", + "trueBooleanValue": true, + "falseBooleanValue": false, + "byteValue": 1, + "shortValue": 2, + "integerValue": 3, + "longValue": 4, + "floatValue": 5.5, + "doubleValue": 6.5 } } }, { - "description": "Tests that a list of structure types is unmarshalled correctly", + "id": "AwsQuerySupportsNaNFloatOutputs", + "description": "Supports handling NaN float values.", "given": { "response": { "status_code": 200, - "body": "foobarrequest-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n NaN\n NaN\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "SimpleScalarXmlProperties" }, "then": { "deserializedAs": { - "listOfStructs": [ + "floatValue": "NaN", + "doubleValue": "NaN" + } + } + }, + { + "id": "AwsQuerySupportsInfinityFloatOutputs", + "description": "Supports handling Infinity float values.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Infinity\n Infinity\n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarXmlProperties" + }, + "then": { + "deserializedAs": { + "floatValue": "Infinity", + "doubleValue": "Infinity" + } + } + }, + { + "id": "AwsQuerySupportsNegativeInfinityFloatOutputs", + "description": "Supports handling -Infinity float values.", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n -Infinity\n -Infinity\n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "SimpleScalarXmlProperties" + }, + "then": { + "deserializedAs": { + "floatValue": "-Infinity", + "doubleValue": "-Infinity" + } + } + }, + { + "id": "QueryXmlBlobs", + "description": "Blobs are base64 encoded", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n dmFsdWU=\n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlBlobs" + }, + "then": { + "deserializedAs": { + "data": "value" + } + } + }, + { + "id": "QueryXmlEmptyBlobs", + "description": "Empty blobs are deserialized as empty string", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEmptyBlobs" + }, + "then": { + "deserializedAs": { + "data": "" + } + } + }, + { + "id": "QueryXmlEmptySelfClosedBlobs", + "description": "Empty self closed blobs are deserialized as empty string", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEmptyBlobs" + }, + "then": { + "deserializedAs": { + "data": "" + } + } + }, + { + "id": "QueryXmlEmptyLists", + "description": "Deserializes empty XML lists", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEmptyLists" + }, + "then": { + "deserializedAs": { + "stringList": [], + "stringSet": [] + } + } + }, + { + "id": "QueryXmlEmptyMaps", + "description": "Deserializes Empty XML maps", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEmptyMaps" + }, + "then": { + "deserializedAs": { + "myMap": {} + } + } + }, + { + "id": "QueryXmlEmptySelfClosedMaps", + "description": "Deserializes Self-Closed XML maps", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEmptyMaps" + }, + "then": { + "deserializedAs": { + "myMap": {} + } + } + }, + { + "id": "QueryXmlEnums", + "description": "Serializes simple scalar properties", + "given": { + "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" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlEnums" + }, + "then": { + "deserializedAs": { + "fooEnum1": "Foo", + "fooEnum2": "0", + "fooEnum3": "1", + "fooEnumList": [ + "Foo", + "0" + ], + "fooEnumSet": [ + "Foo", + "0" + ], + "fooEnumMap": { + "hi": "Foo", + "zero": "0" + } + } + } + }, + { + "id": "QueryXmlIntEnums", + "description": "Serializes simple scalar properties", + "given": { + "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" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlIntEnums" + }, + "then": { + "deserializedAs": { + "intEnum1": 1, + "intEnum2": 2, + "intEnum3": 3, + "intEnumList": [ + 1, + 2 + ], + "intEnumSet": [ + 1, + 2 + ], + "intEnumMap": { + "a": 1, + "b": 2 + } + } + } + }, + { + "id": "QueryXmlLists", + "description": "Tests for XML list serialization", + "given": { + "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" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlLists" + }, + "then": { + "deserializedAs": { + "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": [ { - "StringMember": "foo" + "a": "1", + "b": "2" }, { - "StringMember": "bar" + "a": "3", + "b": "4" } ] } } }, { - "description": "Tests that a flattened list of structure types is unmarshalled correctly", + "id": "QueryXmlMaps", + "description": "Tests for XML map serialization", "given": { "response": { "status_code": 200, - "body": "foobarrequest-id" + "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" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "XmlMaps" }, "then": { "deserializedAs": { - "FlattenedListOfStructs": [ - { - "StringMember": "foo" + "myMap": { + "foo": { + "hi": "there" }, - { - "StringMember": "bar" + "baz": { + "hi": "bye" } - ] + } } } }, { - "description": "Tests that a flattened list of strings with non default location name is unmarshalled correctly", + "id": "QueryQueryXmlMapsXmlName", + "description": "Serializes XML lists", "given": { "response": { "status_code": 200, - "body": "val1val2request-id" + "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" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "XmlMapsXmlName" }, "then": { "deserializedAs": { - "FlattenedListWithLocation": [ - "val1", - "val2" - ] + "myMap": { + "foo": { + "hi": "there" + }, + "baz": { + "hi": "bye" + } + } } } }, { - "description": "Tests unmarshalling a non-flattened map in the payload", + "id": "QueryXmlNamespaces", + "description": "Serializes XML namespaces", "given": { "response": { "status_code": 200, - "body": "key1val1key2val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n \n Foo\n \n Bar\n Baz\n \n \n \n\n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "XmlNamespaces" }, "then": { "deserializedAs": { - "mapOfStringToString": { - "key1": "val1", - "key2": "val2" + "nested": { + "foo": "Foo", + "values": [ + "Bar", + "Baz" + ] } } } }, { - "description": "Tests unmarshalling a non-flattened map with an explicit locationName and locationName's for both key and value", + "id": "QueryXmlTimestamps", + "description": "Tests how normal timestamps are serialized", "given": { "response": { "status_code": 200, - "body": "key1val1key2val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "XmlTimestamps" }, "then": { "deserializedAs": { - "NonFlattenedMapWithLocation": { - "key1": "val1", - "key2": "val2" - } + "normal": 1398796238 } } }, { - "description": "Tests unmarshalling a flattened map with an explicit locationName and locationName's for both key and value", + "id": "QueryXmlTimestampsWithDateTimeFormat", + "description": "Ensures that the timestampFormat of date-time works like normal timestamps", "given": { "response": { "status_code": 200, - "body": "key1val1key2val2request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "QueryTypes" + "operation": "XmlTimestamps" }, "then": { "deserializedAs": { - "FlattenedMapWithLocation": { - "key1": "val1", - "key2": "val2" - } + "dateTime": 1398796238 } } }, { - "description": "Tests unmarshalling an empty XML tag as an empty string", + "id": "QueryXmlTimestampsWithDateTimeOnTargetFormat", + "description": "Ensures that the timestampFormat of date-time on the target shape works like normal timestamps", "given": { "response": { "status_code": 200, - "body": "request-id" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 2014-04-29T18:30:38Z\n \n\n" } }, "when": { "action": "unmarshall", - "operation": "AllTypes" + "operation": "XmlTimestamps" }, "then": { "deserializedAs": { - "stringMember": "" + "dateTimeOnTarget": 1398796238 } } }, { - "description": "ListOfTimeStamp with known values unmarshalled correctly", + "id": "QueryXmlTimestampsWithEpochSecondsFormat", + "description": "Ensures that the timestampFormat of epoch-seconds works", "given": { "response": { "status_code": 200, - "body": "1398796238.1232591234567.123" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 1398796238\n \n\n" } }, "when": { "action": "unmarshall", - - "operation": "AllTypes" + "operation": "XmlTimestamps" }, "then": { "deserializedAs": { - "ListOfTimeStamp": [1398796238123,2591234567123] + "epochSeconds": 1398796238 } } }, { - "description": "MapOfTimeStamp with known values unmarshalled correctly", + "id": "QueryXmlTimestampsWithEpochSecondsOnTargetFormat", + "description": "Ensures that the timestampFormat of epoch-seconds on the target shape works", "given": { "response": { "status_code": 200, - "body": "test11398796238.123test22591234567.123" + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n 1398796238\n \n\n" } }, "when": { "action": "unmarshall", - - "operation": "AllTypes" + "operation": "XmlTimestamps" }, "then": { "deserializedAs": { - "MapOfTimeStamp": { - "test1": "1398796238123", - "test2": "2591234567123" - } + "epochSecondsOnTarget": 1398796238 + } + } + }, + { + "id": "QueryXmlTimestampsWithHttpDateFormat", + "description": "Ensures that the timestampFormat of http-date works", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Tue, 29 Apr 2014 18:30:38 GMT\n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlTimestamps" + }, + "then": { + "deserializedAs": { + "httpDate": 1398796238 + } + } + }, + { + "id": "QueryXmlTimestampsWithHttpDateOnTargetFormat", + "description": "Ensures that the timestampFormat of http-date on the target shape works", + "given": { + "response": { + "status_code": 200, + "headers": { + "Content-Type": "text/xml" + }, + "body": "\n \n Tue, 29 Apr 2014 18:30:38 GMT\n \n\n" + } + }, + "when": { + "action": "unmarshall", + "operation": "XmlTimestamps" + }, + "then": { + "deserializedAs": { + "httpDateOnTarget": 1398796238 } } } -] \ No newline at end of file +] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json index 03f65797cbed..8009a8b5201f 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-input.json @@ -1,166 +1,142 @@ [ { - "description": "Serializes null values in lists", + "id": "empty_input", + "description": "When Input structure is empty we write CBOR equivalent of {}", "given": { - "input": { - "sparseStringList": [ - null - ] - } + "input": {} }, "when": { "action": "marshall", - "operation": "SparseNullsOperation" + "operation": "EmptyInputOutput" }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v3BzcGFyc2VTdHJpbmdMaXN0gfb/" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "doesNotContain": [ + "X-Amz-Target" + ], + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v/8=" + }, + "uri": "/service/RpcV2Protocol/operation/EmptyInputOutput" } } }, { - "description": "Serializes recursive structures", + "id": "no_input", + "description": "Body is empty and no Content-Type header if no input", "given": { - "input": { - "nested": { - "foo": "Foo1", - "nested": { - "bar": "Bar1", - "recursiveMember": { - "foo": "Foo2", - "nested": { - "bar": "Bar2" - } - } - } - } - } + "input": {} }, "when": { "action": "marshall", - "operation": "RecursiveShapes" + "operation": "NoInputOutput" }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", "Accept": "application/cbor", "smithy-protocol": "rpc-v2-cbor" - } - } - } - } - }, - { - "description": "Serializes sparse maps", - "given": { - "input": { - "sparseStructMap": { - "foo": { - "hi": "there" }, - "baz": { - "hi": "bye" - } - } - } - }, - "when": { - "action": "marshall", - "operation": "RpcV2CborSparseMaps" - }, - "then": { - "serializedAs": { + "doesNotContain": [ + "Content-Type", + "X-Amz-Target" + ] + }, "body": { - "encodedEquals": "v29zcGFyc2VTdHJ1Y3RNYXC/Y2Zvb79iaGlldGhlcmX/Y2Jher9iaGljYnll////" + "cborEquals": "" }, - "headers": { - "contains": { - "Content-Type": "application/cbor", - "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "uri": "/service/RpcV2Protocol/operation/NoInputOutput" } } }, { - "description": "A request that contains a sparse map of sets", + "id": "optional_input", + "description": "When input is empty we write CBOR equivalent of {}", "given": { - "input": { - "sparseSetMap": { - "x": [], - "y": [ - "a", - "b" - ] - } - } + "input": {} }, "when": { "action": "marshall", - "operation": "RpcV2CborSparseMaps" + "operation": "OptionalInputOutput" }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2xzcGFyc2VTZXRNYXC/YXiAYXmCYWFhYv//" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "doesNotContain": [ + "X-Amz-Target" + ] + }, + "body": { + "cborEquals": "v/8=" + }, + "uri": "/service/RpcV2Protocol/operation/OptionalInputOutput" } } }, { - "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "id": "RpcV2CborRecursiveShapes", + "description": "Serializes recursive structures", "given": { "input": { - "sparseNumberMap": { - "x": 0 - }, - "sparseBooleanMap": { - "x": false + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } } } }, "when": { "action": "marshall", - "operation": "RpcV2CborSparseMaps" + "operation": "RecursiveShapes" }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v29zcGFyc2VOdW1iZXJNYXC/YXgA/3BzcGFyc2VCb29sZWFuTWFwv2F49P//" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" + }, + "uri": "/service/RpcV2Protocol/operation/RecursiveShapes" } } }, { + "id": "RpcV2CborMaps", "description": "Serializes maps", "given": { "input": { @@ -180,20 +156,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v25kZW5zZVN0cnVjdE1hcL9jZm9vv2JoaWV0aGVyZf9jYmF6v2JoaWNieWX///8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "oW5kZW5zZVN0cnVjdE1hcKJjZm9voWJoaWV0aGVyZWNiYXqhYmhpY2J5ZQ==" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborDenseMaps" } } }, { + "id": "RpcV2CborSerializesZeroValuesInMaps", "description": "Ensure that 0 and false are sent over the wire in all maps and lists", "given": { "input": { @@ -211,20 +193,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v25kZW5zZU51bWJlck1hcL9heAD/b2RlbnNlQm9vbGVhbk1hcL9hePT//w==" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "om5kZW5zZU51bWJlck1hcKFheABvZGVuc2VCb29sZWFuTWFwoWF49A==" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborDenseMaps" } } }, { + "id": "RpcV2CborSerializesDenseSetMap", "description": "A request that contains a dense map of sets.", "given": { "input": { @@ -243,20 +231,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2tkZW5zZVNldE1hcL9heIBheYJhYWFi//8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "oWtkZW5zZVNldE1hcKJheIBheYJhYWFi" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborDenseMaps" } } }, { + "id": "RpcV2CborLists", "description": "Serializes RpcV2 Cbor lists", "given": { "input": { @@ -277,8 +271,8 @@ false ], "timestampList": [ - 1398796238000, - 1398796238000 + 1398796238, + 1398796238 ], "enumList": [ "Foo", @@ -320,20 +314,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2pzdHJpbmdMaXN0gmNmb29jYmFyaXN0cmluZ1NldIJjZm9vY2JhcmtpbnRlZ2VyTGlzdIIBAmtib29sZWFuTGlzdIL19G10aW1lc3RhbXBMaXN0gsH7QdTX+/OAAADB+0HU1/vzgAAAaGVudW1MaXN0gmNGb29hMGtpbnRFbnVtTGlzdIIBAnBuZXN0ZWRTdHJpbmdMaXN0goJjZm9vY2JhcoJjYmF6Y3F1eG1zdHJ1Y3R1cmVMaXN0gr9hYWExYWJhMv+/YWFhM2FiYTT/aGJsb2JMaXN0gkNmb29DYmFy/w==" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2pzdHJpbmdMaXN0gmNmb29jYmFyaXN0cmluZ1NldIJjZm9vY2JhcmtpbnRlZ2VyTGlzdIIBAmtib29sZWFuTGlzdIL19G10aW1lc3RhbXBMaXN0gsH7QdTX+/OAAADB+0HU1/vzgAAAaGVudW1MaXN0gmNGb29hMGtpbnRFbnVtTGlzdIIBAnBuZXN0ZWRTdHJpbmdMaXN0goJjZm9vY2JhcoJjYmF6Y3F1eG1zdHJ1Y3R1cmVMaXN0gqJhYWExYWJhMqJhYWEzYWJhNGhibG9iTGlzdIJDZm9vQ2Jhcv8=" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborLists" } } }, { + "id": "RpcV2CborListsEmpty", "description": "Serializes empty JSON lists", "given": { "input": { @@ -346,20 +346,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2pzdHJpbmdMaXN0gP8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2pzdHJpbmdMaXN0n///" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborLists" } } }, { + "id": "RpcV2CborListsEmptyUsingDefiniteLength", "description": "Serializes empty JSON definite length lists", "given": { "input": { @@ -372,32 +378,38 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2pzdHJpbmdMaXN0gP8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "oWpzdHJpbmdMaXN0gA==" + }, + "uri": "/service/RpcV2Protocol/operation/RpcV2CborLists" } } }, { + "id": "RpcV2CborSimpleScalarProperties", "description": "Serializes simple scalar properties", "given": { "input": { - "trueBooleanValue": true, - "falseBooleanValue": false, "byteValue": 5, "doubleValue": 1.889, + "falseBooleanValue": false, "floatValue": 7.625, "integerValue": 256, "longValue": 9873, "shortValue": 9898, "stringValue": "simple", + "trueBooleanValue": true, "blobValue": "foo" } }, @@ -407,20 +419,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZWlibG9iVmFsdWVDZm9v/w==" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==" + }, + "uri": "/service/RpcV2Protocol/operation/SimpleScalarProperties" } } }, { + "id": "RpcV2CborClientDoesntSerializeNullStructureValues", "description": "RpcV2 Cbor should not serialize null structure values", "given": { "input": { @@ -433,20 +451,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v/8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v/8=" + }, + "uri": "/service/RpcV2Protocol/operation/SimpleScalarProperties" } } }, { + "id": "RpcV2CborSupportsNaNFloatInputs", "description": "Supports handling NaN float values.", "given": { "input": { @@ -460,20 +484,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2tkb3VibGVWYWx1Zft/+AAAAAAAAGpmbG9hdFZhbHVl+n/AAAD/" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2tkb3VibGVWYWx1Zft/+AAAAAAAAGpmbG9hdFZhbHVl+n/AAAD/" + }, + "uri": "/service/RpcV2Protocol/operation/SimpleScalarProperties" } } }, { + "id": "RpcV2CborSupportsInfinityFloatInputs", "description": "Supports handling Infinity float values.", "given": { "input": { @@ -487,20 +517,26 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2tkb3VibGVWYWx1Zfp/gAAAamZsb2F0VmFsdWX6f4AAAP8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } + "Content-Type": "application/cbor" + }, + "mustContain": [ + "Content-Length" + ] + }, + "body": { + "cborEquals": "v2tkb3VibGVWYWx1Zft/8AAAAAAAAGpmbG9hdFZhbHVl+n+AAAD/" + }, + "uri": "/service/RpcV2Protocol/operation/SimpleScalarProperties" } } }, { + "id": "RpcV2CborSupportsNegativeInfinityFloatInputs", "description": "Supports handling Infinity float values.", "given": { "input": { @@ -514,96 +550,21 @@ }, "then": { "serializedAs": { - "body": { - "encodedEquals": "v2tkb3VibGVWYWx1Zfr/gAAAamZsb2F0VmFsdWX6/4AAAP8=" - }, - "headers": { - "contains": { - "Content-Type": "application/cbor", - "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - } - } - } - } - }, - { - "description": "When input is empty we write CBOR equivalent of {}", - "given": { - "input": {} - }, - "when": { - "action": "marshall", - "operation": "OptionalInputOutput" - }, - "then": { - "serializedAs": { - "body": { - "encodedEquals": "v/8=" - }, + "method": "POST", "headers": { "contains": { - "Content-Type": "application/cbor", + "smithy-protocol": "rpc-v2-cbor", "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" + "Content-Type": "application/cbor" }, - "doesNotContain": [ - "X-Amz-Target" + "mustContain": [ + "Content-Length" ] - } - } - } - }, - { - "description": "When Input structure is empty we write CBOR equivalent of {}", - "given": { - "input": {} - }, - "when": { - "action": "marshall", - "operation": "EmptyInputOutput" - }, - "then": { - "serializedAs": { - "body": { - "encodedEquals": "v/8=" }, - "headers": { - "contains": { - "Content-Type": "application/cbor", - "Accept": "application/cbor", - "smithy-protocol": "rpc-v2-cbor" - }, - "doesNotContain": [ - "X-Amz-Target" - ] - } - } - } - }, - { - "description": "Body is empty and no Content-Type header if no input", - "given": { - "input": {} - }, - "when": { - "action": "marshall", - "operation": "NoInputOutput" - }, - "then": { - "serializedAs": { "body": { - "encodedEquals": "" + "cborEquals": "v2tkb3VibGVWYWx1Zfv/8AAAAAAAAGpmbG9hdFZhbHVl+v+AAAD/" }, - "headers": { - "contains": { - "smithy-protocol": "rpc-v2-cbor" - }, - "doesNotContain": [ - "Content-Type", - "X-Amz-Target" - ] - } + "uri": "/service/RpcV2Protocol/operation/SimpleScalarProperties" } } } diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json index c7523d9776f6..cfd0ec2c3c29 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/cases/smithy-rpcv2-output.json @@ -1,9 +1,56 @@ [ { + "id": "empty_output", + "description": "When output structure is empty we write CBOR equivalent of {}", + "given": { + "response": { + "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v/8=" + } + }, + "when": { + "action": "unmarshall", + "operation": "EmptyInputOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "empty_output_no_body", + "description": "When output structure is empty the client should accept an empty body", + "given": { + "response": { + "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "" + } + }, + "when": { + "action": "unmarshall", + "operation": "EmptyInputOutput" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "RpcV2CborFloat16Inf", "description": "Ensures that clients can correctly parse float16 +Inf.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWV2YWx1Zfl8AA==" } }, @@ -18,10 +65,15 @@ } }, { + "id": "RpcV2CborFloat16NegInf", "description": "Ensures that clients can correctly parse float16 -Inf.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWV2YWx1Zfn8AA==" } }, @@ -36,10 +88,15 @@ } }, { + "id": "RpcV2CborFloat16LSBNaN", "description": "Ensures that clients can correctly parse float16 NaN with high LSB.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWV2YWx1Zfl8AQ==" } }, @@ -54,10 +111,15 @@ } }, { + "id": "RpcV2CborFloat16MSBNaN", "description": "Ensures that clients can correctly parse float16 NaN with high MSB.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWV2YWx1Zfl+AA==" } }, @@ -72,30 +134,38 @@ } }, { - "description": "Deserializes null values in lists", + "id": "RpcV2CborFloat16Subnormal", + "description": "Ensures that clients can correctly parse a subnormal float16.", "given": { "response": { "status_code": 200, - "binaryBody": "v3BzcGFyc2VTdHJpbmdMaXN0n/b//w==" + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "oWV2YWx1ZfkAUA==" } }, "when": { "action": "unmarshall", - "operation": "SparseNullsOperation" + "operation": "Float16" }, "then": { "deserializedAs": { - "sparseStringList": [ - null - ] + "value": 4.76837158203125E-6 } } }, { + "id": "RpcV2CborDateTimeWithFractionalSeconds", "description": "Ensures that clients can correctly parse timestamps with fractional seconds", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2hkYXRldGltZcH7Qcw32zgPvnf/" } }, @@ -105,145 +175,243 @@ }, "then": { "deserializedAs": { - "datetime": 946845296123 + "datetime": 9.46845296123E8 } } }, { - "description": "Serializes recursive structures", + "id": "RpcV2CborInvalidGreetingError", + "description": "Parses simple RpcV2 Cbor errors", "given": { "response": { - "status_code": 200, - "binaryBody": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" + "status_code": 400, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v2ZfX3R5cGV4LnNtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNJbnZhbGlkR3JlZXRpbmdnTWVzc2FnZWJIaf8=" } }, "when": { - "action": "unmarshall", - "operation": "RecursiveShapes" + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "InvalidGreeting" }, "then": { "deserializedAs": { - "nested": { - "foo": "Foo1", - "nested": { - "bar": "Bar1", - "recursiveMember": { - "foo": "Foo2", - "nested": { - "bar": "Bar2" - } - } - } + "Message": "Hi" + } + } + }, + { + "id": "RpcV2CborComplexError", + "description": "Parses a complex error with no message member", + "given": { + "response": { + "status_code": 400, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v2ZfX3R5cGV4K3NtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNDb21wbGV4RXJyb3JoVG9wTGV2ZWxpVG9wIGxldmVsZk5lc3RlZL9jRm9vY2Jhcv//" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "ComplexError" + }, + "then": { + "deserializedAs": { + "TopLevel": "Top level", + "Nested": { + "Foo": "bar" } } } }, { - "description": "Deserializes recursive structures encoded using a map with definite length", + "id": "RpcV2CborEmptyComplexError", + "given": { + "response": { + "status_code": 400, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v2ZfX3R5cGV4K3NtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNDb21wbGV4RXJyb3L/" + } + }, + "when": { + "action": "errorUnmarshall", + "operation": "GreetingWithErrors", + "error": "ComplexError" + }, + "then": { + "deserializedAs": {} + } + }, + { + "id": "no_output", + "description": "A `Content-Type` header should not be set if the response body is empty.", "given": { "response": { "status_code": 200, - "binaryBody": "oWZuZXN0ZWSiY2Zvb2RGb28xZm5lc3RlZKJjYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyomNmb29kRm9vMmZuZXN0ZWShY2JhcmRCYXIy" + "headers": { + "smithy-protocol": "rpc-v2-cbor" + }, + "binaryBody": "" } }, "when": { "action": "unmarshall", - "operation": "RecursiveShapes" + "operation": "NoInputOutput" }, "then": { - "deserializedAs": { - "nested": { - "foo": "Foo1", - "nested": { - "bar": "Bar1", - "recursiveMember": { - "foo": "Foo2", - "nested": { - "bar": "Bar2" - } - } - } - } + "deserializedAs": {} + } + }, + { + "id": "NoOutputClientAllowsEmptyCbor", + "description": "Clients should accept a CBOR empty struct if there is no output.", + "given": { + "response": { + "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v/8=" } + }, + "when": { + "action": "unmarshall", + "operation": "NoInputOutput" + }, + "then": { + "deserializedAs": {} } }, { - "description": "Deserializes sparse maps", + "id": "NoOutputClientAllowsEmptyBody", + "description": "Clients should accept an empty body if there is no output and\nshould not raise an error if the `Content-Type` header is set.", "given": { "response": { "status_code": 200, - "binaryBody": "v29zcGFyc2VTdHJ1Y3RNYXC/Y2Zvb79iaGlldGhlcmX/Y2Jher9iaGljYnll////" + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "" } }, "when": { "action": "unmarshall", - "operation": "RpcV2CborSparseMaps" + "operation": "NoInputOutput" }, "then": { - "deserializedAs": { - "sparseStructMap": { - "foo": { - "hi": "there" - }, - "baz": { - "hi": "bye" - } - } + "deserializedAs": {} + } + }, + { + "id": "optional_output", + "description": "When output is empty we write CBOR equivalent of {}", + "given": { + "response": { + "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v/8=" } + }, + "when": { + "action": "unmarshall", + "operation": "OptionalInputOutput" + }, + "then": { + "deserializedAs": {} } }, { - "description": "A response that contains a sparse map of sets", + "id": "RpcV2CborRecursiveShapes", + "description": "Serializes recursive structures", "given": { "response": { "status_code": 200, - "binaryBody": "v2xzcGFyc2VTZXRNYXC/YXmfYWFhYv9heJ////8=" + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "v2ZuZXN0ZWS/Y2Zvb2RGb28xZm5lc3RlZL9jYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyv2Nmb29kRm9vMmZuZXN0ZWS/Y2JhcmRCYXIy//////8=" } }, "when": { "action": "unmarshall", - "operation": "RpcV2CborSparseMaps" + "operation": "RecursiveShapes" }, "then": { "deserializedAs": { - "sparseSetMap": { - "x": [], - "y": [ - "a", - "b" - ] + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } } } } }, { - "description": "Ensure that 0 and false are sent over the wire in all maps and lists", + "id": "RpcV2CborRecursiveShapesUsingDefiniteLength", + "description": "Deserializes recursive structures encoded using a map with definite length", "given": { "response": { "status_code": 200, - "binaryBody": "v29zcGFyc2VOdW1iZXJNYXC/YXgA/3BzcGFyc2VCb29sZWFuTWFwv2F49P//" + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, + "binaryBody": "oWZuZXN0ZWSiY2Zvb2RGb28xZm5lc3RlZKJjYmFyZEJhcjFvcmVjdXJzaXZlTWVtYmVyomNmb29kRm9vMmZuZXN0ZWShY2JhcmRCYXIy" } }, "when": { "action": "unmarshall", - "operation": "RpcV2CborSparseMaps" + "operation": "RecursiveShapes" }, "then": { "deserializedAs": { - "sparseNumberMap": { - "x": 0 - }, - "sparseBooleanMap": { - "x": false + "nested": { + "foo": "Foo1", + "nested": { + "bar": "Bar1", + "recursiveMember": { + "foo": "Foo2", + "nested": { + "bar": "Bar2" + } + } + } } } } }, { + "id": "RpcV2CborMaps", "description": "Deserializes maps", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oW5kZW5zZVN0cnVjdE1hcKJjZm9voWJoaWV0aGVyZWNiYXqhYmhpY2J5ZQ==" } }, @@ -265,10 +433,15 @@ } }, { + "id": "RpcV2CborDeserializesZeroValuesInMaps", "description": "Ensure that 0 and false are sent over the wire in all maps and lists", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "om5kZW5zZU51bWJlck1hcKFheABvZGVuc2VCb29sZWFuTWFwoWF49A==" } }, @@ -288,10 +461,15 @@ } }, { + "id": "RpcV2CborDeserializesDenseSetMap", "description": "A response that contains a dense map of sets", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWtkZW5zZVNldE1hcKJheIBheYJhYWFi" } }, @@ -312,10 +490,15 @@ } }, { + "id": "RpcV2CborLists", "description": "Serializes RpcV2 Cbor lists", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2pzdHJpbmdMaXN0n2Nmb29jYmFy/2lzdHJpbmdTZXSfY2Zvb2NiYXL/a2ludGVnZXJMaXN0nwEC/2tib29sZWFuTGlzdJ/19P9tdGltZXN0YW1wTGlzdJ/B+0HU1/vzgAAAwftB1Nf784AAAP9oZW51bUxpc3SfY0Zvb2Ew/2tpbnRFbnVtTGlzdJ8BAv9wbmVzdGVkU3RyaW5nTGlzdJ+fY2Zvb2NiYXL/n2NiYXpjcXV4//9tc3RydWN0dXJlTGlzdJ+/YWFhMWFiYTL/v2FhYTNhYmE0//9oYmxvYkxpc3SfQ2Zvb0NiYXL//w==" } }, @@ -342,8 +525,8 @@ false ], "timestampList": [ - 1398796238000, - 1398796238000 + 1398796238, + 1398796238 ], "enumList": [ "Foo", @@ -381,10 +564,15 @@ } }, { + "id": "RpcV2CborListsEmpty", "description": "Serializes empty RpcV2 Cbor lists", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2pzdHJpbmdMaXN0n///" } }, @@ -399,10 +587,15 @@ } }, { + "id": "RpcV2CborIndefiniteStringInsideIndefiniteListCanDeserialize", "description": "Can deserialize indefinite length text strings inside an indefinite length list", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2pzdHJpbmdMaXN0n394HUFuIGV4YW1wbGUgaW5kZWZpbml0ZSBzdHJpbmcsdyB3aGljaCB3aWxsIGJlIGNodW5rZWQsbiBvbiBlYWNoIGNvbW1h/394NUFub3RoZXIgZXhhbXBsZSBpbmRlZmluaXRlIHN0cmluZyB3aXRoIG9ubHkgb25lIGNodW5r/3ZUaGlzIGlzIGEgcGxhaW4gc3RyaW5n//8=" } }, @@ -421,10 +614,15 @@ } }, { + "id": "RpcV2CborIndefiniteStringInsideDefiniteListCanDeserialize", "description": "Can deserialize indefinite length text strings inside a definite length list", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "oWpzdHJpbmdMaXN0g394HUFuIGV4YW1wbGUgaW5kZWZpbml0ZSBzdHJpbmcsdyB3aGljaCB3aWxsIGJlIGNodW5rZWQsbiBvbiBlYWNoIGNvbW1h/394NUFub3RoZXIgZXhhbXBsZSBpbmRlZmluaXRlIHN0cmluZyB3aXRoIG9ubHkgb25lIGNodW5r/3ZUaGlzIGlzIGEgcGxhaW4gc3RyaW5n" } }, @@ -443,10 +641,15 @@ } }, { + "id": "RpcV2CborSimpleScalarProperties", "description": "Serializes simple scalar properties", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb2//" } }, @@ -469,10 +672,15 @@ } }, { + "id": "RpcV2CborSimpleScalarPropertiesUsingDefiniteLength", "description": "Deserializes simple scalar properties encoded using a map with definite length", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "qXB0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb28=" } }, @@ -495,10 +703,15 @@ } }, { + "id": "RpcV2CborClientDoesntDeserializeNullStructureValues", "description": "RpcV2 Cbor should not deserialize null structure values", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2tzdHJpbmdWYWx1Zfb/" } }, @@ -511,10 +724,15 @@ } }, { + "id": "RpcV2CborSupportsNaNFloatOutputs", "description": "Supports handling NaN float values.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2tkb3VibGVWYWx1Zft/+AAAAAAAAGpmbG9hdFZhbHVl+n/AAAD/" } }, @@ -530,10 +748,15 @@ } }, { + "id": "RpcV2CborSupportsInfinityFloatOutputs", "description": "Supports handling Infinity float values.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2tkb3VibGVWYWx1Zft/8AAAAAAAAGpmbG9hdFZhbHVl+n+AAAD/" } }, @@ -549,10 +772,15 @@ } }, { + "id": "RpcV2CborSupportsNegativeInfinityFloatOutputs", "description": "Supports handling Negative Infinity float values.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2tkb3VibGVWYWx1Zfv/8AAAAAAAAGpmbG9hdFZhbHVl+v+AAAD/" } }, @@ -568,10 +796,15 @@ } }, { + "id": "RpcV2CborSupportsUpcastingDataOnDeserialize", "description": "Supports upcasting from a smaller byte representation of the same data type.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2tkb3VibGVWYWx1Zfk+AGpmbG9hdFZhbHVl+UegbGludGVnZXJWYWx1ZRg4aWxvbmdWYWx1ZRkBAGpzaG9ydFZhbHVlCv8=" } }, @@ -590,10 +823,15 @@ } }, { + "id": "RpcV2CborExtraFieldsInTheBodyShouldBeSkippedByClients", "description": "The client should skip over additional fields that are not part of the structure. This allows a\nclient generated against an older Smithy model to be able to communicate with a server that is\ngenerated against a newer Smithy model.", "given": { "response": { "status_code": 200, + "headers": { + "smithy-protocol": "rpc-v2-cbor", + "Content-Type": "application/cbor" + }, "binaryBody": "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABrZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==" } }, @@ -603,136 +841,17 @@ }, "then": { "deserializedAs": { - "trueBooleanValue": true, - "falseBooleanValue": false, "byteValue": 5, "doubleValue": 1.889, + "falseBooleanValue": false, "floatValue": 7.625, "integerValue": 256, "longValue": 9873, "shortValue": 9898, "stringValue": "simple", + "trueBooleanValue": true, "blobValue": "foo" } } - }, - { - "description": "When output is empty we write CBOR equivalent of {}", - "given": { - "response": { - "status_code": 200, - "binaryBody": "v/8=" - } - }, - "when": { - "action": "unmarshall", - "operation": "OptionalInputOutput" - }, - "then": { - "deserializedAs": {} - } - }, - { - "description": "When output structure is empty we write CBOR equivalent of {}", - "given": { - "response": { - "status_code": 200, - "binaryBody": "v/8=" - } - }, - "when": { - "action": "unmarshall", - "operation": "EmptyInputOutput" - }, - "then": { - "deserializedAs": {} - } - }, - { - "description": "Clients should accept a CBOR empty struct if there is no output.", - "given": { - "response": { - "status_code": 200, - "binaryBody": "v/8=" - } - }, - "when": { - "action": "unmarshall", - "operation": "NoInputOutput" - }, - "then": { - "deserializedAs": {} - } - }, - { - "description": "Parses simple RpcV2 Cbor errors.", - "given": { - "response": { - "status_code": 400, - "headers": { - "smithy-protocol": "rpc-v2-cbor", - "Content-Type": "application/cbor" - }, - "binaryBody": "v2ZfX3R5cGV4LnNtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNJbnZhbGlkR3JlZXRpbmdnTWVzc2FnZWJIaf8=" - } - }, - "when": { - "action": "errorUnmarshall", - "operation": "GreetingWithErrors", - "error": "InvalidGreeting" - }, - "then": { - "deserializedAs": { - "Message": "Hi" - } - } - }, - { - "description": "Parses a complex error with no message member", - "given": { - "response": { - "status_code": 400, - "headers": { - "smithy-protocol": "rpc-v2-cbor", - "Content-Type": "application/cbor" - }, - "binaryBody": "v2ZfX3R5cGV4K3NtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNDb21wbGV4RXJyb3JoVG9wTGV2ZWxpVG9wIGxldmVsZk5lc3RlZL9jRm9vY2Jhcv//" - } - }, - "when": { - "action": "errorUnmarshall", - "operation": "GreetingWithErrors", - "error": "ComplexError" - }, - "then": { - "deserializedAs": { - "TopLevel": "Top level", - "Nested": { - "Foo": "bar" - } - } - } - }, - { - "description": "Parses an empty complex error", - "given": { - "response": { - "status_code": 400, - "headers": { - "smithy-protocol": "rpc-v2-cbor", - "Content-Type": "application/cbor" - }, - "binaryBody": "v2ZfX3R5cGV4K3NtaXRoeS5wcm90b2NvbHRlc3RzLnJwY3YyQ2JvciNDb21wbGV4RXJyb3L/" - } - }, - "when": { - "action": "errorUnmarshall", - "operation": "GreetingWithErrors", - "error": "ComplexError" - }, - "then": { - "deserializedAs": { - } - } } -] \ No newline at end of file +] diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/json10-suite.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/json10-suite.json new file mode 100644 index 000000000000..faaa5b399cd4 --- /dev/null +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/json10-suite.json @@ -0,0 +1,6 @@ +{ + "testCases": [ + "cases/json10-input.json", + "cases/json10-output.json" + ] +} \ No newline at end of file diff --git a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/query-suite.json b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/query-suite.json index b007fd456a44..c8a5865722f0 100644 --- a/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/query-suite.json +++ b/test/protocol-tests-core/src/main/resources/software/amazon/awssdk/protocol/suites/query-suite.json @@ -1,7 +1,6 @@ { "testCases": [ "cases/query-input.json", - "cases/query-core-input.json", "cases/query-output.json" ] } \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/json10/customization.config b/test/protocol-tests/src/main/resources/codegen-resources/json10/customization.config new file mode 100644 index 000000000000..bb763afd276b --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/json10/customization.config @@ -0,0 +1,4 @@ +{ + "skipEndpointTestGeneration": true, + "enableGenerateCompiledEndpointRules": true +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-rule-set.json b/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-rule-set.json new file mode 100644 index 000000000000..3793173c26a4 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-rule-set.json @@ -0,0 +1,355 @@ +{ + "version": "1.3", + "parameters": { + "Region": { + "builtIn": "AWS::Region", + "required": true, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + }, + "UseDualStack": { + "builtIn": "AWS::UseDualStack", + "required": true, + "default": false, + "documentation": "When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.", + "type": "Boolean" + }, + "UseFIPS": { + "builtIn": "AWS::UseFIPS", + "required": true, + "default": false, + "documentation": "When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.", + "type": "Boolean" + }, + "Endpoint": { + "builtIn": "SDK::Endpoint", + "required": false, + "documentation": "Override the endpoint used to send this request", + "type": "String" + } + }, + "rules": [ + { + "conditions": [ + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "PartitionResult" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "error": "Invalid Configuration: FIPS and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "error": "Invalid Configuration: Dualstack and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "endpoint": { + "url": { + "ref": "Endpoint" + }, + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "FIPS and DualStack are enabled, but this partition does not support one or both", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query-fips.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [], + "error": "FIPS is enabled but this partition does not support FIPS", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "DualStack is enabled but this partition does not support DualStack", + "type": "error" + } + ] + }, + { + "conditions": [], + "endpoint": { + "url": "https://query.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-tests.json b/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-tests.json new file mode 100644 index 000000000000..f94902ff9d99 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/json10/endpoint-tests.json @@ -0,0 +1,5 @@ +{ + "testCases": [ + ], + "version": "1.0" +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/json10/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/json10/service-2.json new file mode 100644 index 000000000000..ef332190434c --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/json10/service-2.json @@ -0,0 +1,417 @@ +{ + "version": "2.0", + "metadata": { + "apiVersion": "2020-07-14", + "auth": [ + "aws.auth#sigv4" + ], + "endpointPrefix": "jsonrpc10", + "jsonVersion": "1.0", + "protocol": "json", + "protocols": [ + "json" + ], + "serviceFullName": "JsonRpc10", + "serviceId": "JSON RPC 10", + "signatureVersion": "v4", + "signingName": "JsonRpc10", + "targetPrefix": "JsonRpc10", + "uid": "json-rpc-10-2020-07-14" + }, + "operations": { + "ContentTypeParameters": { + "name": "ContentTypeParameters", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "ContentTypeParametersInput" + }, + "output": { + "shape": "ContentTypeParametersOutput" + }, + "documentation": "

The example tests how servers must support requests containing a Content-Type header with parameters.

" + }, + "EmptyInputAndEmptyOutput": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "EmptyInputAndEmptyOutputInput" + }, + "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.

" + }, + "EndpointOperation": { + "name": "EndpointOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "endpoint": { + "hostPrefix": "foo." + } + }, + "EndpointWithHostLabelOperation": { + "name": "EndpointWithHostLabelOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "EndpointWithHostLabelOperationInput" + }, + "endpoint": { + "hostPrefix": "foo.{label}." + } + }, + "GreetingWithErrors": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "GreetingWithErrorsInput" + }, + "output": { + "shape": "GreetingWithErrorsOutput" + }, + "errors": [ + { + "shape": "InvalidGreeting" + }, + { + "shape": "FooError" + }, + { + "shape": "ComplexError" + } + ], + "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 + }, + "HostWithPathOperation": { + "name": "HostWithPathOperation", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "JsonUnions": { + "name": "JsonUnions", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "JsonUnionsInput" + }, + "output": { + "shape": "JsonUnionsOutput" + }, + "documentation": "

This operation uses unions for inputs and outputs.

", + "idempotent": true + }, + "NoInputAndNoOutput": { + "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.

" + }, + "NoInputAndOutput": { + "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.

" + }, + "PutWithContentEncoding": { + "name": "PutWithContentEncoding", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "PutWithContentEncodingInput" + }, + "requestcompression": { + "encodings": [ + "gzip" + ] + } + }, + "QueryIncompatibleOperation": { + "name": "QueryIncompatibleOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "idempotent": true + }, + "SimpleScalarProperties": { + "name": "SimpleScalarProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "SimpleScalarPropertiesInput" + }, + "output": { + "shape": "SimpleScalarPropertiesOutput" + } + } + }, + "shapes": { + "Blob": { + "type": "blob" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "documentation": "

This error is thrown when a request is invalid.

", + "exception": true + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + }, + "ContentTypeParametersInput": { + "type": "structure", + "members": { + "value": { + "shape": "Integer" + } + } + }, + "ContentTypeParametersOutput": { + "type": "structure", + "members": {} + }, + "Double": { + "type": "double", + "box": true + }, + "EmptyInputAndEmptyOutputInput": { + "type": "structure", + "members": {} + }, + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + }, + "EndpointWithHostLabelOperationInput": { + "type": "structure", + "required": [ + "label" + ], + "members": { + "label": { + "shape": "String", + "hostLabel": true + } + } + }, + "Float": { + "type": "float", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "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 + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "GreetingWithErrorsInput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + } + }, + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + } + }, + "Integer": { + "type": "integer", + "box": true + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "documentation": "

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

", + "exception": true + }, + "JsonUnionsInput": { + "type": "structure", + "members": { + "contents": { + "shape": "MyUnion" + } + } + }, + "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 + }, + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + }, + "PutWithContentEncodingInput": { + "type": "structure", + "members": { + "encoding": { + "shape": "String" + }, + "data": { + "shape": "String" + } + } + }, + "SimpleScalarPropertiesInput": { + "type": "structure", + "members": { + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + } + } + }, + "SimpleScalarPropertiesOutput": { + "type": "structure", + "members": { + "floatValue": { + "shape": "Float" + }, + "doubleValue": { + "shape": "Double" + } + } + }, + "String": { + "type": "string" + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "Timestamp": { + "type": "timestamp" + } + } +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/customization.config b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/customization.config new file mode 100644 index 000000000000..bb763afd276b --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/customization.config @@ -0,0 +1,4 @@ +{ + "skipEndpointTestGeneration": true, + "enableGenerateCompiledEndpointRules": true +} diff --git a/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-rule-set.json b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-rule-set.json new file mode 100644 index 000000000000..3793173c26a4 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-rule-set.json @@ -0,0 +1,355 @@ +{ + "version": "1.3", + "parameters": { + "Region": { + "builtIn": "AWS::Region", + "required": true, + "documentation": "The AWS region used to dispatch the request.", + "type": "String" + }, + "UseDualStack": { + "builtIn": "AWS::UseDualStack", + "required": true, + "default": false, + "documentation": "When true, use the dual-stack endpoint. If the configured endpoint does not support dual-stack, dispatching the request MAY return an error.", + "type": "Boolean" + }, + "UseFIPS": { + "builtIn": "AWS::UseFIPS", + "required": true, + "default": false, + "documentation": "When true, send this request to the FIPS-compliant regional endpoint. If the configured endpoint does not have a FIPS compliant endpoint, dispatching the request will return an error.", + "type": "Boolean" + }, + "Endpoint": { + "builtIn": "SDK::Endpoint", + "required": false, + "documentation": "Override the endpoint used to send this request", + "type": "String" + } + }, + "rules": [ + { + "conditions": [ + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "PartitionResult" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "error": "Invalid Configuration: FIPS and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "error": "Invalid Configuration: Dualstack and custom endpoint are not supported", + "type": "error" + }, + { + "conditions": [], + "endpoint": { + "url": { + "ref": "Endpoint" + }, + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query-fips.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "FIPS and DualStack are enabled, but this partition does not support one or both", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsFIPS" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query-fips.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] + }, + { + "conditions": [], + "error": "FIPS is enabled but this partition does not support FIPS", + "type": "error" + } + ] + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + true, + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "supportsDualStack" + ] + } + ] + } + ], + "type": "tree", + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://query.{Region}.{PartitionResult#dualStackDnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + }, + { + "conditions": [], + "error": "DualStack is enabled but this partition does not support DualStack", + "type": "error" + } + ] + }, + { + "conditions": [], + "endpoint": { + "url": "https://query.{Region}.{PartitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingRegion": "{Region}", + "signingName": "query" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ] + } + ] +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-tests.json b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-tests.json new file mode 100644 index 000000000000..f94902ff9d99 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/endpoint-tests.json @@ -0,0 +1,5 @@ +{ + "testCases": [ + ], + "version": "1.0" +} \ No newline at end of file diff --git a/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/service-2.json b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/service-2.json new file mode 100644 index 000000000000..1ef0af0526a2 --- /dev/null +++ b/test/protocol-tests/src/main/resources/codegen-resources/smithy-query/service-2.json @@ -0,0 +1,1230 @@ +{ + "version": "2.0", + "metadata": { + "apiVersion": "2020-01-08", + "auth": [ + "aws.auth#sigv4" + ], + "endpointPrefix": "awsquery", + "protocol": "query", + "protocols": [ + "query" + ], + "serviceFullName": "AwsQuery", + "serviceId": "Query Protocol", + "signatureVersion": "v4", + "signingName": "AwsQuery", + "uid": "query-protocol-2020-01-08" + }, + "operations": { + "DatetimeOffsets": { + "name": "DatetimeOffsets", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "DatetimeOffsetsOutput", + "resultWrapper": "DatetimeOffsetsResult" + } + }, + "EmptyInputAndEmptyOutput": { + "name": "EmptyInputAndEmptyOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "EmptyInputAndEmptyOutputInput" + }, + "output": { + "shape": "EmptyInputAndEmptyOutputOutput", + "resultWrapper": "EmptyInputAndEmptyOutputResult" + } + }, + "EndpointOperation": { + "name": "EndpointOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "endpoint": { + "hostPrefix": "foo." + } + }, + "EndpointWithHostLabelOperation": { + "name": "EndpointWithHostLabelOperation", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "HostLabelInput" + }, + "endpoint": { + "hostPrefix": "foo.{label}." + } + }, + "FlattenedXmlMap": { + "name": "FlattenedXmlMap", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapOutput", + "resultWrapper": "FlattenedXmlMapResult" + } + }, + "FlattenedXmlMapWithXmlName": { + "name": "FlattenedXmlMapWithXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNameOutput", + "resultWrapper": "FlattenedXmlMapWithXmlNameResult" + } + }, + "FlattenedXmlMapWithXmlNamespace": { + "name": "FlattenedXmlMapWithXmlNamespace", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FlattenedXmlMapWithXmlNamespaceOutput", + "resultWrapper": "FlattenedXmlMapWithXmlNamespaceResult" + } + }, + "FractionalSeconds": { + "name": "FractionalSeconds", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "FractionalSecondsOutput", + "resultWrapper": "FractionalSecondsResult" + } + }, + "GreetingWithErrors": { + "name": "GreetingWithErrors", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "GreetingWithErrorsOutput", + "resultWrapper": "GreetingWithErrorsResult" + }, + "errors": [ + { + "shape": "InvalidGreeting" + }, + { + "shape": "CustomCodeError" + }, + { + "shape": "ComplexError" + } + ] + }, + "HostWithPathOperation": { + "name": "HostWithPathOperation", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "IgnoresWrappingXmlName": { + "name": "IgnoresWrappingXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "IgnoresWrappingXmlNameOutput", + "resultWrapper": "IgnoresWrappingXmlNameResult" + } + }, + "NestedStructures": { + "name": "NestedStructures", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "NestedStructuresInput" + } + }, + "NoInputAndNoOutput": { + "name": "NoInputAndNoOutput", + "http": { + "method": "POST", + "requestUri": "/" + } + }, + "NoInputAndOutput": { + "name": "NoInputAndOutput", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "NoInputAndOutputInput" + }, + "output": { + "shape": "NoInputAndOutputOutput", + "resultWrapper": "NoInputAndOutputResult" + } + }, + "PutWithContentEncoding": { + "name": "PutWithContentEncoding", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "PutWithContentEncodingInput" + }, + "requestcompression": { + "encodings": [ + "gzip" + ] + } + }, + "QueryIdempotencyTokenAutoFill": { + "name": "QueryIdempotencyTokenAutoFill", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "QueryIdempotencyTokenAutoFillInput" + } + }, + "QueryLists": { + "name": "QueryLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "QueryListsInput" + } + }, + "QueryMaps": { + "name": "QueryMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "QueryMapsInput" + } + }, + "QueryTimestamps": { + "name": "QueryTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "QueryTimestampsInput" + } + }, + "RecursiveXmlShapes": { + "name": "RecursiveXmlShapes", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "RecursiveXmlShapesOutput", + "resultWrapper": "RecursiveXmlShapesResult" + } + }, + "SimpleInputParams": { + "name": "SimpleInputParams", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "SimpleInputParamsInput" + } + }, + "SimpleScalarXmlProperties": { + "name": "SimpleScalarXmlProperties", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "SimpleScalarXmlPropertiesOutput", + "resultWrapper": "SimpleScalarXmlPropertiesResult" + } + }, + "XmlBlobs": { + "name": "XmlBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput", + "resultWrapper": "XmlBlobsResult" + } + }, + "XmlEmptyBlobs": { + "name": "XmlEmptyBlobs", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlBlobsOutput", + "resultWrapper": "XmlEmptyBlobsResult" + } + }, + "XmlEmptyLists": { + "name": "XmlEmptyLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput", + "resultWrapper": "XmlEmptyListsResult" + } + }, + "XmlEmptyMaps": { + "name": "XmlEmptyMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsOutput", + "resultWrapper": "XmlEmptyMapsResult" + } + }, + "XmlEnums": { + "name": "XmlEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlEnumsOutput", + "resultWrapper": "XmlEnumsResult" + } + }, + "XmlIntEnums": { + "name": "XmlIntEnums", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlIntEnumsOutput", + "resultWrapper": "XmlIntEnumsResult" + } + }, + "XmlLists": { + "name": "XmlLists", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlListsOutput", + "resultWrapper": "XmlListsResult" + } + }, + "XmlMaps": { + "name": "XmlMaps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsOutput", + "resultWrapper": "XmlMapsResult" + } + }, + "XmlMapsXmlName": { + "name": "XmlMapsXmlName", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlMapsXmlNameOutput", + "resultWrapper": "XmlMapsXmlNameResult" + } + }, + "XmlNamespaces": { + "name": "XmlNamespaces", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlNamespacesOutput", + "resultWrapper": "XmlNamespacesResult" + } + }, + "XmlTimestamps": { + "name": "XmlTimestamps", + "http": { + "method": "POST", + "requestUri": "/" + }, + "output": { + "shape": "XmlTimestampsOutput", + "resultWrapper": "XmlTimestampsResult" + } + } + }, + "shapes": { + "Blob": { + "type": "blob" + }, + "Boolean": { + "type": "boolean", + "box": true + }, + "BooleanList": { + "type": "list", + "member": { + "shape": "Boolean" + } + }, + "ComplexError": { + "type": "structure", + "members": { + "TopLevel": { + "shape": "String" + }, + "Nested": { + "shape": "ComplexNestedErrorData" + } + }, + "exception": true + }, + "ComplexMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "ComplexNestedErrorData": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + } + } + }, + "CustomCodeError": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "error": { + "code": "Customized", + "httpStatusCode": 402, + "senderFault": true + }, + "exception": true + }, + "DateTime": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "DatetimeOffsetsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "Double": { + "type": "double", + "box": true + }, + "EmptyInputAndEmptyOutputInput": { + "type": "structure", + "members": {} + }, + "EmptyInputAndEmptyOutputOutput": { + "type": "structure", + "members": {} + }, + "EpochSeconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "FlattenedXmlMapOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FooEnumMap", + "flattened": true + } + } + }, + "FlattenedXmlMapWithXmlNameOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "FlattenedXmlMapWithXmlNameOutputMap", + "flattened": true, + "locationName": "KVP" + } + } + }, + "FlattenedXmlMapWithXmlNameOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K" + }, + "value": { + "shape": "String", + "locationName": "V" + } + }, + "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" + } + }, + "Float": { + "type": "float", + "box": true + }, + "FooEnum": { + "type": "string", + "enum": [ + "Foo", + "Baz", + "Bar", + "1", + "0" + ] + }, + "FooEnumList": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FooEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "FooEnum" + } + }, + "FooEnumSet": { + "type": "list", + "member": { + "shape": "FooEnum" + } + }, + "FractionalSecondsOutput": { + "type": "structure", + "members": { + "datetime": { + "shape": "DateTime" + } + } + }, + "GreetingList": { + "type": "list", + "member": { + "shape": "GreetingStruct" + } + }, + "GreetingStruct": { + "type": "structure", + "members": { + "hi": { + "shape": "String" + } + } + }, + "GreetingWithErrorsOutput": { + "type": "structure", + "members": { + "greeting": { + "shape": "String" + } + } + }, + "HostLabelInput": { + "type": "structure", + "required": [ + "label" + ], + "members": { + "label": { + "shape": "String", + "hostLabel": true + } + } + }, + "HttpDate": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "IgnoresWrappingXmlNameOutput": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + } + }, + "locationName": "IgnoreMe" + }, + "Integer": { + "type": "integer", + "box": true + }, + "IntegerEnum": { + "type": "integer", + "box": true + }, + "IntegerEnumList": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "IntegerEnum" + } + }, + "IntegerEnumSet": { + "type": "list", + "member": { + "shape": "IntegerEnum" + } + }, + "IntegerList": { + "type": "list", + "member": { + "shape": "Integer" + } + }, + "InvalidGreeting": { + "type": "structure", + "members": { + "Message": { + "shape": "String" + } + }, + "exception": true + }, + "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" + }, + "ListWithXmlName": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "Long": { + "type": "long", + "box": true + }, + "MapOfLists": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "StringList" + } + }, + "MapWithXmlName": { + "type": "map", + "key": { + "shape": "String", + "locationName": "K" + }, + "value": { + "shape": "String", + "locationName": "V" + } + }, + "NestedStringList": { + "type": "list", + "member": { + "shape": "StringList" + } + }, + "NestedStructWithList": { + "type": "structure", + "members": { + "ListArg": { + "shape": "StringList" + } + } + }, + "NestedStructWithMap": { + "type": "structure", + "members": { + "MapArg": { + "shape": "StringMap" + } + } + }, + "NestedStructuresInput": { + "type": "structure", + "members": { + "Nested": { + "shape": "StructArg" + } + } + }, + "NoInputAndOutputInput": { + "type": "structure", + "members": {} + }, + "NoInputAndOutputOutput": { + "type": "structure", + "members": {} + }, + "PutWithContentEncodingInput": { + "type": "structure", + "members": { + "encoding": { + "shape": "String" + }, + "data": { + "shape": "String" + } + } + }, + "QueryIdempotencyTokenAutoFillInput": { + "type": "structure", + "members": { + "token": { + "shape": "String", + "idempotencyToken": true + } + } + }, + "QueryListsInput": { + "type": "structure", + "members": { + "ListArg": { + "shape": "StringList" + }, + "ComplexListArg": { + "shape": "GreetingList" + }, + "FlattenedListArg": { + "shape": "StringList", + "flattened": true + }, + "ListArgWithXmlNameMember": { + "shape": "ListWithXmlName" + }, + "FlattenedListArgWithXmlName": { + "shape": "ListWithXmlName", + "flattened": true, + "locationName": "Hi" + }, + "NestedWithList": { + "shape": "NestedStructWithList" + } + } + }, + "QueryMapsInput": { + "type": "structure", + "members": { + "MapArg": { + "shape": "StringMap" + }, + "RenamedMapArg": { + "shape": "StringMap", + "locationName": "Foo" + }, + "ComplexMapArg": { + "shape": "ComplexMap" + }, + "MapWithXmlMemberName": { + "shape": "MapWithXmlName" + }, + "FlattenedMap": { + "shape": "StringMap", + "flattened": true + }, + "FlattenedMapWithXmlName": { + "shape": "MapWithXmlName", + "flattened": true, + "locationName": "Hi" + }, + "MapOfLists": { + "shape": "MapOfLists" + }, + "NestedStructWithMap": { + "shape": "NestedStructWithMap" + } + } + }, + "QueryTimestampsInput": { + "type": "structure", + "members": { + "normalFormat": { + "shape": "Timestamp" + }, + "epochMember": { + "shape": "SyntheticTimestamp_epoch_seconds" + }, + "epochTarget": { + "shape": "EpochSeconds" + } + } + }, + "RecursiveXmlShapesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + }, + "RecursiveXmlShapesOutputNested1": { + "type": "structure", + "members": { + "foo": { + "shape": "String" + }, + "nested": { + "shape": "RecursiveXmlShapesOutputNested2" + } + } + }, + "RecursiveXmlShapesOutputNested2": { + "type": "structure", + "members": { + "bar": { + "shape": "String" + }, + "recursiveMember": { + "shape": "RecursiveXmlShapesOutputNested1" + } + } + }, + "RenamedListMembers": { + "type": "list", + "member": { + "shape": "String", + "locationName": "item" + } + }, + "SimpleInputParamsInput": { + "type": "structure", + "members": { + "Foo": { + "shape": "String" + }, + "Bar": { + "shape": "String" + }, + "Baz": { + "shape": "Boolean" + }, + "Bam": { + "shape": "Integer" + }, + "FloatValue": { + "shape": "Float" + }, + "Boo": { + "shape": "Double" + }, + "Qux": { + "shape": "Blob" + }, + "FooEnum": { + "shape": "FooEnum" + }, + "IntegerEnum": { + "shape": "IntegerEnum" + } + } + }, + "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" + }, + "StringList": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StringMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "String" + } + }, + "StringSet": { + "type": "list", + "member": { + "shape": "String" + } + }, + "StructArg": { + "type": "structure", + "members": { + "StringArg": { + "shape": "String" + }, + "OtherArg": { + "shape": "Boolean" + }, + "RecursiveArg": { + "shape": "StructArg" + } + } + }, + "StructureList": { + "type": "list", + "member": { + "shape": "StructureListMember", + "locationName": "item" + } + }, + "StructureListMember": { + "type": "structure", + "members": { + "a": { + "shape": "String", + "locationName": "value" + }, + "b": { + "shape": "String", + "locationName": "other" + } + } + }, + "SyntheticTimestamp_date_time": { + "type": "timestamp", + "timestampFormat": "iso8601" + }, + "SyntheticTimestamp_epoch_seconds": { + "type": "timestamp", + "timestampFormat": "unixTimestamp" + }, + "SyntheticTimestamp_http_date": { + "type": "timestamp", + "timestampFormat": "rfc822" + }, + "Timestamp": { + "type": "timestamp" + }, + "TimestampList": { + "type": "list", + "member": { + "shape": "Timestamp" + } + }, + "XmlBlobsOutput": { + "type": "structure", + "members": { + "data": { + "shape": "Blob" + } + } + }, + "XmlEnumsOutput": { + "type": "structure", + "members": { + "fooEnum1": { + "shape": "FooEnum" + }, + "fooEnum2": { + "shape": "FooEnum" + }, + "fooEnum3": { + "shape": "FooEnum" + }, + "fooEnumList": { + "shape": "FooEnumList" + }, + "fooEnumSet": { + "shape": "FooEnumSet" + }, + "fooEnumMap": { + "shape": "FooEnumMap" + } + } + }, + "XmlIntEnumsOutput": { + "type": "structure", + "members": { + "intEnum1": { + "shape": "IntegerEnum" + }, + "intEnum2": { + "shape": "IntegerEnum" + }, + "intEnum3": { + "shape": "IntegerEnum" + }, + "intEnumList": { + "shape": "IntegerEnumList" + }, + "intEnumSet": { + "shape": "IntegerEnumSet" + }, + "intEnumMap": { + "shape": "IntegerEnumMap" + } + } + }, + "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" + } + } + }, + "XmlMapsOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsOutputMap" + } + } + }, + "XmlMapsOutputMap": { + "type": "map", + "key": { + "shape": "String" + }, + "value": { + "shape": "GreetingStruct" + } + }, + "XmlMapsXmlNameOutput": { + "type": "structure", + "members": { + "myMap": { + "shape": "XmlMapsXmlNameOutputMap" + } + } + }, + "XmlMapsXmlNameOutputMap": { + "type": "map", + "key": { + "shape": "String", + "locationName": "Attribute" + }, + "value": { + "shape": "GreetingStruct", + "locationName": "Setting" + } + }, + "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" + }, + "XmlNamespacedList": { + "type": "list", + "member": { + "shape": "String", + "xmlNamespace": "http://bux.com" + } + }, + "XmlNamespacesOutput": { + "type": "structure", + "members": { + "nested": { + "shape": "XmlNamespaceNested" + } + }, + "xmlNamespace": "http://foo.com" + }, + "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" + } + } + } + } +} \ No newline at end of file diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/Json10ProtocolTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/Json10ProtocolTest.java new file mode 100644 index 000000000000..6fb90767eabb --- /dev/null +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/Json10ProtocolTest.java @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.protocol.tests; + +import java.io.IOException; +import java.util.List; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import software.amazon.awssdk.protocol.ProtocolTestSuiteLoader; +import software.amazon.awssdk.protocol.model.TestCase; +import software.amazon.awssdk.protocol.runners.ProtocolTestRunner; + +@RunWith(Parameterized.class) +public class Json10ProtocolTest extends ProtocolTestBase { + + private static final ProtocolTestSuiteLoader testSuiteLoader = new ProtocolTestSuiteLoader(); + private static ProtocolTestRunner testRunner; + + @Parameterized.Parameter + public TestCase testCase; + + @Parameterized.Parameters(name = "{0}") + public static List data() throws IOException { + return testSuiteLoader.load("json10-suite.json"); + } + + @BeforeClass + public static void setupFixture() { + testRunner = new ProtocolTestRunner("/models/jsonrpc10-2020-07-14-intermediate.json"); + } + + @Test + public void runProtocolTest() throws Exception { + testRunner.runTest(testCase); + } +} diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryProtocolTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryProtocolTest.java index 4fe8da63130c..9f96bfb1687f 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryProtocolTest.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/QueryProtocolTest.java @@ -41,7 +41,7 @@ public static List data() throws IOException { @BeforeClass public static void setupFixture() { - testRunner = new ProtocolTestRunner("/models/query-2016-03-11-intermediate.json"); + testRunner = new ProtocolTestRunner("/models/awsquery-2020-01-08-intermediate.json"); } @Test