View Javadoc

1   package org.apache.maven.plugin.failsafe;
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.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.util.List;
27  
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
31  import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
32  import org.apache.maven.plugins.annotations.LifecyclePhase;
33  import org.apache.maven.plugins.annotations.Mojo;
34  import org.apache.maven.plugins.annotations.Parameter;
35  import org.apache.maven.plugins.annotations.ResolutionScope;
36  import org.apache.maven.shared.utils.ReaderFactory;
37  import org.apache.maven.shared.utils.StringUtils;
38  import org.apache.maven.surefire.suite.RunResult;
39  import org.apache.maven.surefire.util.NestedCheckedException;
40  
41  import static org.apache.maven.shared.utils.io.IOUtil.close;
42  
43  /**
44   * Run integration tests using Surefire.
45   *
46   * @author Jason van Zyl
47   * @author Stephen Connolly
48   * @noinspection JavaDoc,
49   */
50  @Mojo( name = "integration-test", requiresProject = true, requiresDependencyResolution = ResolutionScope.TEST,
51         defaultPhase = LifecyclePhase.INTEGRATION_TEST, threadSafe = true )
52  public class IntegrationTestMojo
53      extends AbstractSurefireMojo
54  {
55  
56      private static final String FAILSAFE_IN_PROGRESS_CONTEXT_KEY = "failsafe-in-progress";
57  
58      /**
59       * Set this to "true" to skip running integration tests, but still compile them. Its use is NOT RECOMMENDED, but
60       * quite convenient on occasion.
61       *
62       * @since 2.4.3-alpha-2
63       */
64      @Parameter( property = "skipITs" )
65      private boolean skipITs;
66  
67      /**
68       * Base directory where all reports are written to.
69       */
70      @Parameter( defaultValue = "${project.build.directory}/failsafe-reports" )
71      private File reportsDirectory;
72  
73      /**
74       * Specify this parameter to run individual tests by file name, overriding the <code>includes/excludes</code>
75       * parameters. Each pattern you specify here will be used to create an include pattern formatted like
76       * <code>**&#47;${test}.java</code>, so you can just type "-Dit.test=MyTest" to run a single test called
77       * "foo/MyTest.java".<br/>
78       * This parameter overrides the <code>includes/excludes</code> parameters, and the TestNG <code>suiteXmlFiles</code>
79       * parameter.
80       * <p/>
81       * since 2.7.3 You can execute a limited number of method in the test with adding #myMethod or #my*ethod. Si type
82       * "-Dtest=MyTest#myMethod" <b>supported for junit 4.x and testNg</b>
83       */
84      @Parameter( property = "it.test" )
85      private String test;
86  
87      /**
88       * The summary file to write integration test results to.
89       */
90      @Parameter( defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true )
91      private File summaryFile;
92  
93      /**
94       * Option to print summary of test suites or just print the test cases that have errors.
95       */
96      @Parameter( property = "failsafe.printSummary", defaultValue = "true" )
97      private boolean printSummary;
98  
99      /**
100      * Selects the formatting for the test report to be generated. Can be set as "brief" or "plain".
101      * Only applies to the output format of the output files  (target/surefire-reports/testName.txt)
102      */
103     @Parameter( property = "failsafe.reportFormat", defaultValue = "brief" )
104     private String reportFormat;
105 
106     /**
107      * Option to generate a file test report or just output the test report to the console.
108      */
109     @Parameter( property = "failsafe.useFile", defaultValue = "true" )
110     private boolean useFile;
111 
112     /**
113      * Set this to "true" to cause a failure if the none of the tests specified in -Dtest=... are run. Defaults to
114      * "true".
115      *
116      * @since 2.12
117      */
118     @Parameter( property = "it.failIfNoSpecifiedTests" )
119     private Boolean failIfNoSpecifiedTests;
120 
121     /**
122      * Attach a debugger to the forked JVM. If set to "true", the process will suspend and wait for a debugger to attach
123      * on port 5005. If set to some other string, that string will be appended to the argLine, allowing you to configure
124      * arbitrary debuggability options (without overwriting the other options specified through the <code>argLine</code>
125      * parameter).
126      *
127      * @since 2.4
128      */
129     @Parameter( property = "maven.failsafe.debug" )
130     private String debugForkedProcess;
131 
132     /**
133      * Kill the forked test process after a certain number of seconds. If set to 0, wait forever for the process, never
134      * timing out.
135      *
136      * @since 2.4
137      */
138     @Parameter( property = "failsafe.timeout" )
139     private int forkedProcessTimeoutInSeconds;
140     
141     /**
142      * A list of &lt;include> elements specifying the tests (by pattern) that should be included in testing. When not
143      * specified and when the <code>test</code> parameter is not specified, the default includes will be <code><br/>
144      * &lt;includes><br/>
145      * &nbsp;&lt;include>**&#47;IT*.java&lt;/include><br/>
146      * &nbsp;&lt;include>**&#47;*IT.java&lt;/include><br/>
147      * &nbsp;&lt;include>**&#47;*ITCase.java&lt;/include><br/>
148      * &lt;/includes><br/>
149      * </code>
150      * <p/>
151      * Each include item may also contain a comma-separated sublist of items, which will be treated as multiple
152      * &nbsp;&lt;include> entries.<br/>
153      * <p/>
154      * This parameter is ignored if the TestNG <code>suiteXmlFiles</code> parameter is specified.
155      */
156     @Parameter
157     private List<String> includes;
158 
159     /**
160      * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
161      * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
162      * classloader.
163      *
164      * @since 2.3
165      */
166     @Parameter( property = "failsafe.useSystemClassLoader", defaultValue = "true" )
167     private boolean useSystemClassLoader;
168 
169     /**
170      * By default, Surefire forks your tests using a manifest-only JAR; set this parameter to "false" to force it to
171      * launch your tests with a plain old Java classpath. (See
172      * http://maven.apache.org/plugins/maven-surefire-plugin/examples/class-loading.html for a more detailed explanation
173      * of manifest-only JARs and their benefits.)
174      * <p/>
175      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
176      *
177      * @since 2.4.3
178      */
179     @Parameter( property = "failsafe.useManifestOnlyJar", defaultValue = "true" )
180     private boolean useManifestOnlyJar;
181 
182     /**
183      * The character encoding scheme to be applied.
184      */
185     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
186     private String encoding;
187 
188     protected void handleSummary( RunResult summary, NestedCheckedException firstForkException )
189         throws MojoExecutionException, MojoFailureException
190     {
191         writeSummary( summary, firstForkException );
192     }
193 
194     @SuppressWarnings( "unchecked" )
195     private void writeSummary( RunResult summary, NestedCheckedException firstForkException )
196         throws MojoExecutionException
197     {
198         File summaryFile = getSummaryFile();
199         if ( !summaryFile.getParentFile().isDirectory() )
200         {
201             //noinspection ResultOfMethodCallIgnored
202             summaryFile.getParentFile().mkdirs();
203         }
204 
205         FileOutputStream fout = null;
206         FileInputStream fin = null;
207         try
208         {
209             Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
210             summary.writeSummary( summaryFile, token != null, getEncodingOrDefault() );
211         }
212         catch ( IOException e )
213         {
214             throw new MojoExecutionException( e.getMessage(), e );
215         }
216         finally
217         {
218             close( fin );
219             close( fout );
220         }
221 
222         getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
223     }
224 
225     private String getEncodingOrDefault()
226     {
227         if ( StringUtils.isEmpty( encoding ) )
228         {
229             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING +
230                                ", i.e. build is platform dependent!" );
231             return ReaderFactory.FILE_ENCODING;
232         }
233         else
234         {
235             return encoding;
236         }
237     }
238 
239     @SuppressWarnings( "deprecation" )
240     protected boolean isSkipExecution()
241     {
242         return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
243     }
244 
245     protected String getPluginName()
246     {
247         return "failsafe";
248     }
249 
250     protected String[] getDefaultIncludes()
251     {
252         return new String[]{ "**/IT*.java", "**/*IT.java", "**/*ITCase.java" };
253     }
254 
255     public boolean isSkipTests()
256     {
257         return skipTests;
258     }
259 
260     public void setSkipTests( boolean skipTests )
261     {
262         this.skipTests = skipTests;
263     }
264 
265     public boolean isSkipITs()
266     {
267         return skipITs;
268     }
269 
270     public void setSkipITs( boolean skipITs )
271     {
272         this.skipITs = skipITs;
273     }
274 
275     @SuppressWarnings( "deprecation" )
276     @Deprecated
277     public boolean isSkipExec()
278     {
279         return skipExec;
280     }
281 
282     @SuppressWarnings( "deprecation" )
283     @Deprecated
284     public void setSkipExec( boolean skipExec )
285     {
286         this.skipExec = skipExec;
287     }
288 
289     public boolean isSkip()
290     {
291         return skip;
292     }
293 
294     public void setSkip( boolean skip )
295     {
296         this.skip = skip;
297     }
298 
299     public File getBasedir()
300     {
301         return basedir;
302     }
303 
304     public void setBasedir( File basedir )
305     {
306         this.basedir = basedir;
307     }
308 
309     public File getTestClassesDirectory()
310     {
311         return testClassesDirectory;
312     }
313 
314     public void setTestClassesDirectory( File testClassesDirectory )
315     {
316         this.testClassesDirectory = testClassesDirectory;
317     }
318 
319     public File getClassesDirectory()
320     {
321         return classesDirectory;
322     }
323 
324     public void setClassesDirectory( File classesDirectory )
325     {
326         this.classesDirectory = classesDirectory;
327     }
328 
329     public File getReportsDirectory()
330     {
331         return reportsDirectory;
332     }
333 
334     public void setReportsDirectory( File reportsDirectory )
335     {
336         this.reportsDirectory = reportsDirectory;
337     }
338 
339     public String getTest()
340     {
341         if ( StringUtils.isBlank( test ) )
342         {
343             return null;
344         }
345         int index = test.indexOf( '#' );
346         if ( index >= 0 )
347         {
348             return test.substring( 0, index );
349         }
350         return test;
351     }
352 
353     public void setTest( String test )
354     {
355         this.test = test;
356     }
357 
358     /**
359      * @since 2.7.3
360      */
361     public String getTestMethod()
362     {
363         if ( StringUtils.isBlank( test ) )
364         {
365             return null;
366         }
367         int index = this.test.indexOf( '#' );
368         if ( index >= 0 )
369         {
370             return this.test.substring( index + 1, this.test.length() );
371         }
372         return null;
373     }
374 
375 
376     public File getSummaryFile()
377     {
378         return summaryFile;
379     }
380 
381     public void setSummaryFile( File summaryFile )
382     {
383         this.summaryFile = summaryFile;
384     }
385 
386     public boolean isPrintSummary()
387     {
388         return printSummary;
389     }
390 
391     public void setPrintSummary( boolean printSummary )
392     {
393         this.printSummary = printSummary;
394     }
395 
396     public String getReportFormat()
397     {
398         return reportFormat;
399     }
400 
401     public void setReportFormat( String reportFormat )
402     {
403         this.reportFormat = reportFormat;
404     }
405 
406     public boolean isUseFile()
407     {
408         return useFile;
409     }
410 
411     public void setUseFile( boolean useFile )
412     {
413         this.useFile = useFile;
414     }
415 
416     public String getDebugForkedProcess()
417     {
418         return debugForkedProcess;
419     }
420 
421     public void setDebugForkedProcess( String debugForkedProcess )
422     {
423         this.debugForkedProcess = debugForkedProcess;
424     }
425 
426     public int getForkedProcessTimeoutInSeconds()
427     {
428         return forkedProcessTimeoutInSeconds;
429     }
430 
431     public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
432     {
433         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
434     }
435 
436     public boolean isUseSystemClassLoader()
437     {
438         return useSystemClassLoader;
439     }
440 
441     public void setUseSystemClassLoader( boolean useSystemClassLoader )
442     {
443         this.useSystemClassLoader = useSystemClassLoader;
444     }
445 
446     public boolean isUseManifestOnlyJar()
447     {
448         return useManifestOnlyJar;
449     }
450 
451     public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
452     {
453         this.useManifestOnlyJar = useManifestOnlyJar;
454     }
455 
456     // the following will be refactored out once the common code is all in one place
457 
458     public boolean isTestFailureIgnore()
459     {
460         return true; // ignore
461     }
462 
463     public void setTestFailureIgnore( boolean testFailureIgnore )
464     {
465         // ignore
466     }
467 
468     protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
469     {
470         checksum.add( skipITs );
471         checksum.add( summaryFile );
472     }
473 
474     public Boolean getFailIfNoSpecifiedTests()
475     {
476         return failIfNoSpecifiedTests;
477     }
478 
479     public void setFailIfNoSpecifiedTests( Boolean failIfNoSpecifiedTests )
480     {
481         this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
482     }
483 
484     @Override
485     public List<String> getIncludes()
486     {
487         return includes;
488     }
489 
490     @Override
491     public void setIncludes( List<String> includes )
492     {
493         this.includes = includes;
494     }
495 }