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