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 the
203      * <a href="http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html">
204      *     http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html</a>;
205      * for a more detailed explanation of manifest-only JARs and their benefits.)
206      * <br/>
207      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
208      *
209      * @since 2.4.3
210      */
211     @Parameter( property = "failsafe.useManifestOnlyJar", defaultValue = "true" )
212     private boolean useManifestOnlyJar;
213 
214     /**
215      * The character encoding scheme to be applied.
216      */
217     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
218     private String encoding;
219 
220     /**
221      * (JUnit 4+ providers)
222      * The number of times each failing test will be rerun. If set larger than 0, rerun failing tests immediately after
223      * they fail. If a failing test passes in any of those reruns, it will be marked as pass and reported as a "flake".
224      * However, all the failing attempts will be recorded.
225      */
226     @Parameter( property = "failsafe.rerunFailingTestsCount", defaultValue = "0" )
227     protected int rerunFailingTestsCount;
228 
229     /**
230      * (TestNG) List of &lt;suiteXmlFile> elements specifying TestNG suite xml file locations. Note that
231      * <code>suiteXmlFiles</code> is incompatible with several other parameters of this plugin, like
232      * <code>includes/excludes</code>.<br/>
233      * This parameter is ignored if the <code>test</code> parameter is specified (allowing you to run a single test
234      * instead of an entire suite).
235      *
236      * @since 2.2
237      */
238     @Parameter( property = "failsafe.suiteXmlFiles" )
239     private File[] suiteXmlFiles;
240 
241     /**
242      * Defines the order the tests will be run in. Supported values are "alphabetical", "reversealphabetical", "random",
243      * "hourly" (alphabetical on even hours, reverse alphabetical on odd hours), "failedfirst", "balanced" and
244      * "filesystem".
245      * <br/>
246      * <br/>
247      * Odd/Even for hourly is determined at the time the of scanning the classpath, meaning it could change during a
248      * multi-module build.
249      * <br/>
250      * <br/>
251      * Failed first will run tests that failed on previous run first, as well as new tests for this run.
252      * <br/>
253      * <br/>
254      * Balanced is only relevant with parallel=classes, and will try to optimize the run-order of the tests reducing the
255      * overall execution time. Initially a statistics file is created and every next test run will reorder classes.
256      * <br/>
257      * <br/>
258      * Note that the statistics are stored in a file named .surefire-XXXXXXXXX beside pom.xml, and should not be checked
259      * into version control. The "XXXXX" is the SHA1 checksum of the entire surefire configuration, so different
260      * configurations will have different statistics files, meaning if you change any config settings you will re-run
261      * once before new statistics data can be established.
262      *
263      * @since 2.7
264      */
265     @Parameter( property = "failsafe.runOrder", defaultValue = "filesystem" )
266     protected String runOrder;
267 
268     protected int getRerunFailingTestsCount()
269     {
270         return rerunFailingTestsCount;
271     }
272 
273     protected void handleSummary( RunResult summary, Exception firstForkException )
274         throws MojoExecutionException, MojoFailureException
275     {
276         writeSummary( summary, firstForkException );
277     }
278 
279     @SuppressWarnings( "unchecked" )
280     private void writeSummary( RunResult summary, Exception firstForkException )
281         throws MojoExecutionException
282     {
283         File summaryFile = getSummaryFile();
284         if ( !summaryFile.getParentFile().isDirectory() )
285         {
286             //noinspection ResultOfMethodCallIgnored
287             summaryFile.getParentFile().mkdirs();
288         }
289 
290         FileOutputStream fout = null;
291         FileInputStream fin = null;
292         try
293         {
294             Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
295             summary.writeSummary( summaryFile, token != null, getEncodingOrDefault() );
296         }
297         catch ( IOException e )
298         {
299             throw new MojoExecutionException( e.getMessage(), e );
300         }
301         finally
302         {
303             close( fin );
304             close( fout );
305         }
306 
307         getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
308     }
309 
310     private String getEncodingOrDefault()
311     {
312         if ( StringUtils.isEmpty( encoding ) )
313         {
314             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
315                            + ", i.e. build is platform dependent! The file encoding for reports output files "
316                                + "should be provided by the POM property ${project.reporting.outputEncoding}." );
317             return ReaderFactory.FILE_ENCODING;
318         }
319         else
320         {
321             return encoding;
322         }
323     }
324 
325     @SuppressWarnings( "deprecation" )
326     protected boolean isSkipExecution()
327     {
328         return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
329     }
330 
331     protected String getPluginName()
332     {
333         return "failsafe";
334     }
335 
336     protected String[] getDefaultIncludes()
337     {
338         return new String[]{ "**/IT*.java", "**/*IT.java", "**/*ITCase.java" };
339     }
340 
341     public boolean isSkipTests()
342     {
343         return skipTests;
344     }
345 
346     public void setSkipTests( boolean skipTests )
347     {
348         this.skipTests = skipTests;
349     }
350 
351     public boolean isSkipITs()
352     {
353         return skipITs;
354     }
355 
356     public void setSkipITs( boolean skipITs )
357     {
358         this.skipITs = skipITs;
359     }
360 
361     @SuppressWarnings( "deprecation" )
362     @Deprecated
363     public boolean isSkipExec()
364     {
365         return skipExec;
366     }
367 
368     @SuppressWarnings( "deprecation" )
369     @Deprecated
370     public void setSkipExec( boolean skipExec )
371     {
372         this.skipExec = skipExec;
373     }
374 
375     public boolean isSkip()
376     {
377         return skip;
378     }
379 
380     public void setSkip( boolean skip )
381     {
382         this.skip = skip;
383     }
384 
385     public File getBasedir()
386     {
387         return basedir;
388     }
389 
390     public void setBasedir( File basedir )
391     {
392         this.basedir = basedir;
393     }
394 
395     public File getTestClassesDirectory()
396     {
397         return testClassesDirectory;
398     }
399 
400     public void setTestClassesDirectory( File testClassesDirectory )
401     {
402         this.testClassesDirectory = testClassesDirectory;
403     }
404 
405     public File getClassesDirectory()
406     {
407         return classesDirectory;
408     }
409 
410     public void setClassesDirectory( File classesDirectory )
411     {
412         this.classesDirectory = classesDirectory;
413     }
414 
415     public File getReportsDirectory()
416     {
417         return reportsDirectory;
418     }
419 
420     public void setReportsDirectory( File reportsDirectory )
421     {
422         this.reportsDirectory = reportsDirectory;
423     }
424 
425     public String getTest()
426     {
427         if ( StringUtils.isBlank( test ) )
428         {
429             return null;
430         }
431         int index = test.indexOf( '#' );
432         if ( index >= 0 )
433         {
434             return test.substring( 0, index );
435         }
436         return test;
437     }
438 
439     public void setTest( String test )
440     {
441         this.test = test;
442     }
443 
444     /**
445      * @since 2.7.3
446      */
447     public String getTestMethod()
448     {
449         if ( StringUtils.isBlank( test ) )
450         {
451             return null;
452         }
453         int index = this.test.indexOf( '#' );
454         if ( index >= 0 )
455         {
456             return this.test.substring( index + 1, this.test.length() );
457         }
458         return null;
459     }
460 
461 
462     public File getSummaryFile()
463     {
464         return summaryFile;
465     }
466 
467     public void setSummaryFile( File summaryFile )
468     {
469         this.summaryFile = summaryFile;
470     }
471 
472     public boolean isPrintSummary()
473     {
474         return printSummary;
475     }
476 
477     public void setPrintSummary( boolean printSummary )
478     {
479         this.printSummary = printSummary;
480     }
481 
482     public String getReportFormat()
483     {
484         return reportFormat;
485     }
486 
487     public void setReportFormat( String reportFormat )
488     {
489         this.reportFormat = reportFormat;
490     }
491 
492     public boolean isUseFile()
493     {
494         return useFile;
495     }
496 
497     public void setUseFile( boolean useFile )
498     {
499         this.useFile = useFile;
500     }
501 
502     public String getDebugForkedProcess()
503     {
504         return debugForkedProcess;
505     }
506 
507     public void setDebugForkedProcess( String debugForkedProcess )
508     {
509         this.debugForkedProcess = debugForkedProcess;
510     }
511 
512     public int getForkedProcessTimeoutInSeconds()
513     {
514         return forkedProcessTimeoutInSeconds;
515     }
516 
517     public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
518     {
519         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
520     }
521 
522     public double getParallelTestsTimeoutInSeconds()
523     {
524         return parallelTestsTimeoutInSeconds;
525     }
526 
527     public void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds )
528     {
529         this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
530     }
531 
532     public double getParallelTestsTimeoutForcedInSeconds()
533     {
534         return parallelTestsTimeoutForcedInSeconds;
535     }
536 
537     public void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds )
538     {
539         this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
540     }
541 
542     public boolean isUseSystemClassLoader()
543     {
544         return useSystemClassLoader;
545     }
546 
547     public void setUseSystemClassLoader( boolean useSystemClassLoader )
548     {
549         this.useSystemClassLoader = useSystemClassLoader;
550     }
551 
552     public boolean isUseManifestOnlyJar()
553     {
554         return useManifestOnlyJar;
555     }
556 
557     public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
558     {
559         this.useManifestOnlyJar = useManifestOnlyJar;
560     }
561 
562     // the following will be refactored out once the common code is all in one place
563 
564     public boolean isTestFailureIgnore()
565     {
566         return true; // ignore
567     }
568 
569     public void setTestFailureIgnore( boolean testFailureIgnore )
570     {
571         // ignore
572     }
573 
574     protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
575     {
576         checksum.add( skipITs );
577         checksum.add( summaryFile );
578     }
579 
580     public Boolean getFailIfNoSpecifiedTests()
581     {
582         return failIfNoSpecifiedTests;
583     }
584 
585     public void setFailIfNoSpecifiedTests( Boolean failIfNoSpecifiedTests )
586     {
587         this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
588     }
589 
590     @Override
591     public List<String> getIncludes()
592     {
593         return includes;
594     }
595 
596     @Override
597     public void setIncludes( List<String> includes )
598     {
599         this.includes = includes;
600     }
601 
602     public File[] getSuiteXmlFiles()
603     {
604         return suiteXmlFiles;
605     }
606 
607     @SuppressWarnings( "UnusedDeclaration" )
608     public void setSuiteXmlFiles( File[] suiteXmlFiles )
609     {
610         this.suiteXmlFiles = suiteXmlFiles;
611     }
612 
613     public String getRunOrder()
614     {
615         return runOrder;
616     }
617 
618     @SuppressWarnings( "UnusedDeclaration" )
619     public void setRunOrder( String runOrder )
620     {
621         this.runOrder = runOrder;
622     }
623 }