From 169ca2b26a5b2ab3bda6a02201fdd1d24ed59236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Kr=C3=BCger?= <56278322+fabapp2@users.noreply.github.com> Date: Sat, 13 Jan 2024 15:32:20 +0000 Subject: [PATCH] Test Maven type resolution * Make -test jar a deploy artifact * Add util package from test * Test type resolution and usage for simplistic scenario --- .github/workflows/ci.yml | 2 +- .../dependency-resolution-tests/pom.xml | 47 ++++ .../rewrite/MavenTypeResolutionTest.java | 210 ++++++++++++++++++ .../pom.xml | 1 + spring-rewrite-commons-launcher/pom.xml | 2 +- .../rewrite/test/util/TestProjectHelper.java | 6 + 6 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml create mode 100644 spring-rewrite-commons-functional-tests/dependency-resolution-tests/src/test/java/org/springframework/rewrite/MavenTypeResolutionTest.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9b0cf2..d0f106a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,7 @@ jobs: --server-id-deploy repo.spring.io \ --repo-deploy-releases release \ --repo-deploy-snapshots snapshot \ - --exclude-patterns="*-example*.*,*-test*.*,*-docs-*.*" + --exclude-patterns="*-example*.*,*-test-*.*,*-docs-*.*" echo JFROG_CLI_BUILD_NAME=spring-rewrite-commons-main >> $GITHUB_ENV echo JFROG_CLI_BUILD_NUMBER=$GITHUB_RUN_NUMBER >> $GITHUB_ENV diff --git a/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml new file mode 100644 index 0000000..d5feeea --- /dev/null +++ b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + org.springframework.rewrite + spring-rewrite-commons-functional-tests + 0.1.0-SNAPSHOT + ../pom.xml + + + dependency-resolution-tests + + + 17 + 17 + UTF-8 + + + + + org.springframework.rewrite + spring-rewrite-commons-launcher + ${project.version} + + + org.openrewrite + rewrite-java + 8.12.0 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.rewrite + spring-rewrite-commons-launcher + test + test-jar + 0.1.0-SNAPSHOT + test + + + + \ No newline at end of file diff --git a/spring-rewrite-commons-functional-tests/dependency-resolution-tests/src/test/java/org/springframework/rewrite/MavenTypeResolutionTest.java b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/src/test/java/org/springframework/rewrite/MavenTypeResolutionTest.java new file mode 100644 index 0000000..06897b4 --- /dev/null +++ b/spring-rewrite-commons-functional-tests/dependency-resolution-tests/src/test/java/org/springframework/rewrite/MavenTypeResolutionTest.java @@ -0,0 +1,210 @@ +/* + * Copyright 2021 - 2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.springframework.rewrite; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.ExecutionContext; +import org.openrewrite.RecipeRun; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.InMemoryLargeSourceSet; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.springframework.rewrite.parsers.RewriteExecutionContext; +import org.springframework.rewrite.parsers.RewriteProjectParsingResult; +import org.springframework.rewrite.parsers.SpringRewriteProperties; +import org.springframework.rewrite.parsers.maven.ClasspathDependencies; +import org.springframework.rewrite.support.openrewrite.GenericOpenRewriteRecipe; +import org.springframework.rewrite.test.util.ParserExecutionHelper; +import org.springframework.rewrite.test.util.TestProjectHelper; + +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MavenTypeResolutionTest { + + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class WithSingleModuleMavenProject { + + private static RewriteProjectParsingResult parsingResult; + + /** + * Given: A Project with pom file containing dependency to @SpringBootApplication + * and a simple Java class When: The project is parsed Then: The classpath should + * contain the simple class and the @SpringBootApplication annotation. The + * typesInUse is empty because the simple class does not import/use any types + */ + @Test + @Order(1) + @DisplayName("parsed project should have correct classpath") + void parsedProjectShouldHaveCorrectClasspath(@TempDir Path baseDir) { + // given + pepareProject(baseDir); + // when + parsingResult = new ParserExecutionHelper().parseWithRewriteProjectParser(baseDir, + new SpringRewriteProperties()); + // then + verifyTypesOnClasspathAndNoTypesInUse(parsingResult); + } + + /** + * Given: The parsed project from (1) When: The annotation is added to the simple + * class Then: The classpath should contain the simple class and + * the @SpringBootApplication annotation. The typesInUse contains + * the @SpringBootApplication + */ + @Test + @Order(2) + @DisplayName("annotating the class adds the annotation to typesInUse") + void annotatingTheClassAddsTheAnnotationToTypesInUse() { + // Given: parsed project + List sourceFiles = parsingResult.sourceFiles(); + assertThat(sourceFiles).isNotEmpty(); + // When: Add @SpringBootApplication annotation to class + RecipeRun recipeRun = annotateClass(sourceFiles); + // Then: annotation is in typesInUse + verifyAnnotationIsNowInUsedTypes(recipeRun); + } + + private static void verifyAnnotationIsNowInUsedTypes(RecipeRun recipeRun) { + SourceFile after = recipeRun.getChangeset().getAllResults().get(0).getAfter(); + assertThat(after).isInstanceOf(J.CompilationUnit.class); + J.CompilationUnit cu = (J.CompilationUnit) after; + List classpath = cu.getMarkers() + .findFirst(JavaSourceSet.class) + .get() + .getClasspath() + .stream() + .map(JavaType.FullyQualified::getFullyQualifiedName) + .toList(); + assertThat(classpath).contains("org.springframework.boot.autoconfigure.SpringBootApplication", "SomeClass"); + + List typesInUse = cu.getTypesInUse() + .getTypesInUse() + .stream() + .map(JavaType.FullyQualified.class::cast) + .map(JavaType.FullyQualified::getFullyQualifiedName) + .toList(); + assertThat(typesInUse) + .containsExactlyInAnyOrder("org.springframework.boot.autoconfigure.SpringBootApplication"); + } + + @NotNull + private static RecipeRun annotateClass(List sourceFiles) { + RecipeRun recipeRun = new GenericOpenRewriteRecipe<>(() -> new JavaIsoVisitor<>() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, + ExecutionContext executionContext) { + J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, executionContext); + if (cd.getSimpleName().equals("SomeClass")) { + ClasspathDependencies classpathDependencies = ((J.CompilationUnit) getCursor() + .dropParentUntil(J.CompilationUnit.class::isInstance) + .getValue()).getMarkers().findFirst(ClasspathDependencies.class).get(); + String annotationFqName = "org.springframework.boot.autoconfigure.SpringBootApplication"; + cd = JavaTemplate.builder("@SpringBootApplication") + .imports(annotationFqName) + .javaParser(JavaParser.fromJavaVersion() + .classpath(classpathDependencies.getDependencies()) + .logCompilationWarningsAndErrors(true)) + .build() + .apply(getCursor(), cd.getCoordinates() + .addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + maybeAddImport(annotationFqName); + } + return cd; + } + }).run(new InMemoryLargeSourceSet(sourceFiles), new RewriteExecutionContext()); + return recipeRun; + } + + private static void verifyTypesOnClasspathAndNoTypesInUse(RewriteProjectParsingResult parallelParsingResult) { + J.CompilationUnit cuBefore = parallelParsingResult.sourceFiles() + .stream() + .filter(J.CompilationUnit.class::isInstance) + .map(J.CompilationUnit.class::cast) + .findFirst() + .get(); + List typesInUseBefore = cuBefore.getTypesInUse() + .getTypesInUse() + .stream() + .map(JavaType.FullyQualified.class::cast) + .map(JavaType.FullyQualified::getFullyQualifiedName) + .toList(); + assertThat(typesInUseBefore).isEmpty(); + List classpathBefore = cuBefore.getMarkers() + .findFirst(JavaSourceSet.class) + .get() + .getClasspath() + .stream() + .map(JavaType.FullyQualified::getFullyQualifiedName) + .toList(); + assertThat(classpathBefore).contains("org.springframework.boot.autoconfigure.SpringBootApplication", + "SomeClass"); + } + + private static void pepareProject(Path baseDir) { + TestProjectHelper.createTestProject(baseDir) + .addResource("pom.xml", + """ + + + 4.0.0 + org.example + artifact + 0.1.0-SNAPSHOT + + 17 + 17 + + + + org.springframework.boot + spring-boot-autoconfigure + 3.1.3 + + + + """) + + .addResource("src/main/java/SomeClass.java", + // @formatter:off + """ + public class SomeClass {} + """ + // @formatter:on + ) + .writeToFilesystem(); + } + + } + + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class WithMultiModuleMavenProject { + + } + +} diff --git a/spring-rewrite-commons-functional-tests/pom.xml b/spring-rewrite-commons-functional-tests/pom.xml index a84951c..e35baaf 100644 --- a/spring-rewrite-commons-functional-tests/pom.xml +++ b/spring-rewrite-commons-functional-tests/pom.xml @@ -23,6 +23,7 @@ private-artifact-repository-tests + dependency-resolution-tests diff --git a/spring-rewrite-commons-launcher/pom.xml b/spring-rewrite-commons-launcher/pom.xml index b671ba3..a695662 100644 --- a/spring-rewrite-commons-launcher/pom.xml +++ b/spring-rewrite-commons-launcher/pom.xml @@ -186,7 +186,7 @@ test - **/parsers/maven/** + **/parsers/maven/**,**/test/util/** diff --git a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java index 9d2d65b..befece9 100644 --- a/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java +++ b/spring-rewrite-commons-launcher/src/test/java/org/springframework/rewrite/test/util/TestProjectHelper.java @@ -120,4 +120,10 @@ public class TestProjectHelper { ResourceUtil.write(targetDir, resources); } + public TestProjectHelper addResource(String relativePath, String content) { + DummyResource dummyResource = new DummyResource(targetDir.resolve(relativePath), content); + this.resources.add(dummyResource); + return this; + } + }