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