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.
181      */
182     @Parameter
183     private List<String> includes;
184 
185     /**
186      * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
187      * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
188      * classloader.
189      *
190      * @since 2.3
191      */
192     @Parameter( property = "failsafe.useSystemClassLoader", defaultValue = "true" )
193     private boolean useSystemClassLoader;
194 
195     /**
196      * By default, Surefire forks your tests using a manifest-only JAR; set this parameter to "false" to force it to
197      * launch your tests with a plain old Java classpath. (See
198      * http://maven.apache.org/plugins/maven-surefire-plugin/examples/class-loading.html for a more detailed explanation
199      * of manifest-only JARs and their benefits.)
200      * <p/>
201      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
202      *
203      * @since 2.4.3
204      */
205     @Parameter( property = "failsafe.useManifestOnlyJar", defaultValue = "true" )
206     private boolean useManifestOnlyJar;
207 
208     /**
209      * The character encoding scheme to be applied.
210      */
211     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
212     private String encoding;
213 
214     protected void handleSummary( RunResult summary, Exception firstForkException )
215         throws MojoExecutionException, MojoFailureException
216     {
217         writeSummary( summary, firstForkException );
218     }
219 
220     @SuppressWarnings( "unchecked" )
221     private void writeSummary( RunResult summary, Exception firstForkException )
222         throws MojoExecutionException
223     {
224         File summaryFile = getSummaryFile();
225         if ( !summaryFile.getParentFile().isDirectory() )
226         {
227             //noinspection ResultOfMethodCallIgnored
228             summaryFile.getParentFile().mkdirs();
229         }
230 
231         FileOutputStream fout = null;
232         FileInputStream fin = null;
233         try
234         {
235             Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
236             summary.writeSummary( summaryFile, token != null, getEncodingOrDefault() );
237         }
238         catch ( IOException e )
239         {
240             throw new MojoExecutionException( e.getMessage(), e );
241         }
242         finally
243         {
244             close( fin );
245             close( fout );
246         }
247 
248         getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
249     }
250 
251     private String getEncodingOrDefault()
252     {
253         if ( StringUtils.isEmpty( encoding ) )
254         {
255             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING +
256                                ", i.e. build is platform dependent!" );
257             return ReaderFactory.FILE_ENCODING;
258         }
259         else
260         {
261             return encoding;
262         }
263     }
264 
265     @SuppressWarnings( "deprecation" )
266     protected boolean isSkipExecution()
267     {
268         return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
269     }
270 
271     protected String getPluginName()
272     {
273         return "failsafe";
274     }
275 
276     protected String[] getDefaultIncludes()
277     {
278         return new String[]{ "**/IT*.java", "**/*IT.java", "**/*ITCase.java" };
279     }
280 
281     public boolean isSkipTests()
282     {
283         return skipTests;
284     }
285 
286     public void setSkipTests( boolean skipTests )
287     {
288         this.skipTests = skipTests;
289     }
290 
291     public boolean isSkipITs()
292     {
293         return skipITs;
294     }
295 
296     public void setSkipITs( boolean skipITs )
297     {
298         this.skipITs = skipITs;
299     }
300 
301     @SuppressWarnings( "deprecation" )
302     @Deprecated
303     public boolean isSkipExec()
304     {
305         return skipExec;
306     }
307 
308     @SuppressWarnings( "deprecation" )
309     @Deprecated
310     public void setSkipExec( boolean skipExec )
311     {
312         this.skipExec = skipExec;
313     }
314 
315     public boolean isSkip()
316     {
317         return skip;
318     }
319 
320     public void setSkip( boolean skip )
321     {
322         this.skip = skip;
323     }
324 
325     public File getBasedir()
326     {
327         return basedir;
328     }
329 
330     public void setBasedir( File basedir )
331     {
332         this.basedir = basedir;
333     }
334 
335     public File getTestClassesDirectory()
336     {
337         return testClassesDirectory;
338     }
339 
340     public void setTestClassesDirectory( File testClassesDirectory )
341     {
342         this.testClassesDirectory = testClassesDirectory;
343     }
344 
345     public File getClassesDirectory()
346     {
347         return classesDirectory;
348     }
349 
350     public void setClassesDirectory( File classesDirectory )
351     {
352         this.classesDirectory = classesDirectory;
353     }
354 
355     public File getReportsDirectory()
356     {
357         return reportsDirectory;
358     }
359 
360     public void setReportsDirectory( File reportsDirectory )
361     {
362         this.reportsDirectory = reportsDirectory;
363     }
364 
365     public String getTest()
366     {
367         if ( StringUtils.isBlank( test ) )
368         {
369             return null;
370         }
371         int index = test.indexOf( '#' );
372         if ( index >= 0 )
373         {
374             return test.substring( 0, index );
375         }
376         return test;
377     }
378 
379     public void setTest( String test )
380     {
381         this.test = test;
382     }
383 
384     /**
385      * @since 2.7.3
386      */
387     public String getTestMethod()
388     {
389         if ( StringUtils.isBlank( test ) )
390         {
391             return null;
392         }
393         int index = this.test.indexOf( '#' );
394         if ( index >= 0 )
395         {
396             return this.test.substring( index + 1, this.test.length() );
397         }
398         return null;
399     }
400 
401 
402     public File getSummaryFile()
403     {
404         return summaryFile;
405     }
406 
407     public void setSummaryFile( File summaryFile )
408     {
409         this.summaryFile = summaryFile;
410     }
411 
412     public boolean isPrintSummary()
413     {
414         return printSummary;
415     }
416 
417     public void setPrintSummary( boolean printSummary )
418     {
419         this.printSummary = printSummary;
420     }
421 
422     public String getReportFormat()
423     {
424         return reportFormat;
425     }
426 
427     public void setReportFormat( String reportFormat )
428     {
429         this.reportFormat = reportFormat;
430     }
431 
432     public boolean isUseFile()
433     {
434         return useFile;
435     }
436 
437     public void setUseFile( boolean useFile )
438     {
439         this.useFile = useFile;
440     }
441 
442     public String getDebugForkedProcess()
443     {
444         return debugForkedProcess;
445     }
446 
447     public void setDebugForkedProcess( String debugForkedProcess )
448     {
449         this.debugForkedProcess = debugForkedProcess;
450     }
451 
452     public int getForkedProcessTimeoutInSeconds()
453     {
454         return forkedProcessTimeoutInSeconds;
455     }
456 
457     public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
458     {
459         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
460     }
461 
462     public double getParallelTestsTimeoutInSeconds() {
463         return parallelTestsTimeoutInSeconds;
464     }
465 
466     public void setParallelTestsTimeoutInSeconds( double parallelTestsTimeoutInSeconds ) {
467         this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
468     }
469 
470     public double getParallelTestsTimeoutForcedInSeconds() {
471         return parallelTestsTimeoutForcedInSeconds;
472     }
473 
474     public void setParallelTestsTimeoutForcedInSeconds( double parallelTestsTimeoutForcedInSeconds ) {
475         this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
476     }
477 
478     public boolean isUseSystemClassLoader()
479     {
480         return useSystemClassLoader;
481     }
482 
483     public void setUseSystemClassLoader( boolean useSystemClassLoader )
484     {
485         this.useSystemClassLoader = useSystemClassLoader;
486     }
487 
488     public boolean isUseManifestOnlyJar()
489     {
490         return useManifestOnlyJar;
491     }
492 
493     public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
494     {
495         this.useManifestOnlyJar = useManifestOnlyJar;
496     }
497 
498     // the following will be refactored out once the common code is all in one place
499 
500     public boolean isTestFailureIgnore()
501     {
502         return true; // ignore
503     }
504 
505     public void setTestFailureIgnore( boolean testFailureIgnore )
506     {
507         // ignore
508     }
509 
510     protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
511     {
512         checksum.add( skipITs );
513         checksum.add( summaryFile );
514     }
515 
516     public Boolean getFailIfNoSpecifiedTests()
517     {
518         return failIfNoSpecifiedTests;
519     }
520 
521     public void setFailIfNoSpecifiedTests( Boolean failIfNoSpecifiedTests )
522     {
523         this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
524     }
525 
526     @Override
527     public List<String> getIncludes()
528     {
529         return includes;
530     }
531 
532     @Override
533     public void setIncludes( List<String> includes )
534     {
535         this.includes = includes;
536     }
537 }