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 java.io.File;
23  import java.io.IOException;
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import org.apache.commons.lang.text.StrSubstitutor;
30  import org.apache.maven.it.VerificationException;
31  import org.apache.maven.it.Verifier;
32  import org.apache.maven.it.util.ResourceExtractor;
33  import org.apache.maven.shared.utils.io.FileUtils;
34  
35  /**
36   * Encapsulate all needed features to start a maven run
37   * <p/>
38   *
39   * @author Kristian Rosenvold
40   */
41  public class MavenLauncher
42  {
43      private final List<String> cliOptions = new ArrayList<String>();
44  
45      private final List<String> goals = new ArrayList<String>();
46  
47      private final Map<String, String> envvars = new HashMap<String, String>();
48  
49      private File unpackedAt;
50  
51      private Verifier verifier;
52  
53      private OutputValidator validator;
54  
55      private final Class testCaseBeingRun;
56  
57      private final String resourceName;
58  
59      private final String suffix;
60  
61      private final String[] cli;
62  
63      private boolean expectFailure;
64  
65      public MavenLauncher( Class testClass, String resourceName, String suffix, String[] cli )
66      {
67          this.testCaseBeingRun = testClass;
68          this.resourceName = resourceName;
69          this.suffix = suffix != null ? suffix : "";
70          this.cli = cli == null ? null : cli.clone();
71          resetGoals();
72          resetCliOptions();
73      }
74  
75      public MavenLauncher( Class testClass, String resourceName, String suffix )
76      {
77          this( testClass, resourceName, suffix, null );
78      }
79  
80      public File getUnpackedAt()
81      {
82          return ensureUnpacked();
83      }
84  
85      private File ensureUnpacked()
86      {
87          if ( unpackedAt == null )
88          {
89              unpackedAt = simpleExtractResources( testCaseBeingRun, resourceName );
90          }
91          return unpackedAt;
92      }
93  
94      public void moveUnpackTo( File dest )
95          throws IOException
96      {
97          FileUtils.deleteDirectory( dest );
98          //noinspection ResultOfMethodCallIgnored
99          getUnpackedAt().renameTo( dest );
100         unpackedAt = dest;
101     }
102 
103     public void resetGoals()
104     {
105         goals.clear();
106     }
107 
108     void addCliOption( String cliOption )
109     {
110         cliOptions.add( cliOption );
111     }
112 
113 
114 
115     private StackTraceElement findTopElemenent( StackTraceElement[] stackTrace, Class testClassToLookFor )
116     {
117         StackTraceElement bestmatch = null;
118         for ( StackTraceElement stackTraceElement : stackTrace )
119         {
120             if ( stackTraceElement.getClassName().equals( testClassToLookFor.getName() ) )
121             {
122                 bestmatch = stackTraceElement;
123             }
124         }
125         return bestmatch;
126     }
127 
128     StackTraceElement[] getStackTraceElements()
129     {
130         try
131         {
132             throw new RuntimeException();
133         }
134         catch ( RuntimeException e )
135         {
136             return e.getStackTrace();
137         }
138     }
139 
140     public void reset()
141     {
142         resetGoals();
143         resetCliOptions();
144     }
145 
146     private void resetCliOptions()
147     {
148         cliOptions.clear();
149     }
150 
151     public MavenLauncher getSubProjectLauncher( String subProject )
152         throws VerificationException
153     {
154         MavenLauncher mavenLauncher =
155             new MavenLauncher( testCaseBeingRun, resourceName + File.separator + subProject, suffix, cli );
156         mavenLauncher.unpackedAt = new File( ensureUnpacked(), subProject );
157         return mavenLauncher;
158     }
159 
160     public OutputValidator getSubProjectValidator( String subProject )
161         throws VerificationException
162     {
163         final File subFile = getValidator().getSubFile( subProject );
164         return new OutputValidator( new Verifier( subFile.getAbsolutePath() ) );
165     }
166 
167 
168     public MavenLauncher addEnvVar( String key, String value )
169     {
170         envvars.put( key, value );
171         return this;
172     }
173 
174     public MavenLauncher assertNotPresent( String subFile )
175     {
176         getVerifier().assertFileNotPresent( getValidator().getSubFile( subFile ).getAbsolutePath() );
177         return this;
178     }
179 
180     public MavenLauncher showErrorStackTraces()
181     {
182         addCliOption( "-e" );
183         return this;
184     }
185 
186     public MavenLauncher debugLogging()
187     {
188         addCliOption( "-X" );
189         return this;
190     }
191 
192     public MavenLauncher failNever()
193     {
194         addCliOption( "-fn" );
195         return this;
196     }
197 
198     public MavenLauncher offline()
199     {
200         addCliOption( "-o" );
201         return this;
202     }
203 
204     public MavenLauncher skipClean()
205     {
206         goals.add( "-Dclean.skip=true" );
207         return this;
208     }
209 
210     public MavenLauncher addGoal( String goal )
211     {
212         goals.add( goal );
213         return this;
214     }
215 
216     public FailsafeOutputValidator executeVerify()
217     {
218         return new FailsafeOutputValidator( conditionalExec( "verify" ) );
219     }
220 
221     public OutputValidator executeTest()
222     {
223         return conditionalExec( "test" );
224     }
225 
226     private OutputValidator conditionalExec(String goal)
227     {
228         OutputValidator verify;
229         try
230         {
231             verify = execute( goal );
232         }
233         catch ( SurefireVerifierException exc )
234         {
235             if ( expectFailure )
236             {
237                 return getValidator();
238             }
239             else
240             {
241                 throw exc;
242             }
243         }
244         if ( expectFailure )
245         {
246             throw new RuntimeException( "Expecting build failure, got none!" );
247         }
248         return verify;
249 
250     }
251 
252     public MavenLauncher withFailure()
253     {
254         this.expectFailure = true;
255         return this;
256     }
257 
258 
259     public OutputValidator execute( String goal )
260     {
261         addGoal( goal );
262         return executeCurrentGoals();
263     }
264 
265     public OutputValidator executeCurrentGoals()
266     {
267 
268         String userLocalRepo = System.getProperty( "user.localRepository" );
269         String testBuildDirectory = System.getProperty( "testBuildDirectory" );
270         boolean useInterpolatedSettings = Boolean.getBoolean( "useInterpolatedSettings" );
271 
272         try
273         {
274             if ( useInterpolatedSettings )
275             {
276                 File interpolatedSettings = new File( testBuildDirectory, "interpolated-settings" );
277 
278                 if ( !interpolatedSettings.exists() )
279                 {
280                     // hack "a la" invoker plugin to download dependencies from local repo
281                     // and not download from central
282 
283                     Map<String, String> values = new HashMap<String, String>( 1 );
284                     values.put( "localRepositoryUrl", toUrl( userLocalRepo ) );
285                     StrSubstitutor strSubstitutor = new StrSubstitutor( values );
286 
287                     String fileContent = FileUtils.fileRead( new File( testBuildDirectory, "settings.xml" ) );
288 
289                     String filtered = strSubstitutor.replace( fileContent );
290 
291                     FileUtils.fileWrite( interpolatedSettings.getAbsolutePath(), filtered );
292 
293                 }
294 
295                 addCliOption( "-s " + interpolatedSettings.getCanonicalPath() );
296             }
297             getVerifier().setCliOptions( cliOptions );
298 
299             getVerifier().executeGoals( goals, envvars );
300             return getValidator();
301         }
302         catch ( IOException e )
303         {
304             throw new SurefireVerifierException( e.getMessage(), e );
305         }
306         catch ( VerificationException e )
307         {
308             throw new SurefireVerifierException( e.getMessage(), e );
309         }
310         finally
311         {
312             getVerifier().resetStreams();
313         }
314     }
315 
316     private static String toUrl( String filename )
317     {
318         /*
319          * NOTE: Maven fails to properly handle percent-encoded "file:" URLs (WAGON-111) so don't use File.toURI() here
320          * as-is but use the decoded path component in the URL.
321          */
322         String url = "file://" + new File( filename ).toURI().getPath();
323         if ( url.endsWith( "/" ) )
324         {
325             url = url.substring( 0, url.length() - 1 );
326         }
327         return url;
328     }
329 
330     public MavenLauncher activateProfile( String profile )
331     {
332         return addGoal( "-P" + profile );
333     }
334 
335     public MavenLauncher sysProp( String variable, String value )
336     {
337         return addGoal( "-D" + variable + "=" + value );
338     }
339 
340     public MavenLauncher sysProp( Map<String, String> properties )
341     {
342         for ( Map.Entry<String, String> property : properties.entrySet() )
343         {
344             sysProp( property.getKey(), property.getValue() );
345         }
346         return this;
347     }
348 
349     public MavenLauncher sysProp( String variable, boolean value )
350     {
351         return addGoal( "-D" + variable + "=" + value );
352     }
353 
354     public MavenLauncher sysProp( String variable, int value )
355     {
356         return addGoal( "-D" + variable + "=" + value );
357     }
358 
359     public MavenLauncher sysProp( String variable, double value )
360     {
361         return addGoal( "-D" + variable + "=" + value );
362     }
363 
364     public MavenLauncher showExceptionMessages()
365     {
366         addCliOption( "-e" );
367         return this;
368     }
369 
370     public MavenLauncher deleteSiteDir()
371     {
372         try
373         {
374             FileUtils.deleteDirectory( getValidator().getSubFile( "site" ) );
375         }
376         catch ( IOException e )
377         {
378             throw new SurefireVerifierException( e );
379         }
380         return this;
381     }
382 
383     public OutputValidator getValidator()
384     {
385         if ( validator == null )
386         {
387             this.validator = new OutputValidator( getVerifier() );
388         }
389         return validator;
390     }
391 
392     public void setForkJvm( boolean forkJvm ) {
393         getVerifier().setForkJvm( forkJvm );
394     }
395 
396     private Verifier getVerifier()
397     {
398         if ( verifier == null )
399         {
400             try
401             {
402                 verifier =
403                     cli == null
404                     ? new Verifier( ensureUnpacked().getAbsolutePath(), null, false )
405                     : new Verifier( ensureUnpacked().getAbsolutePath(), null, false, cli );
406             }
407             catch ( VerificationException e )
408             {
409                 throw new RuntimeException( e );
410             }
411         }
412         return verifier;
413     }
414     
415     private File simpleExtractResources( Class<?> cl, String resourcePath )
416     {
417         if ( !resourcePath.startsWith( "/" ) )
418         {
419             resourcePath = "/" + resourcePath;
420         }
421         File tempDir = getUnpackDir();
422         File testDir = new File( tempDir, resourcePath );
423         try
424         {
425             File parentPom = new File( tempDir.getParentFile(), "pom.xml" );
426             if (!parentPom.exists()){
427                 URL resource = cl.getResource( "/pom.xml" );
428                 FileUtils.copyURLToFile( resource, parentPom );
429             }
430 
431             FileUtils.deleteDirectory( testDir );
432             File file = ResourceExtractor.extractResourceToDestination( cl, resourcePath, tempDir, true );
433             return file.getCanonicalFile();
434         }
435         catch ( IOException e )
436         {
437             throw new RuntimeException( e );
438         }
439 
440     }
441 
442     File getUnpackDir()
443     {
444         String tempDirPath = System.getProperty( "maven.test.tmpdir", System.getProperty( "java.io.tmpdir" ) );
445         return new File( tempDirPath,
446                          testCaseBeingRun.getSimpleName() + "_" + getTestMethodName() + suffix );
447     }
448 
449     public File getArtifactPath( String gid, String aid, String version, String ext )
450     {
451         return new File( verifier.getArtifactPath( gid, aid, version, ext ) );
452     }
453 
454     String getTestMethodName()
455     {
456         // dirty. Im sure we can use junit4 rules to attach testname to thread instead
457         StackTraceElement[] stackTrace = getStackTraceElements();
458         StackTraceElement topInTestClass;
459         topInTestClass = findTopElemenent( stackTrace, testCaseBeingRun );
460         if ( topInTestClass == null )
461         {
462             // Look in superclass...
463             topInTestClass = findTopElemenent( stackTrace, testCaseBeingRun.getSuperclass() );
464         }
465         if ( topInTestClass != null )
466         {
467             return topInTestClass.getMethodName();
468         }
469         throw new IllegalStateException( "Cannot find " + testCaseBeingRun.getName() + "in stacktrace" );
470     }
471 }