Skip to content

Commit

Permalink
Test working
Browse files Browse the repository at this point in the history
  • Loading branch information
fabapp2 committed Nov 3, 2023
1 parent fcf9da0 commit ef8037d
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 203 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ out/
pom.xml.versionsBackup
**/src/generated/java/META-INF
**.java-version
.rewrite-cache
.rewrite-cache
2 changes: 2 additions & 0 deletions sbm-support-rewrite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
testcode/reposilite-test/reposilite-data/**
!testcode/reposilite-test/reposilite-data/shared.configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@
package org.springframework.sbm;

import org.apache.maven.shared.invoker.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.*;
import org.junit.jupiter.api.*;
import org.openrewrite.SourceFile;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.sbm.boot.autoconfigure.SbmSupportRewriteConfiguration;
import org.springframework.sbm.parsers.RewriteProjectParser;
import org.springframework.sbm.parsers.RewriteProjectParsingResult;
import org.springframework.sbm.parsers.maven.RewriteMavenProjectParser;
import org.springframework.sbm.parsers.maven.SbmTestConfiguration;
import org.springframework.util.FileSystemUtils;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
Expand All @@ -32,136 +41,188 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.in;
import static org.assertj.core.api.Fail.fail;

/**
* @author Fabian Krüger
*/
@SpringBootTest(classes = SbmSupportRewriteConfiguration.class)
@SpringBootTest(classes = {SbmSupportRewriteConfiguration.class, SbmTestConfiguration.class})
@Testcontainers
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class PrivateArtifactRepositoryTest {
public static final String $USER_HOME_PLACEHOLDER = "${user.home}";
public static final String $PORT_PLACEHOLDER = "${port}";
public static final String TESTCODE_DIR = "testcode/reposilite-test";
public static final String DEPENDENCY_CLASS_FQNAME = "com.example.dependency.DependencyClass";
@Container
static GenericContainer reposilite = new GenericContainer(DockerImageName.parse("dzikoysk/reposilite:3.4.10"))
.withExposedPorts(8080)
.withEnv("REPOSILITE_OPTS", "--token user:secret");
.withCopyFileToContainer(
MountableFile.forHostPath("./" + TESTCODE_DIR + "/reposilite-data/shared.configuration.json"),
"/app/data/shared.configuration.json"
)
// Create temp user 'user' with password 'secret'
.withEnv("REPOSILITE_OPTS", "--token user:secret --shared-config shared.configuration.json");

@BeforeEach
void beforeEach() {
private static String originalUserHome;
private static String newUserHome;

@Autowired
private RewriteProjectParser parser;

@Autowired
private RewriteMavenProjectParser comparingParser;
private File localMavenRepository = Path.of(TESTCODE_DIR + "/user.home/.m2/repository").toFile();

private Path dependencyPathInLocalMavenRepo = Path.of(TESTCODE_DIR + "/user.home/.m2/repository/com/example/dependency/dependency-project");

@BeforeAll
static void beforeAll() {
originalUserHome = System.getProperty("user.home");
newUserHome = Path.of(".").resolve(TESTCODE_DIR + "/user.home").toAbsolutePath().normalize().toString();
System.setProperty("user.home", newUserHome);
}

@AfterAll
static void afterAll() {
System.setProperty("user.home", originalUserHome);
}

@Test
@Order(1)
@DisplayName("Maven settings should be read")
@SetSystemProperty(key = "user.home", value = "testcode/reposilite-test/user.home")
// @SetSystemProperty(key = "user.home", value = "testcode/reposilite-test/user.home")
void mavenSettingsShouldBeRead() throws IOException, MavenInvocationException, InterruptedException {
System.out.println(System.getenv("MAVEN_HOME"));

Integer port = reposilite.getMappedPort(8080);
System.out.println("Reposilite: http://localhost:" + port + " login with user:secret");

// create pom.xml with correct port for dependency-project
Path dependencyPomTmplPath = Path.of(TESTCODE_DIR + "/dependency-project/pom.xml.template").toAbsolutePath().normalize();
Path dependencyPomPath = renderPomXml(port, dependencyPomTmplPath);

// create pom.xml with correct port for dependent-project
Path dependentPomTmplPath = Path.of(TESTCODE_DIR + "/dependent-project/pom.xml.template").toAbsolutePath().normalize();
Path dependentPomPath = renderPomXml(port, dependentPomTmplPath);

// adjust path in settings.xml
Path settingsXmlTmplPath = Path.of("./").resolve(newUserHome + "/.m2/settings.xml.template").toAbsolutePath().normalize();
Path settingsXmlPath = renderSettingsXml(newUserHome, settingsXmlTmplPath);

// adjust host:port information in pom.xml
Path pomXmlPath = Path.of("testcode/reposilite-test/reposilite-test/pom.xml").toAbsolutePath().normalize();
String pomXmlContent = Files.readString(pomXmlPath);
String pomXmlCurrentPort = replacePort(pomXmlContent, port);
Files.writeString(pomXmlPath, pomXmlCurrentPort);
deployDependency(dependencyPomPath);
// the project 'testcode/reposilite-test/reposilite-test' has been deployed to reposilite

InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(pomXmlPath.toFile());
request.setGoals(List.of("deploy"));
request.setPomFile(dependentPomPath.toFile());
request.setShowErrors(true);
request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings.xml").toFile());
request.setGoals(List.of("-v", "clean", "package"));
request.setLocalRepositoryDirectory(localMavenRepository);
request.setBatchMode(true);
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(new File(System.getenv("MAVEN_HOME")));
invoker.execute(request);
invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile());
InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) {
if (result.getExecutionException() != null) {
fail("Maven clean package failed.", result.getExecutionException());
} else {
fail("Maven clean package. Exit code: " + result.getExitCode());
}
}

clearDependencyFromLocalMavenRepo();
verifyDependenciesFromPrivateRepoWereResolved();
}

