1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.buildcache.its.junit;
20
21 import java.io.IOException;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.Method;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.Comparator;
28 import java.util.stream.Stream;
29
30 import org.apache.maven.it.VerificationException;
31 import org.apache.maven.it.Verifier;
32 import org.junit.jupiter.api.extension.BeforeAllCallback;
33 import org.junit.jupiter.api.extension.BeforeEachCallback;
34 import org.junit.jupiter.api.extension.ExtensionContext;
35 import org.junit.jupiter.api.extension.ParameterContext;
36 import org.junit.jupiter.api.extension.ParameterResolutionException;
37 import org.junit.jupiter.api.extension.ParameterResolver;
38 import org.junit.jupiter.api.parallel.ResourceLock;
39 import org.junit.jupiter.api.parallel.Resources;
40
41 @ResourceLock(Resources.SYSTEM_PROPERTIES)
42 public class IntegrationTestExtension implements BeforeAllCallback, BeforeEachCallback, ParameterResolver {
43
44 private static Path mavenHome;
45
46 @Override
47 public void beforeAll(ExtensionContext context) throws IOException {
48 Path basedir;
49 String basedirstr = System.getProperty("maven.basedir");
50 if (basedirstr == null) {
51 if (Files.exists(Paths.get("target/maven3"))) {
52 basedir = Paths.get("target/maven3");
53 } else if (Files.exists(Paths.get("target/maven4"))) {
54 basedir = Paths.get("target/maven4");
55 } else {
56 throw new IllegalStateException("Could not find maven home !");
57 }
58 } else {
59 basedir = Paths.get(basedirstr);
60 }
61 mavenHome = Files.list(basedir.toAbsolutePath())
62 .filter(p -> Files.exists(p.resolve("bin/mvn")))
63 .findAny()
64 .orElseThrow(() -> new IllegalStateException("Could not find maven home"));
65 System.setProperty("maven.home", mavenHome.toString());
66 mavenHome.resolve("bin/mvn").toFile().setExecutable(true);
67
68 deleteDir(Paths.get("target/build-cache/"));
69 }
70
71 @Override
72 public void beforeEach(ExtensionContext context) throws Exception {
73 final Class<?> testClass = context.getRequiredTestClass();
74 final IntegrationTest test = testClass.getAnnotation(IntegrationTest.class);
75 final String rawProjectDir = test.value();
76 final String className = context.getRequiredTestClass().getSimpleName();
77 String methodName = context.getRequiredTestMethod().getName();
78 if (rawProjectDir == null) {
79 throw new IllegalStateException("@IntegrationTest must be set");
80 }
81 final Path testDir = Paths.get("target/mvn-cache-tests/" + className + "/" + methodName)
82 .toAbsolutePath();
83 deleteDir(testDir);
84 Files.createDirectories(testDir);
85 final Path testExecutionDir;
86
87 final Path testSrcDir = Paths.get(rawProjectDir).toAbsolutePath().normalize();
88 if (!Files.exists(testSrcDir)) {
89 throw new IllegalStateException(
90 "@IntegrationTest(\"" + testSrcDir + "\") points at a path that does not exist: " + testSrcDir);
91 }
92 testExecutionDir = testDir.resolve("project");
93 try (Stream<Path> files = Files.walk(testSrcDir)) {
94 files.forEach(source -> {
95 final Path dest = testExecutionDir.resolve(testSrcDir.relativize(source));
96 try {
97 if (Files.isDirectory(source)) {
98 Files.createDirectories(dest);
99 } else {
100 Files.createDirectories(dest.getParent());
101 Files.copy(source, dest);
102 }
103 } catch (IOException e) {
104 throw new RuntimeException(e);
105 }
106 });
107 }
108
109 for (Field field : testClass.getDeclaredFields()) {
110 if (field.isAnnotationPresent(Inject.class)) {
111 if (field.getType() == Verifier.class) {
112 field.setAccessible(true);
113 field.set(context.getRequiredTestInstance(), resolveParameter(null, context));
114 }
115 }
116 }
117
118 for (Method method : testClass.getDeclaredMethods()) {
119 if (method.isAnnotationPresent(BeforeEach.class)) {
120 method.setAccessible(true);
121 method.invoke(context.getRequiredTestInstance());
122 }
123 }
124 }
125
126 @Override
127 public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
128 throws ParameterResolutionException {
129 return parameterContext.getParameter().getType() == Verifier.class;
130 }
131
132 @Override
133 public Object resolveParameter(ParameterContext parameterContext, ExtensionContext context)
134 throws ParameterResolutionException {
135 try {
136 final IntegrationTest test = context.getRequiredTestClass().getAnnotation(IntegrationTest.class);
137 final String rawProjectDir = test.value();
138 if (rawProjectDir == null) {
139 throw new IllegalStateException("value of @IntegrationTest must be set");
140 }
141
142 final String className = context.getRequiredTestClass().getSimpleName();
143 String methodName = context.getRequiredTestMethod().getName();
144 final Path testDir = Paths.get("target/mvn-cache-tests/" + className + "/" + methodName)
145 .toAbsolutePath();
146
147 deleteDir(testDir);
148 Files.createDirectories(testDir);
149
150 final Path testSrcDir = Paths.get(rawProjectDir).toAbsolutePath().normalize();
151 if (!Files.exists(testSrcDir)) {
152 throw new IllegalStateException(
153 "@IntegrationTest(\"" + testSrcDir + "\") points at a path that does not exist: " + testSrcDir);
154 }
155
156 final Path testExecutionDir = testDir.resolve("project");
157 try (Stream<Path> files = Files.walk(testSrcDir)) {
158 files.forEach(source -> {
159 final Path dest = testExecutionDir.resolve(testSrcDir.relativize(source));
160 try {
161 if (Files.isDirectory(source)) {
162 Files.createDirectories(dest);
163 } else {
164 Files.createDirectories(dest.getParent());
165 Files.copy(source, dest);
166 }
167 } catch (IOException e) {
168 throw new RuntimeException(e);
169 }
170 });
171 }
172
173 Verifier verifier = new Verifier(testExecutionDir.toString(), true);
174 verifier.setLogFileName("../log.txt");
175 verifier.setSystemProperty("projectVersion", System.getProperty("projectVersion"));
176 verifier.setLocalRepo(System.getProperty("localRepo"));
177 return verifier;
178 } catch (VerificationException | IOException e) {
179 throw new ParameterResolutionException("Unable to create Verifier", e);
180 }
181 }
182
183 public static Path deleteDir(Path dir) {
184 return deleteDir(dir, true);
185 }
186
187 public static Path deleteDir(Path dir, boolean failOnError) {
188 if (Files.exists(dir)) {
189 try (Stream<Path> files = Files.walk(dir)) {
190 files.sorted(Comparator.reverseOrder()).forEach(f -> deleteFile(f, failOnError));
191 } catch (Exception e) {
192 throw new RuntimeException("Could not walk " + dir, e);
193 }
194 }
195 return dir;
196 }
197
198 private static void deleteFile(Path f, boolean failOnError) {
199 try {
200 Files.delete(f);
201 } catch (Exception e) {
202 if (failOnError) {
203 throw new RuntimeException("Could not delete " + f, e);
204 } else {
205 System.err.println("Error deleting " + f + ": " + e);
206 }
207 }
208 }
209 }