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