// @Test
// @Order(2)
@DisplayName("verify dependencies from private repo were resolved")
void verifyDependenciesFromPrivateRepoWereResolved() {
// verify dependency does not exist in local Maven repo
Path dependencyArtifactDir = dependencyPathInLocalMavenRepo.getParent();
assertThat(Files.isDirectory(dependencyArtifactDir)).isTrue();
assertThat(dependencyArtifactDir.toFile().listFiles()).isEmpty();

@Test
@DisplayName("searchAndReplace")
void searchAndReplace() {
String given =
"""
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>reposilite-test</artifactId>
<version>1.0-SNAPSHOT</version>
<name>reposilite-test</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>reposilite-repository-releases</id>
<name>Reposilite Repository</name>
<url>http://localhost:8085/snapshots</url>
</repository>
</distributionManagement>
</project>
""";

String s1 = replacePort(given, 1234);

assertThat(s1).isEqualTo(
"""
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>reposilite-test</artifactId>
<version>1.0-SNAPSHOT</version>
<name>reposilite-test</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>reposilite-repository-releases</id>
<name>Reposilite Repository</name>
<url>http://localhost:1234/snapshots</url>
</repository>
</distributionManagement>
</project>
"""
);
// scan a project that depends on this dependency
Path migrateApplication = Path.of(TESTCODE_DIR + "/dependent-project");
RewriteProjectParsingResult parsingResult = parser.parse(migrateApplication);

// verify dependency was downloaded
Path snapshotDir = dependencyPathInLocalMavenRepo.resolve("1.0-SNAPSHOT");
assertThat(snapshotDir).isDirectory();
assertThat(Arrays.stream(snapshotDir.toFile().listFiles()).map(f -> f.getName()).findFirst().get()).matches("dependency-project-1.0-.*\\.jar");

// verify that DependencyClass type can be resolved
J.CompilationUnit cu = (J.CompilationUnit) parsingResult.sourceFiles().stream().filter(s -> s.getSourcePath().toFile().getName().endsWith(".java")).findFirst().get();
List<String> fqClassesInUse = cu.getTypesInUse().getTypesInUse().stream().filter(JavaType.FullyQualified.class::isInstance).map(JavaType.FullyQualified.class::cast).map(JavaType.FullyQualified::getFullyQualifiedName).toList();

// DependencyClass must be in list of used types
assertThat(fqClassesInUse).contains(DEPENDENCY_CLASS_FQNAME);

// type should be on classpath
List<String> classpathFqNames = cu.getMarkers().findFirst(JavaSourceSet.class).get().getClasspath().stream().map(fqn -> fqn.getFullyQualifiedName()).toList();
assertThat(classpathFqNames).contains(DEPENDENCY_CLASS_FQNAME);

// Type of member should be resolvable
J.ClassDeclaration classDeclaration = cu.getClasses().get(0);
JavaType.Class type = (JavaType.Class) ((J.VariableDeclarations) classDeclaration.getBody().getStatements().get(0)).getType();
assertThat(type.getFullyQualifiedName()).isEqualTo(DEPENDENCY_CLASS_FQNAME);
}


private Path renderSettingsXml(String testcodeDir, Path settingsXmlTmplPath) throws IOException {
String settingsXmlContent = Files.readString(settingsXmlTmplPath);
String replaced = settingsXmlContent.replace($USER_HOME_PLACEHOLDER, testcodeDir);
Path settingsXmlPath = Path.of(settingsXmlTmplPath.toString().replace(".template", ""));
return Files.writeString(settingsXmlPath, replaced);
}

private static String replacePort(String given, Integer port) {
String regex = "(<url>http:\\/\\/localhost:)(\\d{1,5})(\\/snapshots<\\/url>)";

private static String replace(String content, Object replacement, String regex) {
Pattern compile = Pattern.compile(regex);
Matcher matcher = compile.matcher(given);
String s1 = matcher.replaceFirst("$1" + port + "$3");
Matcher matcher = compile.matcher(content);
String s1 = matcher.replaceFirst("$1" + replacement + "$3");
return s1;
}

private static Path renderPomXml(Integer port, Path pomXmlTmplPath) throws IOException {
String given = Files.readString(pomXmlTmplPath);
String replaced = given.replace($PORT_PLACEHOLDER, port.toString());
Path pomXmlPath = Path.of(pomXmlTmplPath.toString().replace(".template", ""));
return Files.writeString(pomXmlPath, replaced);
}

private void clearDependencyFromLocalMavenRepo() {
try {
FileSystemUtils.deleteRecursively(dependencyPathInLocalMavenRepo);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void deployDependency(Path pomXmlPath) throws MavenInvocationException {
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(pomXmlPath.toFile());
request.setShowErrors(true);
request.setUserSettingsFile(Path.of(TESTCODE_DIR + "/user.home/.m2/settings.xml").toFile());
request.setGoals(List.of("deploy"));
request.setLocalRepositoryDirectory(localMavenRepository);
request.setBatchMode(true);
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(Path.of(TESTCODE_DIR + "/user.home/apache-maven-3.9.5").toFile());
InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) {
if (result.getExecutionException() != null) {
fail("Maven deploy failed.", result.getExecutionException());
} else {
fail("Maven deploy failed. Exit code: " + result.getExitCode());
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -59,6 +60,10 @@ public MavenExecutionRequest createMavenExecutionRequest(PlexusContainer plexusC
request.setShowErrors(true);
request.setLocalRepositoryPath(LOCAL_REPOSITORY);
request.setPluginArtifactRepositories(List.of(repository));
File userSettingsFile = Path.of(System.getProperty("user.home")).resolve(".m2/settings.xml").toFile();
if(userSettingsFile.exists()) {
request.setUserSettingsFile(userSettingsFile);
}

List<String> activatedProfiles = mavenConfigFileParser.getActivatedProfiles(baseDir);
if (activatedProfiles.isEmpty()) {
Expand Down
32 changes: 28 additions & 4 deletions sbm-support-rewrite/testcode/reposilite-test/README.adoc
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
# Artifact Repository Test

Test that artifacts available in a private artifact repository configured in `~/.m2/settings.xml` and `~/.m2/security-settings.xml` can be accessed.
Test that artifacts available in a private artifact repository configured in `~/.m2/settings.xml` can be accessed.
This is important as many enterprise projects use their private artifact repository to retrieve private dependencies.

A local and private artifact repository (https://github.com/dzikoysk/reposilite[reposilite]) is started in a docker container.
- A private artifact repository using (https://github.com/dzikoysk/reposilite[reposilite]) is started in a Docker container.
The reposilite instance has a user configured (admin:secret) which can deploy and access artifacts.
A project that uses this dependency is parsed.
After successful dependency resolution the types of this artifact must be available on the AST.
- The repositories in the artifact repository (e.g. snapshot) require successful authentication (deploy + download).
- `dependency-project` has a simple class `DependencyClass` and gets deployed to the artifact repository.
- `dependent-project` depends on `dependency-project` and has a class `DependentClass` that uses `DependencyClass`
- `dependent-project` gets parsed
- The resulting AST has the type information of `dependency-project` resolved when the repository information and credentials were read from `settings.xml` and `security-settings.xml`.
Technical requirements:

- The port of the Docker container is dynamic and used in settings.xml and pom.xml.
- The local Maven installation of any system should not be affected by this test.
- The location of the Maven dir `.m2` must therefore point to a different location while the test is running.
This requires temporarily a different `.m2` location, here `testcode/reposilite-test/user.home/.m2`.
When deploying the `dependency-project` the path to `settings.xml` is provided, pointing to `testcode/reposilite-test/user.home/.m2/settings.xml`.
This file declares the location of the local Maven repository pointing to the same dir.
Because these paths can't be relative for this test and absolute paths


The `user.home` is set to point to `testcode/reposilite-test/user.home` which contains a `.m2` directory providing access configuration to the reposilite instance through `.m2/settings.xml` and `.m2/security-settings.xml`,
Loading

0 comments on commit ef8037d

Please sign in to comment.