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