diff --git a/.changes/next-release/feature-AWSSDKforJavav2-f004fae.json b/.changes/next-release/feature-AWSSDKforJavav2-f004fae.json new file mode 100644 index 000000000000..184769e3f85c --- /dev/null +++ b/.changes/next-release/feature-AWSSDKforJavav2-f004fae.json @@ -0,0 +1,6 @@ +{ + "type": "feature", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Add support for validating that shared models between two services are identical." +} diff --git a/codegen/pom.xml b/codegen/pom.xml index bb9c7874c6a8..d539fc07f4d4 100644 --- a/codegen/pom.xml +++ b/codegen/pom.xml @@ -239,5 +239,10 @@ mockito-core compile + + nl.jqno.equalsverifier + equalsverifier + test + diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/CodeGenerator.java b/codegen/src/main/java/software/amazon/awssdk/codegen/CodeGenerator.java index 0bcdbccb4d04..b96b62436ea6 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/CodeGenerator.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/CodeGenerator.java @@ -32,6 +32,7 @@ import software.amazon.awssdk.codegen.validation.ModelValidationContext; import software.amazon.awssdk.codegen.validation.ModelValidationReport; import software.amazon.awssdk.codegen.validation.ModelValidator; +import software.amazon.awssdk.codegen.validation.SharedModelsValidator; import software.amazon.awssdk.codegen.validation.ValidationEntry; import software.amazon.awssdk.utils.Logger; @@ -39,8 +40,9 @@ public class CodeGenerator { private static final Logger log = Logger.loggerFor(CodeGenerator.class); private static final String MODEL_DIR_NAME = "models"; - // TODO: add validators - private static final List DEFAULT_MODEL_VALIDATORS = Collections.emptyList(); + private static final List DEFAULT_MODEL_VALIDATORS = Collections.singletonList( + new SharedModelsValidator() + ); private final C2jModels c2jModels; diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModel.java index 5013db7d3f9e..16e848303a4f 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModel.java @@ -15,6 +15,8 @@ package software.amazon.awssdk.codegen.model.intermediate; +import java.util.Objects; + public class ArgumentModel extends DocumentationModel { private String name; @@ -61,4 +63,28 @@ public ArgumentModel withIsEnumArg(boolean isEnumArg) { this.isEnumArg = isEnumArg; return this; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + ArgumentModel that = (ArgumentModel) o; + return isEnumArg == that.isEnumArg + && Objects.equals(name, that.name) + && Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(name); + result = 31 * result + Objects.hashCode(type); + result = 31 * result + Boolean.hashCode(isEnumArg); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModel.java index ce98c0dfea8e..316f4e741139 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModel.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.codegen.model.intermediate; import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Objects; import software.amazon.awssdk.codegen.model.service.Location; public class AuthorizerModel extends DocumentationModel { @@ -63,4 +64,30 @@ public String getAddAuthTokenMethod() { authTokenLocation)); } } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + AuthorizerModel that = (AuthorizerModel) o; + return Objects.equals(name, that.name) + && Objects.equals(interfaceName, that.interfaceName) + && authTokenLocation == that.authTokenLocation + && Objects.equals(tokenName, that.tokenName); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(name); + result = 31 * result + Objects.hashCode(interfaceName); + result = 31 * result + Objects.hashCode(authTokenLocation); + result = 31 * result + Objects.hashCode(tokenName); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/DocumentationModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/DocumentationModel.java index 5be891040acc..55fd39f4a7c7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/DocumentationModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/DocumentationModel.java @@ -17,6 +17,8 @@ import static software.amazon.awssdk.codegen.internal.DocumentationUtils.escapeIllegalCharacters; +import java.util.Objects; + public class DocumentationModel { protected String documentation; @@ -28,4 +30,22 @@ public String getDocumentation() { public void setDocumentation(String documentation) { this.documentation = escapeIllegalCharacters(documentation); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DocumentationModel that = (DocumentationModel) o; + return Objects.equals(documentation, that.documentation); + } + + @Override + public int hashCode() { + return Objects.hashCode(documentation); + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EndpointDiscovery.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EndpointDiscovery.java index 91a5f3b60f25..e372079fc541 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EndpointDiscovery.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EndpointDiscovery.java @@ -26,4 +26,22 @@ public boolean isRequired() { public void setRequired(boolean required) { this.required = required; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + EndpointDiscovery that = (EndpointDiscovery) o; + return required == that.required; + } + + @Override + public int hashCode() { + return Boolean.hashCode(required); + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EnumModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EnumModel.java index f469b5de99fd..652f2c2aca6e 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EnumModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/EnumModel.java @@ -15,6 +15,8 @@ package software.amazon.awssdk.codegen.model.intermediate; +import java.util.Objects; + /** * Represents a single enum field in a enum. */ @@ -49,4 +51,23 @@ public String getValue() { return value; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + EnumModel enumModel = (EnumModel) o; + return Objects.equals(value, enumModel.value) && Objects.equals(name, enumModel.name); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(value); + result = 31 * result + Objects.hashCode(name); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java index fddf93d4d72d..3e905aa1ed56 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java @@ -28,6 +28,7 @@ import com.squareup.javapoet.ClassName; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import software.amazon.awssdk.codegen.internal.TypeUtils; import software.amazon.awssdk.codegen.model.service.ContextParam; @@ -785,4 +786,98 @@ public void ignoreDataTypeConversionFailures(boolean ignoreDataTypeConversionFai public boolean ignoreDataTypeConversionFailures() { return ignoreDataTypeConversionFailures; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + MemberModel that = (MemberModel) o; + return deprecated == that.deprecated + && required == that.required + && synthetic == that.synthetic + && idempotencyToken == that.idempotencyToken + && isJsonValue == that.isJsonValue + && eventPayload == that.eventPayload + && eventHeader == that.eventHeader + && endpointDiscoveryId == that.endpointDiscoveryId + && sensitive == that.sensitive + && xmlAttribute == that.xmlAttribute + && ignoreDataTypeConversionFailures == that.ignoreDataTypeConversionFailures + && Objects.equals(name, that.name) + && Objects.equals(c2jName, that.c2jName) + && Objects.equals(c2jShape, that.c2jShape) + && Objects.equals(variable, that.variable) + && Objects.equals(setterModel, that.setterModel) + && Objects.equals(getterModel, that.getterModel) + && Objects.equals(http, that.http) + && Objects.equals(deprecatedMessage, that.deprecatedMessage) + && Objects.equals(listModel, that.listModel) + && Objects.equals(mapModel, that.mapModel) + && Objects.equals(enumType, that.enumType) + && Objects.equals(xmlNameSpaceUri, that.xmlNameSpaceUri) + && Objects.equals(shape, that.shape) + && Objects.equals(fluentGetterMethodName, that.fluentGetterMethodName) + && Objects.equals(fluentEnumGetterMethodName, that.fluentEnumGetterMethodName) + && Objects.equals(fluentSetterMethodName, that.fluentSetterMethodName) + && Objects.equals(fluentEnumSetterMethodName, that.fluentEnumSetterMethodName) + && Objects.equals(existenceCheckMethodName, that.existenceCheckMethodName) + && Objects.equals(beanStyleGetterName, that.beanStyleGetterName) + && Objects.equals(beanStyleSetterName, that.beanStyleSetterName) + && Objects.equals(unionEnumTypeName, that.unionEnumTypeName) + && Objects.equals(timestampFormat, that.timestampFormat) + && Objects.equals(deprecatedName, that.deprecatedName) + && Objects.equals(fluentDeprecatedGetterMethodName, that.fluentDeprecatedGetterMethodName) + && Objects.equals(fluentDeprecatedSetterMethodName, that.fluentDeprecatedSetterMethodName) + && Objects.equals(deprecatedBeanStyleSetterMethodName, that.deprecatedBeanStyleSetterMethodName) + && Objects.equals(contextParam, that.contextParam); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(name); + result = 31 * result + Objects.hashCode(c2jName); + result = 31 * result + Objects.hashCode(c2jShape); + result = 31 * result + Objects.hashCode(variable); + result = 31 * result + Objects.hashCode(setterModel); + result = 31 * result + Objects.hashCode(getterModel); + result = 31 * result + Objects.hashCode(http); + result = 31 * result + Boolean.hashCode(deprecated); + result = 31 * result + Objects.hashCode(deprecatedMessage); + result = 31 * result + Boolean.hashCode(required); + result = 31 * result + Boolean.hashCode(synthetic); + result = 31 * result + Objects.hashCode(listModel); + result = 31 * result + Objects.hashCode(mapModel); + result = 31 * result + Objects.hashCode(enumType); + result = 31 * result + Objects.hashCode(xmlNameSpaceUri); + result = 31 * result + Boolean.hashCode(idempotencyToken); + result = 31 * result + Objects.hashCode(shape); + result = 31 * result + Objects.hashCode(fluentGetterMethodName); + result = 31 * result + Objects.hashCode(fluentEnumGetterMethodName); + result = 31 * result + Objects.hashCode(fluentSetterMethodName); + result = 31 * result + Objects.hashCode(fluentEnumSetterMethodName); + result = 31 * result + Objects.hashCode(existenceCheckMethodName); + result = 31 * result + Objects.hashCode(beanStyleGetterName); + result = 31 * result + Objects.hashCode(beanStyleSetterName); + result = 31 * result + Objects.hashCode(unionEnumTypeName); + result = 31 * result + Boolean.hashCode(isJsonValue); + result = 31 * result + Objects.hashCode(timestampFormat); + result = 31 * result + Boolean.hashCode(eventPayload); + result = 31 * result + Boolean.hashCode(eventHeader); + result = 31 * result + Boolean.hashCode(endpointDiscoveryId); + result = 31 * result + Boolean.hashCode(sensitive); + result = 31 * result + Boolean.hashCode(xmlAttribute); + result = 31 * result + Objects.hashCode(deprecatedName); + result = 31 * result + Objects.hashCode(fluentDeprecatedGetterMethodName); + result = 31 * result + Objects.hashCode(fluentDeprecatedSetterMethodName); + result = 31 * result + Objects.hashCode(deprecatedBeanStyleSetterMethodName); + result = 31 * result + Objects.hashCode(contextParam); + result = 31 * result + Boolean.hashCode(ignoreDataTypeConversionFailures); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/OperationModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/OperationModel.java index a2a060c7a915..6b192644da1d 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/OperationModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/OperationModel.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import software.amazon.awssdk.codegen.checksum.HttpChecksum; import software.amazon.awssdk.codegen.compression.RequestCompression; import software.amazon.awssdk.codegen.docs.ClientType; @@ -379,4 +380,63 @@ public boolean isUnsignedPayload() { public void setUnsignedPayload(boolean unsignedPayload) { this.unsignedPayload = unsignedPayload; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + OperationModel that = (OperationModel) o; + return deprecated == that.deprecated && hasBlobMemberAsPayload == that.hasBlobMemberAsPayload + && hasStringMemberAsPayload == that.hasStringMemberAsPayload && isAuthenticated == that.isAuthenticated + && isPaginated == that.isPaginated && endpointOperation == that.endpointOperation + && endpointCacheRequired == that.endpointCacheRequired && httpChecksumRequired == that.httpChecksumRequired + && unsignedPayload == that.unsignedPayload && Objects.equals(operationName, that.operationName) + && Objects.equals(serviceProtocol, that.serviceProtocol) + && Objects.equals(deprecatedMessage, that.deprecatedMessage) && Objects.equals(input, that.input) + && Objects.equals(returnType, that.returnType) && Objects.equals(exceptions, that.exceptions) + && Objects.equals(simpleMethods, that.simpleMethods) && authType == that.authType + && Objects.equals(auth, that.auth) && Objects.equals(endpointDiscovery, that.endpointDiscovery) + && Objects.equals(inputShape, that.inputShape) && Objects.equals(outputShape, that.outputShape) + && Objects.equals(endpointTrait, that.endpointTrait) && Objects.equals(httpChecksum, that.httpChecksum) + && Objects.equals(requestcompression, that.requestcompression) + && Objects.equals(staticContextParams, that.staticContextParams) + && Objects.equals(operationContextParams, that.operationContextParams); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(operationName); + result = 31 * result + Objects.hashCode(serviceProtocol); + result = 31 * result + Boolean.hashCode(deprecated); + result = 31 * result + Objects.hashCode(deprecatedMessage); + result = 31 * result + Objects.hashCode(input); + result = 31 * result + Objects.hashCode(returnType); + result = 31 * result + Objects.hashCode(exceptions); + result = 31 * result + Objects.hashCode(simpleMethods); + result = 31 * result + Boolean.hashCode(hasBlobMemberAsPayload); + result = 31 * result + Boolean.hashCode(hasStringMemberAsPayload); + result = 31 * result + Boolean.hashCode(isAuthenticated); + result = 31 * result + Objects.hashCode(authType); + result = 31 * result + Objects.hashCode(auth); + result = 31 * result + Boolean.hashCode(isPaginated); + result = 31 * result + Boolean.hashCode(endpointOperation); + result = 31 * result + Boolean.hashCode(endpointCacheRequired); + result = 31 * result + Objects.hashCode(endpointDiscovery); + result = 31 * result + Objects.hashCode(inputShape); + result = 31 * result + Objects.hashCode(outputShape); + result = 31 * result + Objects.hashCode(endpointTrait); + result = 31 * result + Boolean.hashCode(httpChecksumRequired); + result = 31 * result + Objects.hashCode(httpChecksum); + result = 31 * result + Objects.hashCode(requestcompression); + result = 31 * result + Objects.hashCode(staticContextParams); + result = 31 * result + Objects.hashCode(operationContextParams); + result = 31 * result + Boolean.hashCode(unsignedPayload); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMapping.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMapping.java index 22ed4a8e6880..fc9a776059a7 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMapping.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMapping.java @@ -15,6 +15,7 @@ package software.amazon.awssdk.codegen.model.intermediate; +import java.util.Objects; import software.amazon.awssdk.codegen.model.service.Location; import software.amazon.awssdk.core.protocol.MarshallLocation; @@ -199,4 +200,40 @@ public MarshallLocation getMarshallLocation() { } } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ParameterHttpMapping that = (ParameterHttpMapping) o; + return isPayload == that.isPayload + && isStreaming == that.isStreaming + && flattened == that.flattened + && isGreedy == that.isGreedy + && requiresLength == that.requiresLength + && Objects.equals(unmarshallLocationName, that.unmarshallLocationName) + && Objects.equals(marshallLocationName, that.marshallLocationName) + && Objects.equals(additionalUnmarshallingPath, that.additionalUnmarshallingPath) + && Objects.equals(additionalMarshallingPath, that.additionalMarshallingPath) + && location == that.location; + } + + @Override + public int hashCode() { + int result = Objects.hashCode(unmarshallLocationName); + result = 31 * result + Objects.hashCode(marshallLocationName); + result = 31 * result + Objects.hashCode(additionalUnmarshallingPath); + result = 31 * result + Objects.hashCode(additionalMarshallingPath); + result = 31 * result + Boolean.hashCode(isPayload); + result = 31 * result + Boolean.hashCode(isStreaming); + result = 31 * result + Objects.hashCode(location); + result = 31 * result + Boolean.hashCode(flattened); + result = 31 * result + Boolean.hashCode(isGreedy); + result = 31 * result + Boolean.hashCode(requiresLength); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModel.java index 77dff4c71481..1d46c2802cda 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModel.java @@ -15,6 +15,8 @@ package software.amazon.awssdk.codegen.model.intermediate; +import java.util.Objects; + public class ReturnTypeModel { private String returnType; @@ -48,4 +50,24 @@ public ReturnTypeModel withDocumentation(String documentation) { setDocumentation(documentation); return this; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ReturnTypeModel that = (ReturnTypeModel) o; + return Objects.equals(returnType, that.returnType) && Objects.equals(documentation, that.documentation); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(returnType); + result = 31 * result + Objects.hashCode(documentation); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModel.java index 098ea46bc7e4..3c26965302d5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModel.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import software.amazon.awssdk.codegen.model.intermediate.customization.ShapeCustomizationInfo; import software.amazon.awssdk.codegen.model.service.XmlNamespace; @@ -669,4 +670,84 @@ public ShapeModel withIsThrottling(boolean throttling) { this.throttling = throttling; return this; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + ShapeModel that = (ShapeModel) o; + return deprecated == that.deprecated + && hasPayloadMember == that.hasPayloadMember + && hasHeaderMember == that.hasHeaderMember + && hasStatusCodeMember == that.hasStatusCodeMember + && hasStreamingMember == that.hasStreamingMember + && hasRequiresLengthMember == that.hasRequiresLengthMember + && wrapper == that.wrapper + && simpleMethod == that.simpleMethod + && fault == that.fault + && isEventStream == that.isEventStream + && isEvent == that.isEvent + && document == that.document + && union == that.union + && retryable == that.retryable + && throttling == that.throttling + && Objects.equals(c2jName, that.c2jName) + && Objects.equals(shapeName, that.shapeName) + && Objects.equals(deprecatedMessage, that.deprecatedMessage) + && Objects.equals(type, that.type) + && Objects.equals(required, that.required) + && Objects.equals(requestSignerClassFqcn, that.requestSignerClassFqcn) + && Objects.equals(endpointDiscovery, that.endpointDiscovery) + && Objects.equals(members, that.members) + && Objects.equals(enums, that.enums) + && Objects.equals(variable, that.variable) + && Objects.equals(marshaller, that.marshaller) + && Objects.equals(unmarshaller, that.unmarshaller) + && Objects.equals(errorCode, that.errorCode) + && Objects.equals(httpStatusCode, that.httpStatusCode) + && Objects.equals(customization, that.customization) + && Objects.equals(xmlNamespace, that.xmlNamespace); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(c2jName); + result = 31 * result + Objects.hashCode(shapeName); + result = 31 * result + Boolean.hashCode(deprecated); + result = 31 * result + Objects.hashCode(deprecatedMessage); + result = 31 * result + Objects.hashCode(type); + result = 31 * result + Objects.hashCode(required); + result = 31 * result + Boolean.hashCode(hasPayloadMember); + result = 31 * result + Boolean.hashCode(hasHeaderMember); + result = 31 * result + Boolean.hashCode(hasStatusCodeMember); + result = 31 * result + Boolean.hashCode(hasStreamingMember); + result = 31 * result + Boolean.hashCode(hasRequiresLengthMember); + result = 31 * result + Boolean.hashCode(wrapper); + result = 31 * result + Boolean.hashCode(simpleMethod); + result = 31 * result + Objects.hashCode(requestSignerClassFqcn); + result = 31 * result + Objects.hashCode(endpointDiscovery); + result = 31 * result + Objects.hashCode(members); + result = 31 * result + Objects.hashCode(enums); + result = 31 * result + Objects.hashCode(variable); + result = 31 * result + Objects.hashCode(marshaller); + result = 31 * result + Objects.hashCode(unmarshaller); + result = 31 * result + Objects.hashCode(errorCode); + result = 31 * result + Objects.hashCode(httpStatusCode); + result = 31 * result + Boolean.hashCode(fault); + result = 31 * result + Objects.hashCode(customization); + result = 31 * result + Boolean.hashCode(isEventStream); + result = 31 * result + Boolean.hashCode(isEvent); + result = 31 * result + Objects.hashCode(xmlNamespace); + result = 31 * result + Boolean.hashCode(document); + result = 31 * result + Boolean.hashCode(union); + result = 31 * result + Boolean.hashCode(retryable); + result = 31 * result + Boolean.hashCode(throttling); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/VariableModel.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/VariableModel.java index bdf0668a9d21..b9355009e748 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/VariableModel.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/VariableModel.java @@ -17,6 +17,7 @@ import java.util.Collection; import java.util.List; +import java.util.Objects; public class VariableModel extends DocumentationModel { @@ -98,4 +99,31 @@ public String getVariableSetterType() { public String toString() { return variableName; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + VariableModel that = (VariableModel) o; + return Objects.equals(variableName, that.variableName) + && Objects.equals(variableType, that.variableType) + && Objects.equals(variableDeclarationType, that.variableDeclarationType); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + Objects.hashCode(variableName); + result = 31 * result + Objects.hashCode(variableType); + result = 31 * result + Objects.hashCode(variableDeclarationType); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapper.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapper.java index e8adab25b48c..dd0b91d86301 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapper.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapper.java @@ -15,6 +15,8 @@ package software.amazon.awssdk.codegen.model.intermediate.customization; +import java.util.Objects; + public class ArtificialResultWrapper { private String wrappedMemberName; private String wrappedMemberSimpleType; @@ -34,4 +36,25 @@ public String getWrappedMemberSimpleType() { public void setWrappedMemberSimpleType(String wrappedMemberSimpleType) { this.wrappedMemberSimpleType = wrappedMemberSimpleType; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ArtificialResultWrapper that = (ArtificialResultWrapper) o; + return Objects.equals(wrappedMemberName, that.wrappedMemberName) + && Objects.equals(wrappedMemberSimpleType, that.wrappedMemberSimpleType); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(wrappedMemberName); + result = 31 * result + Objects.hashCode(wrappedMemberSimpleType); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfo.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfo.java index b6d3950985b2..2e031eabb9a4 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfo.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfo.java @@ -16,6 +16,7 @@ package software.amazon.awssdk.codegen.model.intermediate.customization; import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Objects; public class ShapeCustomizationInfo { @@ -72,4 +73,33 @@ public void setStaxTargetDepthOffset(int staxTargetDepthOffset) { public boolean hasStaxTargetDepthOffset() { return hasStaxTargetDepthOffset; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ShapeCustomizationInfo that = (ShapeCustomizationInfo) o; + return skipGeneratingModelClass == that.skipGeneratingModelClass + && skipGeneratingMarshaller == that.skipGeneratingMarshaller + && skipGeneratingUnmarshaller == that.skipGeneratingUnmarshaller + && staxTargetDepthOffset == that.staxTargetDepthOffset + && hasStaxTargetDepthOffset == that.hasStaxTargetDepthOffset + && Objects.equals(artificialResultWrapper, that.artificialResultWrapper); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(artificialResultWrapper); + result = 31 * result + Boolean.hashCode(skipGeneratingModelClass); + result = 31 * result + Boolean.hashCode(skipGeneratingMarshaller); + result = 31 * result + Boolean.hashCode(skipGeneratingUnmarshaller); + result = 31 * result + staxTargetDepthOffset; + result = 31 * result + Boolean.hashCode(hasStaxTargetDepthOffset); + return result; + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/ContextParam.java b/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/ContextParam.java index 96f363cd84f1..8650d1145bcb 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/ContextParam.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/model/service/ContextParam.java @@ -15,6 +15,8 @@ package software.amazon.awssdk.codegen.model.service; +import java.util.Objects; + public class ContextParam { private String name; @@ -25,4 +27,22 @@ public String getName() { public void setName(String name) { this.name = name; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ContextParam that = (ContextParam) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/validation/SharedModelsValidator.java b/codegen/src/main/java/software/amazon/awssdk/codegen/validation/SharedModelsValidator.java new file mode 100644 index 000000000000..6b7f8471da7c --- /dev/null +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/validation/SharedModelsValidator.java @@ -0,0 +1,210 @@ +/* + * 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.codegen.validation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.intermediate.ListModel; +import software.amazon.awssdk.codegen.model.intermediate.MapModel; +import software.amazon.awssdk.codegen.model.intermediate.MemberModel; +import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; +import software.amazon.awssdk.utils.Logger; + +/** + * Validator that ensures any shapes shared between two services are completely identical. This validator returns a validation + * entry for each shape that is present in both service models but has differing definitions in each model. + */ +public final class SharedModelsValidator implements ModelValidator { + private static final Logger LOG = Logger.loggerFor(SharedModelsValidator.class); + + @Override + public List validateModels(ModelValidationContext context) { + if (!context.shareModelsTarget().isPresent()) { + return Collections.emptyList(); + } + + return validateSharedShapes(context.intermediateModel(), context.shareModelsTarget().get()); + } + + private List validateSharedShapes(IntermediateModel m1, IntermediateModel m2) { + List errors = new ArrayList<>(); + + Map m1Shapes = m1.getShapes(); + Map m2Shapes = m2.getShapes(); + + m1Shapes.forEach((name, m1Shape) -> { + if (!m2Shapes.containsKey(name)) { + return; + } + + ShapeModel m2Shape = m2Shapes.get(name); + + if (!shapesAreIdentical(m1Shape, m2Shape)) { + String detailMsg = String.format("Services '%s' and '%s' have differing definitions of the shared model '%s'", + m1.getMetadata().getServiceName(), + m2.getMetadata().getServiceName(), + name); + LOG.warn(() -> detailMsg); + + errors.add(new ValidationEntry().withErrorId(ValidationErrorId.SHARED_MODELS_DIFFER) + .withSeverity(ValidationErrorSeverity.DANGER) + .withDetailMessage(detailMsg)); + } + }); + + return errors; + } + + private boolean shapesAreIdentical(ShapeModel m1, ShapeModel m2) { + // Note: We can't simply do m1.equals(m2) because shared models can still differ slightly in the + // marshalling/unmarshalling info such as the exact request operation name on the wire. + // In particular, we leave out comparing the `unmarshaller` and `marshaller` members of ShapeModel. + // Additionally, the List are not compared with equals() because we handle MemberModel equality specially + // as well. + return m1.isDeprecated() == m2.isDeprecated() + && m1.isHasPayloadMember() == m2.isHasPayloadMember() + && m1.isHasHeaderMember() == m2.isHasHeaderMember() + && m1.isHasStatusCodeMember() == m2.isHasStatusCodeMember() + && m1.isHasStreamingMember() == m2.isHasStreamingMember() + && m1.isHasRequiresLengthMember() == m2.isHasRequiresLengthMember() + && m1.isWrapper() == m2.isWrapper() + && m1.isSimpleMethod() == m2.isSimpleMethod() + && m1.isFault() == m2.isFault() + && m1.isEventStream() == m2.isEventStream() + && m1.isEvent() == m2.isEvent() + && m1.isDocument() == m2.isDocument() + && m1.isUnion() == m2.isUnion() + && m1.isRetryable() == m2.isRetryable() + && m1.isThrottling() == m2.isThrottling() + && Objects.equals(m1.getC2jName(), m2.getC2jName()) + && Objects.equals(m1.getShapeName(), m2.getShapeName()) + && Objects.equals(m1.getDeprecatedMessage(), m2.getDeprecatedMessage()) + && Objects.equals(m1.getType(), m2.getType()) + && Objects.equals(m1.getRequired(), m2.getRequired()) + && Objects.equals(m1.getRequestSignerClassFqcn(), m2.getRequestSignerClassFqcn()) + && Objects.equals(m1.getEndpointDiscovery(), m2.getEndpointDiscovery()) + && memberListsAreIdentical(m1.getMembers(), m2.getMembers()) + && Objects.equals(m1.getEnums(), m2.getEnums()) + && Objects.equals(m1.getVariable(), m2.getVariable()) + && Objects.equals(m1.getErrorCode(), m2.getErrorCode()) + && Objects.equals(m1.getHttpStatusCode(), m2.getHttpStatusCode()) + && Objects.equals(m1.getCustomization(), m2.getCustomization()) + && Objects.equals(m1.getXmlNamespace(), m2.getXmlNamespace()) + ; + } + + private boolean memberListsAreIdentical(List memberList1, List memberList2) { + if (memberList1.size() != memberList2.size()) { + return false; + } + + for (int i = 0; i < memberList1.size(); i++) { + MemberModel m1 = memberList1.get(i); + MemberModel m2 = memberList2.get(i); + if (!memberModelsAreIdentical(m1, m2)) { + return false; + } + } + + return true; + } + + private boolean memberModelsAreIdentical(MemberModel m1, MemberModel m2) { + // Similar to ShapeModel, can't call equals() directly. It has a ShapeModel property that is ignored, and ListModel and + // MapModel are treated similarly + return m1.isDeprecated() == m2.isDeprecated() + && m1.isRequired() == m2.isRequired() + && m1.isSynthetic() == m2.isSynthetic() + && m1.isIdempotencyToken() == m2.isIdempotencyToken() + && m1.isJsonValue() == m2.isJsonValue() + && m1.isEventPayload() == m2.isEventPayload() + && m1.isEventHeader() == m2.isEventHeader() + && m1.isEndpointDiscoveryId() == m2.isEndpointDiscoveryId() + && m1.isSensitive() == m2.isSensitive() + && m1.isXmlAttribute() == m2.isXmlAttribute() + && m1.ignoreDataTypeConversionFailures() == m2.ignoreDataTypeConversionFailures() + && Objects.equals(m1.getName(), m2.getName()) + && Objects.equals(m1.getC2jName(), m2.getC2jName()) + && Objects.equals(m1.getC2jShape(), m2.getC2jShape()) + && Objects.equals(m1.getVariable(), m2.getVariable()) + && Objects.equals(m1.getSetterModel(), m2.getSetterModel()) + && Objects.equals(m1.getGetterModel(), m2.getGetterModel()) + && Objects.equals(m1.getHttp(), m2.getHttp()) + && Objects.equals(m1.getDeprecatedMessage(), m2.getDeprecatedMessage()) + // Note: not equals() + && listModelsAreIdentical(m1.getListModel(), m2.getListModel()) + // Note: not equals() + && mapModelsAreIdentical(m1.getMapModel(), m2.getMapModel()) + && Objects.equals(m1.getEnumType(), m2.getEnumType()) + && Objects.equals(m1.getXmlNameSpaceUri(), m2.getXmlNameSpaceUri()) + && Objects.equals(m1.getFluentGetterMethodName(), m2.getFluentGetterMethodName()) + && Objects.equals(m1.getFluentEnumGetterMethodName(), m2.getFluentEnumGetterMethodName()) + && Objects.equals(m1.getFluentSetterMethodName(), m2.getFluentSetterMethodName()) + && Objects.equals(m1.getFluentEnumSetterMethodName(), m2.getFluentEnumSetterMethodName()) + && Objects.equals(m1.getExistenceCheckMethodName(), m2.getExistenceCheckMethodName()) + && Objects.equals(m1.getBeanStyleGetterMethodName(), m2.getBeanStyleGetterMethodName()) + && Objects.equals(m1.getBeanStyleSetterMethodName(), m2.getBeanStyleSetterMethodName()) + && Objects.equals(m1.getUnionEnumTypeName(), m2.getUnionEnumTypeName()) + && Objects.equals(m1.getTimestampFormat(), m2.getTimestampFormat()) + && Objects.equals(m1.getDeprecatedName(), m2.getDeprecatedName()) + && Objects.equals(m1.getDeprecatedFluentGetterMethodName(), m2.getDeprecatedFluentGetterMethodName()) + && Objects.equals(m1.getDeprecatedFluentSetterMethodName(), m2.getDeprecatedFluentSetterMethodName()) + && Objects.equals(m1.getDeprecatedBeanStyleSetterMethodName(), m2.getDeprecatedBeanStyleSetterMethodName()) + && Objects.equals(m1.getContextParam(), m2.getContextParam()); + } + + private boolean listModelsAreIdentical(ListModel m1, ListModel m2) { + if (m1 == null ^ m2 == null) { + return false; + } + + if (m1 == null) { + return true; + } + + return Objects.equals(m1.getImplType(), m2.getImplType()) + && Objects.equals(m1.getMemberType(), m2.getMemberType()) + && Objects.equals(m1.getInterfaceType(), m2.getInterfaceType()) + // Note: not equals() + && memberModelsAreIdentical(m1.getListMemberModel(), m2.getListMemberModel()) + && Objects.equals(m1.getMemberLocationName(), m2.getMemberLocationName()) + && Objects.equals(m1.getMemberAdditionalMarshallingPath(), m2.getMemberAdditionalMarshallingPath()) + && Objects.equals(m1.getMemberAdditionalUnmarshallingPath(), m2.getMemberAdditionalUnmarshallingPath()); + } + + private boolean mapModelsAreIdentical(MapModel m1, MapModel m2) { + if (m1 == null ^ m2 == null) { + return false; + } + + if (m1 == null) { + return true; + } + + return Objects.equals(m1.getImplType(), m2.getImplType()) + && Objects.equals(m1.getInterfaceType(), m2.getInterfaceType()) + && Objects.equals(m1.getKeyLocationName(), m2.getKeyLocationName()) + // Note: not equals() + && memberModelsAreIdentical(m1.getKeyModel(), m2.getKeyModel()) + && Objects.equals(m1.getValueLocationName(), m2.getValueLocationName()) + // Note: not equals() + && memberModelsAreIdentical(m1.getValueModel(), m2.getValueModel()); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModelTest.java new file mode 100644 index 000000000000..107a6e6cdb66 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ArgumentModelTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ArgumentModelTest { + @Test + public void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ArgumentModel.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModelTest.java new file mode 100644 index 000000000000..28d8dd845412 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/AuthorizerModelTest.java @@ -0,0 +1,26 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class AuthorizerModelTest { + @Test + public void equals_isCorrect() { + EqualsVerifier.simple().forClass(AuthorizerModel.class).usingGetClass().verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/MemberModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/MemberModelTest.java new file mode 100644 index 000000000000..bd4a0859603f --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/MemberModelTest.java @@ -0,0 +1,40 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class MemberModelTest { + @Test + public void equals_isCorrect() { + ListModel redListModel = new ListModel(); + redListModel.setMemberLocationName("RedLocation"); + ListModel blueListModel = new ListModel(); + blueListModel.setMemberLocationName("BlueLocation"); + + MemberModel redMemberModel = new MemberModel(); + redMemberModel.setC2jName("RedC2jName"); + MemberModel blueMemberModel = new MemberModel(); + blueMemberModel.setC2jName("BlueC2jName"); + + EqualsVerifier.simple().forClass(MemberModel.class) + .withPrefabValues(ListModel.class, redListModel, blueListModel) + .withPrefabValues(MemberModel.class, redMemberModel, blueMemberModel) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/OperationModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/OperationModelTest.java new file mode 100644 index 000000000000..531d0b1aa55e --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/OperationModelTest.java @@ -0,0 +1,35 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class OperationModelTest { + @Test + void equals_isCorrect() { + MemberModel blueMemberModel = new MemberModel(); + blueMemberModel.setName("blue"); + MemberModel redMemberModel = new MemberModel(); + redMemberModel.setName("red"); + + EqualsVerifier.simple() + .forClass(OperationModel.class) + .withPrefabValues(MemberModel.class, blueMemberModel, redMemberModel) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMappingTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMappingTest.java new file mode 100644 index 000000000000..cd142cb34c2c --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ParameterHttpMappingTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ParameterHttpMappingTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ParameterHttpMapping.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModelTest.java new file mode 100644 index 000000000000..53e99f514403 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ReturnTypeModelTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ReturnTypeModelTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ReturnTypeModel.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModelTest.java new file mode 100644 index 000000000000..08fb79681e96 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/ShapeModelTest.java @@ -0,0 +1,37 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ShapeModelTest { + + + @Test + public void equals_isCorrect() { + MemberModel blueMemberModel = new MemberModel(); + blueMemberModel.setName("blue"); + MemberModel redMemberModel = new MemberModel(); + redMemberModel.setName("red"); + + EqualsVerifier.simple() + .forClass(ShapeModel.class) + .withPrefabValues(MemberModel.class, blueMemberModel, redMemberModel) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/VariableModelTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/VariableModelTest.java new file mode 100644 index 000000000000..55ea2f39123a --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/VariableModelTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class VariableModelTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(VariableModel.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapperTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapperTest.java new file mode 100644 index 000000000000..aa29412a5f5f --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ArtificialResultWrapperTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate.customization; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ArtificialResultWrapperTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ArtificialResultWrapper.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfoTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfoTest.java new file mode 100644 index 000000000000..3126117f100d --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/intermediate/customization/ShapeCustomizationInfoTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.intermediate.customization; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ShapeCustomizationInfoTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ShapeCustomizationInfo.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/model/service/ContextParamTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/model/service/ContextParamTest.java new file mode 100644 index 000000000000..937688b70cb4 --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/model/service/ContextParamTest.java @@ -0,0 +1,29 @@ +/* + * 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.codegen.model.service; + +import nl.jqno.equalsverifier.EqualsVerifier; +import org.junit.jupiter.api.Test; + +public class ContextParamTest { + @Test + void equals_isCorrect() { + EqualsVerifier.simple() + .forClass(ContextParam.class) + .usingGetClass() + .verify(); + } +} diff --git a/codegen/src/test/java/software/amazon/awssdk/codegen/validation/SharedModelsValidatorTest.java b/codegen/src/test/java/software/amazon/awssdk/codegen/validation/SharedModelsValidatorTest.java new file mode 100644 index 000000000000..a485956d94bc --- /dev/null +++ b/codegen/src/test/java/software/amazon/awssdk/codegen/validation/SharedModelsValidatorTest.java @@ -0,0 +1,148 @@ +/* + * 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.codegen.validation; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; +import software.amazon.awssdk.codegen.model.intermediate.MemberModel; +import software.amazon.awssdk.codegen.model.intermediate.Metadata; +import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; +import software.amazon.awssdk.codegen.poet.ClientTestModels; + +public class SharedModelsValidatorTest { + private final ModelValidator validator = new SharedModelsValidator(); + + @Test + void validateModels_noTargetService_noValidationErrors() { + assertThat(runValidation(ClientTestModels.awsJsonServiceModels(), null)).isEmpty(); + } + + @Test + void validateModels_targetServiceTriviallyIdentical_noValidationErrors() { + assertThat(runValidation(ClientTestModels.awsJsonServiceModels(), ClientTestModels.awsJsonServiceModels())).isEmpty(); + } + + @Test + void validateModels_noSharedShapes_noValidationErrors() { + IntermediateModel target = ClientTestModels.awsJsonServiceModels(); + Map renamedShapes = target.getShapes() + .entrySet() + .stream() + .collect(Collectors.toMap(e -> "Copy" + e.getKey(), Map.Entry::getValue)); + target.setShapes(renamedShapes); + + assertThat(runValidation(ClientTestModels.awsJsonServiceModels(), target)).isEmpty(); + } + + @Test + void validateModels_sharedShapesNotIdentical_emitsValidationError() { + IntermediateModel target = ClientTestModels.awsJsonServiceModels(); + Map modifiedShapes = target.getShapes() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, + e -> { + ShapeModel shapeModel = e.getValue(); + shapeModel.setDeprecated(!shapeModel.isDeprecated()); + return shapeModel; + })); + + target.setShapes(modifiedShapes); + + List validationEntries = runValidation(ClientTestModels.awsJsonServiceModels(), target); + + assertThat(validationEntries).hasSize(modifiedShapes.size()); + + assertThat(validationEntries).allMatch(e -> e.getErrorId() == ValidationErrorId.SHARED_MODELS_DIFFER + && e.getSeverity() == ValidationErrorSeverity.DANGER); + } + + @Test + void validateModels_shapesDontHaveSameMemberNames_emitsValidationError() { + IntermediateModel fooService = new IntermediateModel(); + fooService.setMetadata(new Metadata().withServiceName("Foo")); + + IntermediateModel barService = new IntermediateModel(); + barService.setMetadata(new Metadata().withServiceName("Bar")); + + String shapeName = "TestShape"; + + ShapeModel shape1 = new ShapeModel(); + MemberModel member1 = new MemberModel(); + member1.setName("Shape1Member"); + shape1.setMembers(Arrays.asList(member1)); + + ShapeModel shape2 = new ShapeModel(); + MemberModel member2 = new MemberModel(); + member2.setName("Shape2Member"); + shape2.setMembers(Arrays.asList(member2)); + + Map fooServiceShapes = new HashMap<>(); + fooServiceShapes.put(shapeName, shape1); + fooService.setShapes(fooServiceShapes); + + Map barServiceShapes = new HashMap<>(); + barServiceShapes.put(shapeName, shape2); + barService.setShapes(barServiceShapes); + + List validationEntries = runValidation(fooService, barService); + + assertThat(validationEntries).hasSize(1); + } + + @Test + void validateModels_shapesDontHaveSameMembers_emitsValidationError() { + IntermediateModel fooService = new IntermediateModel(); + fooService.setMetadata(new Metadata().withServiceName("Foo")); + + IntermediateModel barService = new IntermediateModel(); + barService.setMetadata(new Metadata().withServiceName("Bar")); + + String shapeName = "TestShape"; + ShapeModel shape1 = new ShapeModel(); + + ShapeModel shape2 = new ShapeModel(); + shape2.setMembers(Arrays.asList(new MemberModel(), new MemberModel())); + + Map fooServiceShapes = new HashMap<>(); + fooServiceShapes.put(shapeName, shape1); + fooService.setShapes(fooServiceShapes); + + Map barServiceShapes = new HashMap<>(); + barServiceShapes.put(shapeName, shape2); + barService.setShapes(barServiceShapes); + + List validationEntries = runValidation(fooService, barService); + + assertThat(validationEntries).hasSize(1); + } + + private List runValidation(IntermediateModel m1, IntermediateModel m2) { + ModelValidationContext ctx = ModelValidationContext.builder() + .intermediateModel(m1) + .shareModelsTarget(m2) + .build(); + + return validator.validateModels(ctx); + } +}