|
16 | 16 | package org.springframework.sbm;
|
17 | 17 |
|
18 | 18 | import org.apache.maven.shared.invoker.*;
|
19 |
| -import org.junit.jupiter.api.BeforeEach; |
20 |
| -import org.junit.jupiter.api.DisplayName; |
21 |
| -import org.junit.jupiter.api.Test; |
22 |
| -import org.junitpioneer.jupiter.*; |
| 19 | +import org.junit.jupiter.api.*; |
| 20 | +import org.openrewrite.SourceFile; |
| 21 | +import org.openrewrite.java.JavaParser; |
| 22 | +import org.openrewrite.java.internal.JavaTypeCache; |
| 23 | +import org.openrewrite.java.marker.JavaSourceSet; |
| 24 | +import org.openrewrite.java.tree.J; |
| 25 | +import org.openrewrite.java.tree.JavaType; |
| 26 | +import org.springframework.beans.factory.annotation.Autowired; |
23 | 27 | import org.springframework.boot.test.context.SpringBootTest;
|
24 | 28 | import org.springframework.sbm.boot.autoconfigure.SbmSupportRewriteConfiguration;
|
| 29 | +import org.springframework.sbm.parsers.RewriteProjectParser; |
| 30 | +import org.springframework.sbm.parsers.RewriteProjectParsingResult; |
| 31 | +import org.springframework.sbm.parsers.maven.RewriteMavenProjectParser; |
| 32 | +import org.springframework.sbm.parsers.maven.SbmTestConfiguration; |
| 33 | +import org.springframework.util.FileSystemUtils; |
25 | 34 | import org.testcontainers.containers.GenericContainer;
|
26 | 35 | import org.testcontainers.junit.jupiter.Container;
|
27 | 36 | import org.testcontainers.junit.jupiter.Testcontainers;
|
|
32 | 41 | import java.io.IOException;
|
33 | 42 | import java.nio.file.Files;
|
34 | 43 | import java.nio.file.Path;
|
| 44 | +import java.util.Arrays; |
35 | 45 | import java.util.List;
|
36 | 46 | import java.util.regex.Matcher;
|
37 | 47 | import java.util.regex.Pattern;
|
38 | 48 |
|
39 | 49 | import static org.assertj.core.api.Assertions.assertThat;
|
40 |
| -import static org.assertj.core.api.Assertions.in; |
| 50 | +import static org.assertj.core.api.Fail.fail; |
41 | 51 |
|
42 | 52 | /**
|
43 | 53 | * @author Fabian Krüger
|
44 | 54 | */
|
45 |
| -@SpringBootTest(classes = SbmSupportRewriteConfiguration.class) |
| 55 | +@SpringBootTest(classes = {SbmSupportRewriteConfiguration.class, SbmTestConfiguration.class}) |
46 | 56 | @Testcontainers
|
| 57 | +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
47 | 58 | public class PrivateArtifactRepositoryTest {
|
| 59 | + public static final String $USER_HOME_PLACEHOLDER = "${user.home}"; |
| 60 | + public static final String $PORT_PLACEHOLDER = "${port}"; |
| 61 | + public static final String TESTCODE_DIR = "testcode/reposilite-test"; |
| 62 | + public static final String DEPENDENCY_CLASS_FQNAME = "com.example.dependency.DependencyClass"; |
48 | 63 | @Container
|
49 | 64 | static GenericContainer reposilite = new GenericContainer(DockerImageName.parse("dzikoysk/reposilite:3.4.10"))
|
50 | 65 | .withExposedPorts(8080)
|
51 |
| - .withEnv("REPOSILITE_OPTS", "--token user:secret"); |
| 66 | + .withCopyFileToContainer( |
| 67 | + MountableFile.forHostPath("./" + TESTCODE_DIR + "/reposilite-data/shared.configuration.json"), |
| 68 | + "/app/data/shared.configuration.json" |
| 69 | + ) |
| 70 | + // Create temp user 'user' with password 'secret' |
| 71 | + .withEnv("REPOSILITE_OPTS", "--token user:secret --shared-config shared.configuration.json"); |
52 | 72 |
|
53 |
| - @BeforeEach |
54 |
| - void beforeEach() { |
| 73 | + private static String originalUserHome; |
| 74 | + private static String newUserHome; |
55 | 75 |
|
| 76 | + @Autowired |
| 77 | + private RewriteProjectParser parser; |
| 78 | + |
| 79 | + @Autowired |
| 80 | + private RewriteMavenProjectParser comparingParser; |
| 81 | + private File localMavenRepository = Path.of(TESTCODE_DIR + "/user.home/.m2/repository").toFile(); |
| 82 | + |
| 83 | + private Path dependencyPathInLocalMavenRepo = Path.of(TESTCODE_DIR + "/user.home/.m2/repository/com/example/dependency/dependency-project"); |
| 84 | + |
| 85 | + @BeforeAll |
| 86 | + static void beforeAll() { |
| 87 | + originalUserHome = System.getProperty("user.home"); |
| 88 | + newUserHome = Path.of(".").resolve(TESTCODE_DIR + "/user.home").toAbsolutePath().normalize().toString(); |
| 89 | + System.setProperty("user.home", newUserHome); |
| 90 | + } |
| 91 | + |
| 92 | + @AfterAll |
| 93 | + static void afterAll() { |
| 94 | + System.setProperty("user.home", originalUserHome); |
56 | 95 | }
|
57 | 96 |
|
58 | 97 | @Test
|
| 98 | + @Order(1) |
59 | 99 | @DisplayName("Maven settings should be read")
|
60 |
| - @SetSystemProperty(key = "user.home", value = "testcode/reposilite-test/user.home") |
| 100 | +// @SetSystemProperty(key = "user.home", value = "testcode/reposilite-test/user.home") |
61 | 101 | void mavenSettingsShouldBeRead() throws IOException, MavenInvocationException, InterruptedException {
|
62 |
| - System.out.println(System.getenv("MAVEN_HOME")); |
63 |
| - |
64 | 102 | Integer port = reposilite.getMappedPort(8080);
|
| 103 | + System.out.println("Reposilite: http://localhost:" + port + " login with user:secret"); |
| 104 | + |
| 105 | + // create pom.xml with correct port for dependency-project |
| 106 | + Path dependencyPomTmplPath = Path.of(TESTCODE_DIR + "/dependency-project/pom.xml.template").toAbsolutePath().normalize(); |
| 107 | + Path dependencyPomPath = renderPomXml(port, dependencyPomTmplPath); |
| 108 | + |
| 109 | + // create pom.xml with correct port for dependent-project |
| 110 | + Path dependentPomTmplPath = Path.of(TESTCODE_DIR + "/dependent-project/pom.xml.template").toAbsolutePath().normalize(); |
| 111 | + Path dependentPomPath = renderPomXml(port, dependentPomTmplPath); |
| 112 | + |
| 113 | + // adjust path in settings.xml |
| 114 | + Path settingsXmlTmplPath = Path.of("./").resolve(newUserHome + "/.m2/settings.xml.template").toAbsolutePath().normalize(); |
| 115 | + Path settingsXmlPath = renderSettingsXml(newUserHome, settingsXmlTmplPath); |
65 | 116 |
|
66 |
| - // adjust host:port information in pom.xml |
67 |
| - Path pomXmlPath = Path.of("testcode/reposilite-test/reposilite-test/pom.xml").toAbsolutePath().normalize(); |
68 |
| - String pomXmlContent = Files.readString(pomXmlPath); |
69 |
| - String pomXmlCurrentPort = replacePort(pomXmlContent, port); |
70 |
| - Files.writeString(pomXmlPath, pomXmlCurrentPort); |
| 117 | + deployDependency(dependencyPomPath); |
| 118 | + // the project 'testcode/reposilite-test/reposilite-test' has been deployed to reposilite |
71 | 119 |
|
72 | 120 | InvocationRequest request = new DefaultInvocationRequest();
|
73 |
| - request.setPomFile(pomXmlPath.toFile()); |
74 |
| - request.setGoals(List.of("deploy")); |
| 121 | + request.setPomFile(dependentPomPath.toFile()); |
| 122 | + request.setShowErrors(true); |
| 123 | + request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings.xml").toFile()); |
| 124 | + request.setGoals(List.of("-v", "clean", "package")); |
| 125 | + request.setLocalRepositoryDirectory(localMavenRepository); |
| 126 | + request.setBatchMode(true); |
75 | 127 | Invoker invoker = new DefaultInvoker();
|
76 |
| - invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); |
77 |
| - invoker.execute(request); |
| 128 | + invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile()); |
| 129 | + InvocationResult result = invoker.execute(request); |
| 130 | + if (result.getExitCode() != 0) { |
| 131 | + if (result.getExecutionException() != null) { |
| 132 | + fail("Maven clean package failed.", result.getExecutionException()); |
| 133 | + } else { |
| 134 | + fail("Maven clean package. Exit code: " + result.getExitCode()); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + clearDependencyFromLocalMavenRepo(); |
| 139 | + verifyDependenciesFromPrivateRepoWereResolved(); |
78 | 140 | }
|
79 | 141 |
|
| 142 | + // @Test |
| 143 | +// @Order(2) |
| 144 | + @DisplayName("verify dependencies from private repo were resolved") |
| 145 | + void verifyDependenciesFromPrivateRepoWereResolved() { |
| 146 | + // verify dependency does not exist in local Maven repo |
| 147 | + Path dependencyArtifactDir = dependencyPathInLocalMavenRepo.getParent(); |
| 148 | + assertThat(Files.isDirectory(dependencyArtifactDir)).isTrue(); |
| 149 | + assertThat(dependencyArtifactDir.toFile().listFiles()).isEmpty(); |
80 | 150 |
|
81 |
| - @Test |
82 |
| - @DisplayName("searchAndReplace") |
83 |
| - void searchAndReplace() { |
84 |
| - String given = |
85 |
| - """ |
86 |
| - <?xml version="1.0" encoding="UTF-8"?> |
87 |
| - <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
88 |
| - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
89 |
| - <modelVersion>4.0.0</modelVersion> |
90 |
| - |
91 |
| - <groupId>com.example</groupId> |
92 |
| - <artifactId>reposilite-test</artifactId> |
93 |
| - <version>1.0-SNAPSHOT</version> |
94 |
| - <name>reposilite-test</name> |
95 |
| - |
96 |
| - <properties> |
97 |
| - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
98 |
| - <maven.compiler.source>1.7</maven.compiler.source> |
99 |
| - <maven.compiler.target>1.7</maven.compiler.target> |
100 |
| - </properties> |
101 |
| - |
102 |
| - <dependencies> |
103 |
| - <dependency> |
104 |
| - <groupId>javax.validation</groupId> |
105 |
| - <artifactId>validation-api</artifactId> |
106 |
| - <version>2.0.1.Final</version> |
107 |
| - </dependency> |
108 |
| - </dependencies> |
109 |
| - |
110 |
| - <distributionManagement> |
111 |
| - <repository> |
112 |
| - <id>reposilite-repository-releases</id> |
113 |
| - <name>Reposilite Repository</name> |
114 |
| - <url>http://localhost:8085/snapshots</url> |
115 |
| - </repository> |
116 |
| - </distributionManagement> |
117 |
| - </project> |
118 |
| - """; |
119 |
| - |
120 |
| - String s1 = replacePort(given, 1234); |
121 |
| - |
122 |
| - assertThat(s1).isEqualTo( |
123 |
| - """ |
124 |
| - <?xml version="1.0" encoding="UTF-8"?> |
125 |
| - <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
126 |
| - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
127 |
| - <modelVersion>4.0.0</modelVersion> |
128 |
| - |
129 |
| - <groupId>com.example</groupId> |
130 |
| - <artifactId>reposilite-test</artifactId> |
131 |
| - <version>1.0-SNAPSHOT</version> |
132 |
| - <name>reposilite-test</name> |
133 |
| - |
134 |
| - <properties> |
135 |
| - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
136 |
| - <maven.compiler.source>1.7</maven.compiler.source> |
137 |
| - <maven.compiler.target>1.7</maven.compiler.target> |
138 |
| - </properties> |
139 |
| - |
140 |
| - <dependencies> |
141 |
| - <dependency> |
142 |
| - <groupId>javax.validation</groupId> |
143 |
| - <artifactId>validation-api</artifactId> |
144 |
| - <version>2.0.1.Final</version> |
145 |
| - </dependency> |
146 |
| - </dependencies> |
147 |
| - |
148 |
| - <distributionManagement> |
149 |
| - <repository> |
150 |
| - <id>reposilite-repository-releases</id> |
151 |
| - <name>Reposilite Repository</name> |
152 |
| - <url>http://localhost:1234/snapshots</url> |
153 |
| - </repository> |
154 |
| - </distributionManagement> |
155 |
| - </project> |
156 |
| - """ |
157 |
| - ); |
| 151 | + // scan a project that depends on this dependency |
| 152 | + Path migrateApplication = Path.of(TESTCODE_DIR + "/dependent-project"); |
| 153 | + RewriteProjectParsingResult parsingResult = parser.parse(migrateApplication); |
| 154 | + |
| 155 | + // verify dependency was downloaded |
| 156 | + Path snapshotDir = dependencyPathInLocalMavenRepo.resolve("1.0-SNAPSHOT"); |
| 157 | + assertThat(snapshotDir).isDirectory(); |
| 158 | + assertThat(Arrays.stream(snapshotDir.toFile().listFiles()).map(f -> f.getName()).findFirst().get()).matches("dependency-project-1.0-.*\\.jar"); |
| 159 | + |
| 160 | + // verify that DependencyClass type can be resolved |
| 161 | + J.CompilationUnit cu = (J.CompilationUnit) parsingResult.sourceFiles().stream().filter(s -> s.getSourcePath().toFile().getName().endsWith(".java")).findFirst().get(); |
| 162 | + List<String> fqClassesInUse = cu.getTypesInUse().getTypesInUse().stream().filter(JavaType.FullyQualified.class::isInstance).map(JavaType.FullyQualified.class::cast).map(JavaType.FullyQualified::getFullyQualifiedName).toList(); |
| 163 | + |
| 164 | + // DependencyClass must be in list of used types |
| 165 | + assertThat(fqClassesInUse).contains(DEPENDENCY_CLASS_FQNAME); |
| 166 | + |
| 167 | + // type should be on classpath |
| 168 | + List<String> classpathFqNames = cu.getMarkers().findFirst(JavaSourceSet.class).get().getClasspath().stream().map(fqn -> fqn.getFullyQualifiedName()).toList(); |
| 169 | + assertThat(classpathFqNames).contains(DEPENDENCY_CLASS_FQNAME); |
| 170 | + |
| 171 | + // Type of member should be resolvable |
| 172 | + J.ClassDeclaration classDeclaration = cu.getClasses().get(0); |
| 173 | + JavaType.Class type = (JavaType.Class) ((J.VariableDeclarations) classDeclaration.getBody().getStatements().get(0)).getType(); |
| 174 | + assertThat(type.getFullyQualifiedName()).isEqualTo(DEPENDENCY_CLASS_FQNAME); |
| 175 | + } |
| 176 | + |
| 177 | + |
| 178 | + private Path renderSettingsXml(String testcodeDir, Path settingsXmlTmplPath) throws IOException { |
| 179 | + String settingsXmlContent = Files.readString(settingsXmlTmplPath); |
| 180 | + String replaced = settingsXmlContent.replace($USER_HOME_PLACEHOLDER, testcodeDir); |
| 181 | + Path settingsXmlPath = Path.of(settingsXmlTmplPath.toString().replace(".template", "")); |
| 182 | + return Files.writeString(settingsXmlPath, replaced); |
158 | 183 | }
|
159 | 184 |
|
160 |
| - private static String replacePort(String given, Integer port) { |
161 |
| - String regex = "(<url>http:\\/\\/localhost:)(\\d{1,5})(\\/snapshots<\\/url>)"; |
| 185 | + |
| 186 | + private static String replace(String content, Object replacement, String regex) { |
162 | 187 | Pattern compile = Pattern.compile(regex);
|
163 |
| - Matcher matcher = compile.matcher(given); |
164 |
| - String s1 = matcher.replaceFirst("$1" + port + "$3"); |
| 188 | + Matcher matcher = compile.matcher(content); |
| 189 | + String s1 = matcher.replaceFirst("$1" + replacement + "$3"); |
165 | 190 | return s1;
|
166 | 191 | }
|
| 192 | + |
| 193 | + private static Path renderPomXml(Integer port, Path pomXmlTmplPath) throws IOException { |
| 194 | + String given = Files.readString(pomXmlTmplPath); |
| 195 | + String replaced = given.replace($PORT_PLACEHOLDER, port.toString()); |
| 196 | + Path pomXmlPath = Path.of(pomXmlTmplPath.toString().replace(".template", "")); |
| 197 | + return Files.writeString(pomXmlPath, replaced); |
| 198 | + } |
| 199 | + |
| 200 | + private void clearDependencyFromLocalMavenRepo() { |
| 201 | + try { |
| 202 | + FileSystemUtils.deleteRecursively(dependencyPathInLocalMavenRepo); |
| 203 | + } catch (IOException e) { |
| 204 | + throw new RuntimeException(e); |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + private void deployDependency(Path pomXmlPath) throws MavenInvocationException { |
| 209 | + InvocationRequest request = new DefaultInvocationRequest(); |
| 210 | + request.setPomFile(pomXmlPath.toFile()); |
| 211 | + request.setShowErrors(true); |
| 212 | + request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings.xml").toFile()); |
| 213 | + request.setGoals(List.of("deploy")); |
| 214 | + request.setLocalRepositoryDirectory(localMavenRepository); |
| 215 | + request.setBatchMode(true); |
| 216 | + Invoker invoker = new DefaultInvoker(); |
| 217 | + invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile()); |
| 218 | + InvocationResult result = invoker.execute(request); |
| 219 | + if (result.getExitCode() != 0) { |
| 220 | + if (result.getExecutionException() != null) { |
| 221 | + fail("Maven deploy failed.", result.getExecutionException()); |
| 222 | + } else { |
| 223 | + fail("Maven deploy failed. Exit code: " + result.getExitCode()); |
| 224 | + } |
| 225 | + } |
| 226 | + } |
| 227 | + |
167 | 228 | }
|
0 commit comments