View Javadoc
1   package org.apache.maven.surefire.its.fixture;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.it.VerificationException;
23  import org.apache.maven.it.Verifier;
24  import org.apache.maven.it.util.ResourceExtractor;
25  import org.apache.maven.shared.utils.io.FileUtils;
26  
27  import java.io.File;
28  import java.io.IOException;
29  import java.net.URL;
30  import java.util.ArrayList;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.ListIterator;
34  import java.util.Map;
35  
36  import static java.util.Collections.unmodifiableList;
37  
38  /**
39   * Encapsulate all needed features to start a maven run
40   * <br>
41   *
42   * @author Kristian Rosenvold
43   */
44  public final class MavenLauncher
45  {
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 File unpackedAt;
55  
56      private Verifier verifier;
57  
58      private OutputValidator validator;
59  
60      private final Class testCaseBeingRun;
61  
62      private final String resourceName;
63  
64      private final String suffix;
65  
66      private final String[] cli;
67  
68      private boolean expectFailure;
69  
70      MavenLauncher( Class testClass, String resourceName, String suffix, String[] cli )
71      {
72          this.testCaseBeingRun = testClass;
73          this.resourceName = resourceName;
74          this.suffix = suffix != null ? suffix : "";
75          this.cli = cli == null ? null : cli.clone();
76          resetGoals();
77          resetCliOptions();
78      }
79  
80      public MavenLauncher( Class testClass, String resourceName, String suffix )
81      {
82          this( testClass, resourceName, suffix, null );
83      }
84  
85      public File getUnpackedAt()
86      {
87          return ensureUnpacked();
88      }
89  
90      private File ensureUnpacked()
91      {
92          if ( unpackedAt == null )
93          {
94              unpackedAt = simpleExtractResources( testCaseBeingRun, resourceName );
95          }
96          return unpackedAt;
97      }
98  
99      public void moveUnpackTo( File dest ) throws IOException
100     {
101         FileUtils.deleteDirectory( dest );
102         //noinspection ResultOfMethodCallIgnored
103         getUnpackedAt().renameTo( dest );
104         unpackedAt = dest;
105     }
106 
107     private void resetGoals()
108     {
109         goals.clear();
110     }
111 
112     private void addCliOption( String cliOption )
113     {
114         cliOptions.add( cliOption );
115     }
116 
117     private StackTraceElement findTopElemenent( StackTraceElement[] stackTrace, Class testClassToLookFor )
118     {
119         StackTraceElement bestmatch = null;
120         for ( StackTraceElement stackTraceElement : stackTrace )
121         {
122             if ( stackTraceElement.getClassName().equals( testClassToLookFor.getName() ) )
123             {
124                 bestmatch = stackTraceElement;
125             }
126         }
127         return bestmatch;
128     }
129 
130     private static StackTraceElement[] getStackTraceElements()
131     {
132         try
133         {
134             throw new RuntimeException();
135         }
136         catch ( RuntimeException e )
137         {
138             return e.getStackTrace();
139         }
140     }
141 
142     public void reset()
143     {
144         resetGoals();
145         resetCliOptions();
146     }
147 
148     private void resetCliOptions()
149     {
150         cliOptions.clear();
151     }
152 
153     public MavenLauncher getSubProjectLauncher( String subProject )
154     {
155         MavenLauncher mavenLauncher =
156             new MavenLauncher( testCaseBeingRun, resourceName + File.separator + subProject, suffix, cli );
157         mavenLauncher.unpackedAt = new File( ensureUnpacked(), subProject );
158         return mavenLauncher;
159     }
160 
161     public OutputValidator getSubProjectValidator( String subProject ) throws VerificationException
162     {
163         String subProjectBasedir = getValidator().getSubFile( subProject ).getAbsolutePath();
164         String settingsXml = settingsXmlPath().getAbsolutePath();
165         Verifier subProjectVerifier = createVerifier( subProjectBasedir, settingsXml, null );
166         return new OutputValidator( subProjectVerifier );
167     }
168 
169     public MavenLauncher addEnvVar( String key, String value )
170     {
171         envVars.put( key, value );
172         return this;
173     }
174 
175     public MavenLauncher assertNotPresent( String subFile )
176     {
177         getVerifier().assertFileNotPresent( getValidator().getSubFile( subFile ).getAbsolutePath() );
178         return this;
179     }
180 
181     public MavenLauncher showErrorStackTraces()
182     {
183         addCliOption( "-e" );
184         return this;
185     }
186 
187     public MavenLauncher debugLogging()
188     {
189         addCliOption( "-X" );
190         return this;
191     }
192 
193     public MavenLauncher failNever()
194     {
195         addCliOption( "-fn" );
196         return this;
197     }
198 
199     public MavenLauncher offline()
200     {
201         addCliOption( "-o" );
202         return this;
203     }
204 
205     public MavenLauncher skipClean()
206     {
207         writeGoal( "-Dclean.skip=true" );
208         return this;
209     }
210 
211     public MavenLauncher addGoal( String goal )
212     {
213         writeGoal( goal );
214         return this;
215     }
216 
217     public FailsafeOutputValidator executeVerify()
218     {
219         return new FailsafeOutputValidator( conditionalExec( "verify" ) );
220     }
221 
222     public OutputValidator executeTest()
223     {
224         return conditionalExec( "test" );
225     }
226 
227     List<String> getGoals()
228     {
229         return unmodifiableList( goals );
230     }
231 
232     private void writeGoal( String newGoal )
233     {
234         if ( newGoal != null && newGoal.startsWith( "-D" ) )
235         {
236             String sysPropKey = newGoal.contains( "=" ) ? newGoal.substring( 0, newGoal.indexOf( '=' ) ) : newGoal;
237 
238             String sysPropStarter = sysPropKey + "=";
239 
240             for ( ListIterator<String> it = goals.listIterator(); it.hasNext(); )
241             {
242                 String goal = it.next();
243                 if ( goal.equals( sysPropKey ) || goal.startsWith( sysPropStarter ) )
244                 {
245                     System.out.printf( "[WARNING] System property already exists '%s'. Overriding to '%s'.\n", goal,
246                             newGoal );
247                     it.set( newGoal );
248                     return;
249                 }
250             }
251         }
252         goals.add( newGoal );
253     }
254 
255     private OutputValidator conditionalExec( String goal )
256     {
257         OutputValidator verify;
258         try
259         {
260             verify = execute( goal );
261         }
262         catch ( SurefireVerifierException exc )
263         {
264             if ( expectFailure )
265             {
266                 return getValidator();
267             }
268             else
269             {
270                 throw exc;
271             }
272         }
273         if ( expectFailure )
274         {
275             throw new RuntimeException( "Expecting build failure, got none!" );
276         }
277         return verify;
278     }
279 
280     public MavenLauncher withFailure()
281     {
282         expectFailure = true;
283         return this;
284     }
285 
286     public OutputValidator execute( String goal )
287     {
288         addGoal( goal );
289         return executeCurrentGoals();
290     }
291 
292     public OutputValidator executeCurrentGoals()
293     {
294         try
295         {
296             getVerifier().setCliOptions( cliOptions );
297             getVerifier().executeGoals( goals, envVars );
298             return getValidator();
299         }
300         catch ( VerificationException e )
301         {
302             throw new SurefireVerifierException( e.getLocalizedMessage(), e );
303         }
304         finally
305         {
306             getVerifier().resetStreams();
307         }
308     }
309 
310     public MavenLauncher activateProfile( String profile )
311     {
312         return addGoal( "-P" + profile );
313     }
314 
315     public MavenLauncher sysProp( String variable, String value )
316     {
317         return addGoal( "-D" + variable + "=" + value );
318     }
319 
320     public MavenLauncher sysProp( Map<String, String> properties )
321     {
322         for ( Map.Entry<String, String> property : properties.entrySet() )
323         {
324             sysProp( property.getKey(), property.getValue() );
325         }
326         return this;
327     }
328 
329     public MavenLauncher sysProp( String variable, boolean value )
330     {
331         return addGoal( "-D" + variable + "=" + value );
332     }
333 
334     public MavenLauncher sysProp( String variable, int value )
335     {
336         return addGoal( "-D" + variable + "=" + value );
337     }
338 
339     public MavenLauncher sysProp( String variable, double value )
340     {
341         return addGoal( "-D" + variable + "=" + value );
342     }
343 
344     public MavenLauncher showExceptionMessages()
345     {
346         addCliOption( "-e" );
347         return this;
348     }
349 
350     public MavenLauncher deleteSiteDir()
351     {
352         try
353         {
354             FileUtils.deleteDirectory( getValidator().getSubFile( "site" ) );
355         }
356         catch ( IOException e )
357         {
358             throw new SurefireVerifierException( e );
359         }
360         return this;
361     }
362 
363     public OutputValidator getValidator()
364     {
365         if ( validator == null )
366         {
367             validator = new OutputValidator( getVerifier() );
368         }
369         return validator;
370     }
371 
372     public void setForkJvm( boolean forkJvm )
373     {
374         getVerifier().setForkJvm( forkJvm );
375     }
376 
377     public String getLocalRepository()
378     {
379         return getVerifier().getLocalRepository();
380     }
381 
382     public void setAutoclean( boolean autoclean )
383     {
384         getVerifier().setAutoclean( autoclean );
385     }
386 
387     private Verifier getVerifier()
388     {
389         if ( verifier == null )
390         {
391             try
392             {
393                 String unpackedPath = ensureUnpacked().getAbsolutePath();
394                 String settingsXml = SETTINGS_XML_PATH.getAbsolutePath();
395                 verifier = createVerifier( unpackedPath, settingsXml, cli );
396             }
397             catch ( VerificationException e )
398             {
399                 throw new RuntimeException( e );
400             }
401         }
402         return verifier;
403     }
404 
405     private File simpleExtractResources( Class<?> cl, String resourcePath )
406     {
407         if ( !resourcePath.startsWith( "/" ) )
408         {
409             resourcePath = "/" + resourcePath;
410         }
411         File tempDir = getUnpackDir();
412         File testDir = new File( tempDir, resourcePath );
413         try
414         {
415             File parentPom = new File( tempDir.getParentFile(), "pom.xml" );
416             if ( !parentPom.exists() )
417             {
418                 URL resource = cl.getResource( "/pom.xml" );
419                 FileUtils.copyURLToFile( resource, parentPom );
420             }
421 
422             FileUtils.deleteDirectory( testDir );
423             File file = ResourceExtractor.extractResourceToDestination( cl, resourcePath, tempDir, true );
424             return file.getCanonicalFile();
425         }
426         catch ( IOException e )
427         {
428             throw new RuntimeException( e );
429         }
430     }
431 
432     private File getUnpackDir()
433     {
434         String tempDirPath = System.getProperty( "maven.test.tmpdir", System.getProperty( "java.io.tmpdir" ) );
435         return new File( tempDirPath, testCaseBeingRun.getSimpleName() + "_" + getTestMethodName() + suffix );
436     }
437 
438     public File getArtifactPath( String gid, String aid, String version, String ext )
439     {
440         return new File( verifier.getArtifactPath( gid, aid, version, ext ) );
441     }
442 
443     String getTestMethodName()
444     {
445         // dirty. Im sure we can use junit4 rules to attach testname to thread instead
446         StackTraceElement[] stackTrace = getStackTraceElements();
447         StackTraceElement topInTestClass;
448         topInTestClass = findTopElemenent( stackTrace, testCaseBeingRun );
449         if ( topInTestClass == null )
450         {
451             // Look in superclass...
452             topInTestClass = findTopElemenent( stackTrace, testCaseBeingRun.getSuperclass() );
453         }
454         if ( topInTestClass != null )
455         {
456             return topInTestClass.getMethodName();
457         }
458         throw new IllegalStateException( "Cannot find " + testCaseBeingRun.getName() + "in stacktrace" );
459     }
460 
461     private static Verifier createVerifier( String basedir, String settingsFile, String[] defaultCliOptions )
462             throws VerificationException
463     {
464         Verifier verifier = defaultCliOptions == null ? new Verifier( basedir, settingsFile, false ) : new Verifier(
465                 basedir, settingsFile, false, defaultCliOptions );
466 
467         verifier.getVerifierProperties().setProperty( "use.mavenRepoLocal", "true" );
468 
469         return verifier;
470     }
471 
472     private static File settingsXmlPath()
473     {
474         try
475         {
476             return new File( System.getProperty( "maven.settings.file" ) ).getCanonicalFile();
477         }
478         catch ( IOException e )
479         {
480             throw new IllegalStateException( e.getLocalizedMessage(), e );
481         }
482     }
483 }