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(conditionalExec("verify"));
209 }
210
211 public OutputValidator executeTest() {
212 return conditionalExec("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 conditionalExec(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 getVerifier().addCliArguments(cliOptions.toArray(new String[0]));
268 getVerifier().addCliArguments(goals.toArray(new String[] {}));
269 getVerifier().setSystemProperties(props);
270 getVerifier().setEnvironmentVariables(envVars);
271 if (envVars.isEmpty()) {
272 getVerifier().setForkJvm(forkJvm);
273 } else {
274 getVerifier().setForkJvm(true);
275 }
276 getVerifier().execute();
277 return getValidator();
278 } catch (VerificationException e) {
279 throw new SurefireVerifierException(e.getLocalizedMessage(), e);
280 }
281 }
282
283 public MavenLauncher activateProfile(String profile) {
284 return addGoal("-P" + profile);
285 }
286
287 public MavenLauncher sysProp(String key, String value) {
288 return sysProp(singletonMap(key, value));
289 }
290
291 public MavenLauncher sysProp(Map<String, String> properties) {
292 props.putAll(properties);
293 return this;
294 }
295
296 public MavenLauncher sysProp(String key, boolean value) {
297 return sysProp(singletonMap(key, Boolean.toString(value)));
298 }
299
300 public MavenLauncher sysProp(String key, int value) {
301 return sysProp(singletonMap(key, Integer.toString(value)));
302 }
303
304 public MavenLauncher sysProp(String key, double value) {
305 return sysProp(singletonMap(key, Double.toString(value)));
306 }
307
308 public MavenLauncher showExceptionMessages() {
309 addCliOption("-e");
310 return this;
311 }
312
313 public MavenLauncher deleteReportsDir() {
314 try {
315 FileUtils.deleteDirectory(getValidator().getSubFile("reports"));
316 } catch (IOException e) {
317 throw new SurefireVerifierException(e);
318 }
319 return this;
320 }
321
322 public OutputValidator getValidator() {
323 if (validator == null) {
324 validator = new OutputValidator(getVerifier());
325 }
326 return validator;
327 }
328
329 public void setForkJvm(boolean forkJvm) {
330 this.forkJvm = forkJvm;
331 }
332
333 public String getLocalRepository() {
334 return getVerifier().getLocalRepository();
335 }
336
337 public void setAutoclean(boolean autoclean) {
338 getVerifier().setAutoclean(autoclean);
339 }
340
341 public void setLogFileName(String logFileName) {
342 getVerifier().setLogFileName(logFileName);
343 }
344
345 private Verifier getVerifier() {
346 if (verifier == null) {
347 try {
348 String unpackedPath = ensureUnpacked().getAbsolutePath();
349 String settingsXml = SETTINGS_XML_PATH.getAbsolutePath();
350 verifier = createVerifier(unpackedPath, settingsXml, cli);
351 } catch (VerificationException e) {
352 throw new RuntimeException(e);
353 }
354 }
355 return verifier;
356 }
357
358 private File simpleExtractResources(Class<?> cl, String resourcePath) {
359 if (!resourcePath.startsWith("/")) {
360 resourcePath = "/" + resourcePath;
361 }
362 File tempDir = getUnpackDir();
363 File testDir = new File(tempDir, resourcePath);
364 try {
365 File parentPom = new File(tempDir.getParentFile(), "pom.xml");
366 if (!parentPom.exists()) {
367 URL resource = cl.getResource("/pom.xml");
368 FileUtils.copyURLToFile(resource, parentPom);
369 }
370
371 FileUtils.deleteDirectory(testDir);
372 File file = ResourceExtractor.extractResourceToDestination(cl, resourcePath, tempDir, true);
373 return file.getCanonicalFile();
374 } catch (IOException e) {
375 throw new RuntimeException(e);
376 }
377 }
378
379 private File getUnpackDir() {
380 String tempDirPath = System.getProperty("maven.test.tmpdir", System.getProperty("java.io.tmpdir"));
381 return new File(tempDirPath, testCaseBeingRun.getSimpleName() + "_" + getTestMethodName() + suffix);
382 }
383
384 public File getArtifactPath(String gid, String aid, String version, String ext) {
385 return new File(verifier.getArtifactPath(gid, aid, version, ext));
386 }
387
388 String getTestMethodName() {
389
390 StackTraceElement[] stackTrace = getStackTraceElements();
391 StackTraceElement topInTestClass;
392 topInTestClass = findTopElemenent(stackTrace, testCaseBeingRun);
393 if (topInTestClass == null) {
394
395 topInTestClass = findTopElemenent(stackTrace, testCaseBeingRun.getSuperclass());
396 }
397 if (topInTestClass != null) {
398 return topInTestClass.getMethodName();
399 }
400 throw new IllegalStateException("Cannot find " + testCaseBeingRun.getName() + "in stacktrace");
401 }
402
403 private static Verifier createVerifier(String basedir, String settingsFile, String[] defaultCliOptions)
404 throws VerificationException {
405
406 return defaultCliOptions == null
407 ? new Verifier(basedir, settingsFile, false)
408 : new Verifier(basedir, settingsFile, false, defaultCliOptions);
409 }
410
411 private static File settingsXmlPath() {
412 try {
413 return new File(System.getProperty("maven.settings.file")).getCanonicalFile();
414 } catch (IOException e) {
415 throw new IllegalStateException(e.getLocalizedMessage(), e);
416 }
417 }
418 }