Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-382b343.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Adding compatibility tests between sdk-core and service packages"
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask;
import software.amazon.awssdk.codegen.internal.Utils;
import software.amazon.awssdk.codegen.poet.client.EnvironmentTokenSystemSettingsClass;
import software.amazon.awssdk.codegen.poet.client.SdkClientOptions;
import software.amazon.awssdk.codegen.poet.client.specs.ServiceVersionInfoSpec;
import software.amazon.awssdk.codegen.poet.client.specs.VersionCompatibilityTestSpec;
import software.amazon.awssdk.codegen.poet.common.UserAgentUtilsSpec;

public class CommonInternalGeneratorTasks extends BaseGeneratorTasks {
Expand All @@ -40,6 +43,8 @@ protected List<GeneratorTask> createTasks() throws Exception {
if (params.getModel().getCustomizationConfig().isEnableEnvironmentBearerToken()) {
tasks.add(createEnvironmentTokenSystemSettingTask());
}
tasks.add(createServiceVersionInfoTask());
tasks.add(createVersionCompatibilityTestTask());
return tasks;
}

Expand All @@ -58,6 +63,21 @@ private GeneratorTask createEnvironmentTokenSystemSettingTask() {
new EnvironmentTokenSystemSettingsClass(params.getModel()));
}

private GeneratorTask createServiceVersionInfoTask() {
return new PoetGeneratorTask(clientOptionsDir(), params.getModel().getFileHeader(),
new ServiceVersionInfoSpec(params.getModel()));
}

private GeneratorTask createVersionCompatibilityTestTask() {
return new PoetGeneratorTask(testDir(), params.getModel().getFileHeader(),
new VersionCompatibilityTestSpec(params.getModel()));
}

private String testDir() {
return params.getPathProvider().getTestDirectory() + "/" +
Utils.packageToDirectory(params.getModel().getMetadata().getFullClientInternalPackageName());
}

private String clientOptionsDir() {
return params.getPathProvider().getClientInternalDirectory();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ public ClassName getUserAgentClass() {
return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "UserAgentUtils");
}

public ClassName getServiceVersionInfoClass() {
return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "ServiceVersionInfo");
}

