1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.surefire.its.fixture;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.URL;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.ListIterator;
28 import java.util.Map;
29 import java.util.Properties;
30
31 import org.apache.maven.shared.utils.io.FileUtils;
32 import org.apache.maven.shared.verifier.VerificationException;
33 import org.apache.maven.shared.verifier.Verifier;
34 import org.apache.maven.shared.verifier.util.ResourceExtractor;
35
36 import static java.util.Collections.singletonMap;
37 import static java.util.Collections.unmodifiableList;
38
39
40
41
42
43
44
45 public final class MavenLauncher {
46 private static final File SETTINGS_XML_PATH = settingsXmlPath();
47
48 private final List<String> cliOptions = new ArrayList<>();
49
50 private final List<String> goals = new ArrayList<>();
51
52 private final Map<String, String> envVars = new HashMap<>();
53
54 private final Properties props = new Properties();
55
56 private File unpackedAt;
57
58 private Verifier verifier;
59
60 private OutputValidator validator;
61
62 private final Class<?> testCaseBeingRun;
63
64 private final String resourceName;
65
66 private final String suffix;
67
68 private final String[] cli;
69
70 private boolean expectFailure;
71
72 private boolean forkJvm;
73
74 MavenLauncher(Class<?> testClass, String resourceName, String suffix, String[] cli) {
75 this.testCaseBeingRun = testClass;
76 this.resourceName = resourceName;
77 this.suffix = suffix != null ? suffix : "";
78 this.cli = cli == null ? null : cli.clone();
79
80 this.forkJvm = false;
81 resetGoals();
82 resetCliOptions();
83 }
84
85 public MavenLauncher(Class<?> testClass, String resourceName, String suffix) {
86 this(testClass, resourceName, suffix, null);
87 }
88
89 public File getUnpackedAt() {
90 return ensureUnpacked();
91 }
92
93 private File ensureUnpacked() {
94 if (unpackedAt == null) {
95 unpackedAt = simpleExtractResources(testCaseBeingRun, resourceName);
96 }
97 return unpackedAt;
98 }
99
100 public void moveUnpackTo(File dest) throws IOException {
101 FileUtils.deleteDirectory(dest);
102
103 boolean moved = getUnpackedAt().renameTo(dest);
104 if (!moved) {
105 String fileEncoding = System.getProperty("file.encoding");
106 String os = System.getProperty("os.name");
107 String version = System.getProperty("os.version");
108 String arch = System.getProperty("os.arch");
109 throw new IOException("Could not move " + getUnpackedAt() + " to " + dest + " (file.encoding="
110 + fileEncoding + ", " + os + " " + version + " " + arch + ").");
111 }
112 unpackedAt = dest;
113 }
114
115 private void resetGoals() {
116 goals.clear();
117 }
118
119 private void addCliOption(String cliOption) {
120 cliOptions.add(cliOption);
121 }
122
123 private StackTraceElement findTopElemenent(StackTraceElement[] stackTrace, Class<?> testClassToLookFor) {
124 StackTraceElement bestmatch = null;
125 for (StackTraceElement stackTraceElement : stackTrace) {
126 if (stackTraceElement.getClassName().equals(testClassToLookFor.getName())) {
127 bestmatch = stackTraceElement;
128 }
129 }
130 return bestmatch;
131 }
132
133 private static StackTraceElement[] getStackTraceElements() {
134 try {
135 throw new RuntimeException();
136 } catch (RuntimeException e) {
137 return e.getStackTrace();
138 }
139 }
140
141 public void reset() {
142 resetGoals();
143 resetCliOptions();
144 verifier = null;
145 validator = null;
146 }
147
148 private void resetCliOptions() {
149 cliOptions.clear();
150 }
151
152 public MavenLauncher getSubProjectLauncher(String subProject) {
153 MavenLauncher mavenLauncher =
154 new MavenLauncher(testCaseBeingRun, resourceName + File.separator + subProject, suffix, cli);
155 mavenLauncher.unpackedAt = new File(ensureUnpacked(), subProject);
156 return mavenLauncher;
157 }
158
159 public OutputValidator getSubProjectValidator(String subProject) throws VerificationException {
160 String subProjectBasedir = getValidator().getSubFile(subProject).getAbsolutePath();
161 String settingsXml = settingsXmlPath().getAbsolutePath();
162 Verifier subProjectVerifier = createVerifier(subProjectBasedir, settingsXml, null);
163 return new OutputValidator(subProjectVerifier);
164 }
165
166 public MavenLauncher addEnvVar(String key, String value) {
167 envVars.put(key, value);
168 return this;
169 }
170
171 public MavenLauncher verifyFileNotPresent(String subFile) throws VerificationException {
172 getVerifier().verifyFileNotPresent(getValidator().getSubFile(subFile).getAbsolutePath());
173 return this;
174 }
175
176 public MavenLauncher showErrorStackTraces() {
177 addCliOption("-e");
178 return this;
179 }
180
181 public MavenLauncher debugLogging() {
182 addCliOption("-X");
183 return this;
184 }
185
186 public MavenLauncher failNever() {
187 addCliOption("-fn");
188 return this;
189 }
190
191 public MavenLauncher offline() {
192 addCliOption("-o");
193 return this;
194 }
195
196 public MavenLauncher skipClean() {
197 writeGoal("-Dclean.skip=true" );
198 writeGoal("-Dmaven.clean.skip=true" );
199 return this;
200 }
201
202 public MavenLauncher addGoal(String goal) {
203 writeGoal(goal);
204 return this;
205 }
206
207 public FailsafeOutputValidator executeVerify() {
208 return new FailsafeOutputValidator(executeGoal("verify"));
209 }
210
211 public OutputValidator executeTest() {
212 return executeGoal("test");
213 }
214
215 List<String> getGoals() {
216 return unmodifiableList(goals);
217 }
218
219 private void writeGoal(String newGoal) {
220 if (newGoal != null && newGoal.startsWith("-D")) {
221 String sysPropKey = newGoal.contains("=") ? newGoal.substring(0, newGoal.indexOf('=')) : newGoal;
222
223 String sysPropStarter = sysPropKey + "=";
224
225 for (ListIterator<String> it = goals.listIterator(); it.hasNext(); ) {
226 String goal = it.next();
227 if (goal.equals(sysPropKey) || goal.startsWith(sysPropStarter)) {
228 System.out.printf(
229 "[WARNING] System property already exists '%s'. Overriding to '%s'.%n", goal, newGoal);
230 it.set(newGoal);
231 return;
232 }
233 }
234 }
235 goals.add(newGoal);
236 }
237
238 private OutputValidator executeGoal(String goal) {
239 OutputValidator verify;
240 try {
241 verify = execute(goal);
242 } catch (SurefireVerifierException exc) {
243 if (expectFailure) {
244 return getValidator();
245 } else {
246 throw exc;
247 }
248 }
249 if (expectFailure) {
250 throw new RuntimeException("Expecting build failure, have got none!");
251 }
252 return verify;
253 }
254
255 public MavenLauncher withFailure() {
256 expectFailure = true;
257 return this;
258 }
259
260 public OutputValidator execute(String goal) {
261 addGoal(goal);
262 return executeCurrentGoals();
263 }
264
265 public OutputValidator executeCurrentGoals() {
266 try {
267 props.put("maven.build.cache.enabled", "false");
268 getVerifier().addCliArguments(cliOptions.toArray(new String[0]));
269 getVerifier().addCliArguments(goals.toArray(new String[] {}));
270 getVerifier().setSystemProperties(props);
271 getVerifier().setEnvironmentVariables(envVars);
272 if (envVars.isEmpty()) {
273 getVerifier().setForkJvm(forkJvm);
274 } else {
275 getVerifier().setForkJvm(true);
276 }
277 getVerifier().execute();
278 return getValidator();
279 } catch (VerificationException e) {
280 throw new SurefireVerifierException(e.getLocalizedMessage(), e);
281 }
282 }
283
284 public MavenLauncher activateProfile(String profile) {
285 return addGoal("-P" + profile);
286 }
287
288 public MavenLauncher sysProp(String key, String value) {
289 return sysProp(singletonMap(key, value));
290 }
291
292 public MavenLauncher sysProp(Map<String, String> properties) {
293 props.putAll(properties);
294 return this;
295 }
296
297 public MavenLauncher sysProp(String key, boolean value) {
298 return sysProp(singletonMap(key, Boolean.toString(value)));
299 }
300
301 public MavenLauncher sysProp(String key, int value) {
302 return sysProp(singletonMap(key, Integer.toString(value)));
303 }
304
305 public MavenLauncher sysProp(String key, double value) {
306 return sysProp(singletonMap(key, Double.toString(value)));
307 }
308
309 public MavenLauncher showExceptionMessages() {
310 addCliOption("-e");
311 return this;
312 }
313
314 public MavenLauncher deleteReportsDir() {
315 try {
316 FileUtils.deleteDirectory(getValidator().getSubFile("reports"));
317 } catch (IOException e) {
318 throw new SurefireVerifierException(e);
319 }
320 return this;
321 }
322
323 public OutputValidator getValidator() {
324 if (validator == null) {
325 validator = new OutputValidator(getVerifier());
326 }
327 return validator;
328 }
329
330 public void setForkJvm(boolean forkJvm) {
331 this.forkJvm = forkJvm;
332 }
333
334 public String getLocalRepository() {
335 return getVerifier().getLocalRepository();
336 }
337
338 public void setAutoclean(boolean autoclean) {
339 getVerifier().setAutoclean(autoclean);
340 }
341
342 public void setLogFileName(String logFileName) {
343 getVerifier().setLogFileName(logFileName);
344 }
345
346 private Verifier getVerifier() {
347 if (verifier == null) {
348 try {
349 String unpackedPath = ensureUnpacked().getAbsolutePath();
350 String settingsXml = SETTINGS_XML_PATH.getAbsolutePath();
351 verifier = createVerifier(unpackedPath, settingsXml, cli);
352 } catch (VerificationException e) {
353 throw new RuntimeException(e);
354 }
355 }
356 return verifier;
357 }
358
359 private File simpleExtractResources(Class<?> cl, String resourcePath) {
360 if (!resourcePath.startsWith("/")) {
361 resourcePath = "/" + resourcePath;
362 }
363 File tempDir = getUnpackDir();
364 File testDir = new File(tempDir, resourcePath);
365 try {
366 File parentPom = new File(tempDir.getParentFile(), "pom.xml");
367 if (!parentPom.exists()) {
368 URL resource = cl.getResource("/pom.xml");
369 FileUtils.copyURLToFile(resource, parentPom);
370 }
371
372 FileUtils.deleteDirectory(testDir);
373 File file = ResourceExtractor.extractResourceToDestination(cl, resourcePath, tempDir, true);
374 return file.getCanonicalFile();
375 } catch (IOException e) {
376 throw new RuntimeException(e);
377 }
378 }
379
380 private File getUnpackDir() {
381 String tempDirPath = System.getProperty("maven.test.tmpdir", System.getProperty("java.io.tmpdir"));
382 return new File(tempDirPath, testCaseBeingRun.getSimpleName() + "_" + getTestMethodName() + suffix);
383 }
384
385 public File getArtifactPath(String gid, String aid, String version, String ext) {
386 return new File(verifier.getArtifactPath(gid, aid, version, ext));
387 }
388
389 String getTestMethodName() {
390
391 StackTraceElement[] stackTrace = getStackTraceElements();
392 StackTraceElement topInTestClass;
393 topInTestClass = findTopElemenent(stackTrace, testCaseBeingRun);
394 if (topInTestClass == null) {
395
396 topInTestClass = findTopElemenent(stackTrace, testCaseBeingRun.getSuperclass());
397 }
398 if (topInTestClass != null) {
399 return topInTestClass.getMethodName();
400 }
401 throw new IllegalStateException("Cannot find " + testCaseBeingRun.getName() + "in stacktrace");
402 }
403
404 private static Verifier createVerifier(String basedir, String settingsFile, String[] defaultCliOptions)
405 throws VerificationException {
406
407 return defaultCliOptions == null
408 ? new Verifier(basedir, settingsFile, false)
409 : new Verifier(basedir, settingsFile, false, defaultCliOptions);
410 }
411
412 private static File settingsXmlPath() {
413 try {
414 return new File(System.getProperty("maven.settings.file")).getCanonicalFile();
415 } catch (IOException e) {
416 throw new IllegalStateException(e.getLocalizedMessage(), e);
417 }
418 }
419 }