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