public ClassName getEnvironmentTokenSystemSettingsClass() {
return ClassName.get(model.getMetadata().getFullClientInternalPackageName(), "EnvironmentTokenSystemSettings");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.poet.client.specs;

import static software.amazon.awssdk.core.util.VersionInfo.SDK_VERSION;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetExtension;
import software.amazon.awssdk.codegen.poet.PoetUtils;

public class ServiceVersionInfoSpec implements ClassSpec {
private final PoetExtension poetExtension;

public ServiceVersionInfoSpec(IntermediateModel model) {
this.poetExtension = new PoetExtension(model);
}

@Override
public TypeSpec poetSpec() {
TypeSpec.Builder builder = TypeSpec.classBuilder("ServiceVersionInfo")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addAnnotation(PoetUtils.generatedAnnotation())
.addField(FieldSpec.builder(
String.class, "VERSION", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", SDK_VERSION)
.addJavadoc("Returns the current version for the AWS SDK in which"
+ " this class is running.")
.build())
.addMethod(privateConstructor());

return builder.build();
}

protected MethodSpec privateConstructor() {
return MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.build();
}

@Override
public ClassName className() {
return poetExtension.getServiceVersionInfoClass();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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.poet.client.specs;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetUtils;

public class VersionCompatibilityTestSpec implements ClassSpec {
private final IntermediateModel model;

public VersionCompatibilityTestSpec(IntermediateModel model) {
this.model = model;
}

@Override
public TypeSpec poetSpec() {
return PoetUtils.createClassBuilder(className())
.addModifiers(Modifier.PUBLIC)
.addMethod(compatibilityTest())
.addMethod(isVersionCompatibleMethod())
.build();
}

@Override
public ClassName className() {
return ClassName.get(model.getMetadata().getFullClientPackageName(), "VersionCompatibilityTest");
}

private MethodSpec compatibilityTest() {
ClassName serviceVersionInfo = ClassName.get(
model.getMetadata().getFullInternalPackageName(),
"ServiceVersionInfo"
);

ClassName versionInfo = ClassName.get("software.amazon.awssdk.core.util", "VersionInfo");
ClassName assertions = ClassName.get("org.assertj.core.api", "Assertions");

return MethodSpec.methodBuilder("checkCompatibility")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Test.class)
.returns(void.class)
.addStatement("String coreVersion = $T.SDK_VERSION", versionInfo)
.addStatement("String serviceVersion = $T.VERSION", serviceVersionInfo)
.addStatement("$T.assertThat(isVersionCompatible(coreVersion, serviceVersion))" +
".withFailMessage(\"Core version %s must be equal to or newer than service version %s\", "
+ "coreVersion, serviceVersion).isTrue()",
assertions)
.build();
}

private MethodSpec isVersionCompatibleMethod() {
return MethodSpec.methodBuilder("isVersionCompatible")
.addModifiers(Modifier.PRIVATE)
.returns(boolean.class)
.addParameter(String.class, "coreVersion")
.addParameter(String.class, "serviceVersion")
.addStatement("String normalizedCore = coreVersion.replace(\"-SNAPSHOT\", \"\")")
.addStatement("String normalizedService = serviceVersion.replace(\"-SNAPSHOT\", \"\")")
.addStatement("String[] coreParts = normalizedCore.split(\"\\\\.\")")
.addStatement("String[] serviceParts = normalizedService.split(\"\\\\.\")")
.addCode("\n")
.addStatement("int coreMajor = Integer.parseInt(coreParts[0])")
.addStatement("int serviceMajor = Integer.parseInt(serviceParts[0])")
.beginControlFlow("if (coreMajor != serviceMajor)")
.addStatement("return coreMajor >= serviceMajor")
.endControlFlow()
.addCode("\n")
.addStatement("int coreMinor = Integer.parseInt(coreParts[1])")
.addStatement("int serviceMinor = Integer.parseInt(serviceParts[1])")
.beginControlFlow("if (coreMinor != serviceMinor)")
.addStatement("return coreMinor >= serviceMinor")
.endControlFlow()
.addCode("\n")
.addStatement("int corePatch = Integer.parseInt(coreParts[2])")
.addStatement("int servicePatch = Integer.parseInt(serviceParts[2])")
.addStatement("return corePatch >= servicePatch")
.build();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.poet.client;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import java.io.InputStream;
import java.util.Scanner;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.ClientTestModels;
import software.amazon.awssdk.codegen.poet.client.specs.ServiceVersionInfoSpec;
import software.amazon.awssdk.core.util.VersionInfo;

public class ServiceVersionInfoSpecTest {

// a fixture test that dynamically updates the generated fixture with the current version
// this is needed because every time codegen runs, the version will change.
// we need a way to generate the fixture, and then edit it in place with the current version and only then make the assertion.
@Test
void testServiceVersionInfoClass() {
String currVersion = VersionInfo.SDK_VERSION;
ClassSpec serviceVersionInfoSpec = new ServiceVersionInfoSpec(ClientTestModels.restJsonServiceModels());

String expectedContent = loadFixtureFile("test-service-version-info-class.java");
String[] parts = expectedContent.split("public static final String VERSION = \"");
if (parts.length == 2) {
String privateConstructor = parts[1].substring(parts[1].indexOf("\""));
expectedContent = parts[0] + "public static final String VERSION = \"" + currVersion
+ privateConstructor;
}

String actualContent = generateContent(serviceVersionInfoSpec);

assertThat(actualContent).isEqualTo(expectedContent);
}

private String loadFixtureFile(String filename) {
InputStream is = getClass().getResourceAsStream("specs/" + filename);
return new Scanner(is).useDelimiter("\\A").next();
}

private String generateContent(ClassSpec spec) {
TypeSpec typeSpec = spec.poetSpec();
JavaFile javaFile = JavaFile.builder(spec.className().packageName(), typeSpec).build();
return javaFile.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package software.amazon.awssdk.services.json.internal;

import java.lang.String;
import software.amazon.awssdk.annotations.Generated;

@Generated("software.amazon.awssdk:codegen")
public final class ServiceVersionInfo {
/**
* Returns the current version for the AWS SDK in which this class is running.
*/
public static final String VERSION = "{{VERSION}}";

private ServiceVersionInfo() {
}
}
Loading