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 org.apache.maven.execution.MavenSession;
23  import org.apache.maven.plugin.AbstractMojo;
24  import org.apache.maven.plugin.MojoExecutionException;
25  import org.apache.maven.plugin.MojoFailureException;
26  import org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils;
27  import org.apache.maven.plugin.surefire.SurefireHelper;
28  import org.apache.maven.plugin.surefire.SurefireReportParameters;
29  import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
30  import org.apache.maven.plugins.annotations.Component;
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.surefire.api.cli.CommandLineOption;
35  import org.apache.maven.surefire.api.suite.RunResult;
36  import org.codehaus.plexus.logging.Logger;
37  
38  import java.io.File;
39  import java.util.Collection;
40  
41  import static org.apache.maven.plugin.surefire.SurefireHelper.reportExecution;
42  import static org.apache.maven.surefire.shared.utils.StringUtils.capitalizeFirstLetter;
43  import static org.apache.maven.surefire.api.suite.RunResult.noTestsRun;
44  
45  /**
46   * Verify integration tests ran using Surefire.
47   *
48   * @author Stephen Connolly
49   * @author Jason van Zyl
50   */
51  @SuppressWarnings( "unused" )
52  @Mojo( name = "verify", defaultPhase = LifecyclePhase.VERIFY, requiresProject = true, threadSafe = true )
53  public class VerifyMojo
54          extends AbstractMojo
55          implements SurefireReportParameters
56  {
57  
58      /**
59       * Set this to 'true' to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite
60       * convenient on occasion.
61       *
62       * @since 2.4
63       */
64      @Parameter( property = "skipTests" )
65      private boolean skipTests;
66  
67      /**
68       * Set this to 'true' to skip running integration tests, but still compile them. Its use is NOT RECOMMENDED, but
69       * quite convenient on occasion.
70       *
71       * @since 2.4.3-alpha-2
72       */
73      @Parameter( property = "skipITs" )
74      private boolean skipITs;
75  
76      /**
77       * This old parameter is just like skipTests, but bound to the old property maven.test.skip.exec.
78       *
79       * @since 2.3
80       * @deprecated Use -DskipTests instead.
81       */
82      @Deprecated
83      @Parameter( property = "maven.test.skip.exec" )
84      private boolean skipExec;
85  
86      /**
87       * Set this to 'true' to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you
88       * enable it using the "maven.test.skip" property, because maven.test.skip disables both running the
89       * tests and compiling the tests.  Consider using the skipTests parameter instead.
90       */
91      @Parameter( property = "maven.test.skip", defaultValue = "false" )
92      private boolean skip;
93  
94      /**
95       * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on
96       * occasion.
97       */
98      @Parameter( property = "maven.test.failure.ignore", defaultValue = "false" )
99      private boolean testFailureIgnore;
100 
101     /**
102      * The base directory of the project being tested. This can be obtained in your unit test by
103      * System.getProperty("basedir").
104      */
105     @Parameter( defaultValue = "${basedir}" )
106     private File basedir;
107 
108     /**
109      * The directory containing generated test classes of the project being tested.
110      * This will be included at the beginning the test classpath.
111      */
112     @Parameter( defaultValue = "${project.build.testOutputDirectory}" )
113     private File testClassesDirectory;
114 
115     /**
116      * Base directory where all reports are written to.
117      */
118     @Parameter( defaultValue = "${project.build.directory}/failsafe-reports" )
119     private File reportsDirectory;
120 
121     /**
122      * The summary file to read integration test results from.
123      */
124     @Parameter( defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true )
125     private File summaryFile;
126 
127     /**
128      * Additional summary files to read integration test results from.
129      * @since 2.6
130      */
131     @Parameter
132     private File[] summaryFiles;
133 
134     /**
135      * Set this to "true" to cause a failure if there are no tests to run. Defaults to "false".
136      *
137      * @since 2.4
138      */
139     @Parameter( property = "failIfNoTests", defaultValue = "false" )
140     private boolean failIfNoTests;
141 
142     /**
143      * Set this to a value greater than 0 to fail the whole test set if the cumulative number of flakes reaches
144      * this threshold. Set to 0 to allow an unlimited number of flakes.
145      * 
146      * @since 3.0.0-M6
147      */
148     @Parameter( property = "failsafe.failOnFlakeCount", defaultValue = "0" )
149     private int failOnFlakeCount;
150 
151     /**
152      * The character encoding scheme to be applied.
153      * Deprecated since 2.20.1 and used encoding UTF-8 in <code>failsafe-summary.xml</code>.
154      *
155      * @deprecated since of 2.20.1
156      */
157     @Parameter( property = "encoding", defaultValue = "${project.reporting.outputEncoding}" )
158     private String encoding;
159 
160     /**
161      * The current build session instance.
162      */
163     @Parameter( defaultValue = "${session}", readonly = true )
164     private MavenSession session;
165 
166     @Component
167     private Logger logger;
168 
169     private Collection<CommandLineOption> cli;
170 
171     private volatile PluginConsoleLogger consoleLogger;
172 
173     @Override
174     public void execute()
175             throws MojoExecutionException, MojoFailureException
176     {
177         cli = commandLineOptions();
178         if ( verifyParameters() )
179         {
180             logDebugOrCliShowErrors( capitalizeFirstLetter( getPluginName() )
181                                              + " report directory: " + getReportsDirectory() );
182 
183             RunResult summary;
184             try
185             {
186                 summary = existsSummaryFile() ? readSummary( summaryFile ) : noTestsRun();
187 
188                 if ( existsSummaryFiles() )
189                 {
190                     for ( final File summaryFile : summaryFiles )
191                     {
192                         summary = summary.aggregate( readSummary( summaryFile ) );
193                     }
194                 }
195             }
196             catch ( Exception e )
197             {
198                 throw new MojoExecutionException( e.getMessage(), e );
199             }
200 
201             reportExecution( this, summary, getConsoleLogger(), null );
202         }
203     }
204 
205     private PluginConsoleLogger getConsoleLogger()
206     {
207         if ( consoleLogger == null )
208         {
209             synchronized ( this )
210             {
211                 if ( consoleLogger == null )
212                 {
213                     consoleLogger = new PluginConsoleLogger( logger );
214                 }
215             }
216         }
217         return consoleLogger;
218     }
219 
220     private RunResult readSummary( File summaryFile ) throws Exception
221     {
222         return FailsafeSummaryXmlUtils.toRunResult( summaryFile );
223     }
224 
225     protected boolean verifyParameters()
226             throws MojoFailureException
227     {
228         if ( isSkip() || isSkipTests() || isSkipITs() || isSkipExec() )
229         {
230             getConsoleLogger().info( "Tests are skipped." );
231             return false;
232         }
233 
234         if ( !getTestClassesDirectory().exists() )
235         {
236             if ( getFailIfNoTests() )
237             {
238                 throw new MojoFailureException( "No tests to run!" );
239             }
240         }
241 
242         if ( !existsSummary() )
243         {
244             getConsoleLogger().info( "No tests to run." );
245             return false;
246         }
247 
248         if ( failOnFlakeCount < 0 )
249         {
250             throw new MojoFailureException( "Parameter \"failOnFlakeCount\" should not be negative." );
251         }
252 
253         return true;
254     }
255 
256     protected String getPluginName()
257     {
258         return "failsafe";
259     }
260 
261     protected String[] getDefaultIncludes()
262     {
263         return null;
264     }
265 
266     @Override
267     public boolean isSkipTests()
268     {
269         return skipTests;
270     }
271 
272     @Override
273     public void setSkipTests( boolean skipTests )
274     {
275         this.skipTests = skipTests;
276     }
277 
278     public boolean isSkipITs()
279     {
280         return skipITs;
281     }
282 
283     public void setSkipITs( boolean skipITs )
284     {
285         this.skipITs = skipITs;
286     }
287 
288     @Override
289     @Deprecated
290     public boolean isSkipExec()
291     {
292         return skipExec;
293     }
294 
295     @Override
296     @Deprecated
297     public void setSkipExec( boolean skipExec )
298     {
299         this.skipExec = skipExec;
300     }
301 
302     @Override
303     public boolean isSkip()
304     {
305         return skip;
306     }
307 
308     @Override
309     public void setSkip( boolean skip )
310     {
311         this.skip = skip;
312     }
313 
314     @Override
315     public boolean isTestFailureIgnore()
316     {
317         return testFailureIgnore;
318     }
319 
320     @Override
321     public void setTestFailureIgnore( boolean testFailureIgnore )
322     {
323         this.testFailureIgnore = testFailureIgnore;
324     }
325 
326     @Override
327     public File getBasedir()
328     {
329         return basedir;
330     }
331 
332     @Override
333     public void setBasedir( File basedir )
334     {
335         this.basedir = basedir;
336     }
337 
338     @Override
339     public File getTestClassesDirectory()
340     {
341         return testClassesDirectory;
342     }
343 
344     @Override
345     public void setTestClassesDirectory( File testClassesDirectory )
346     {
347         this.testClassesDirectory = testClassesDirectory;
348     }
349 
350     @Override
351     public File getReportsDirectory()
352     {
353         return reportsDirectory;
354     }
355 
356     @Override
357     public void setReportsDirectory( File reportsDirectory )
358     {
359         this.reportsDirectory = reportsDirectory;
360     }
361 
362     @Override
363     public boolean getFailIfNoTests()
364     {
365         return failIfNoTests;
366     }
367 
368     @Override
369     public void setFailIfNoTests( boolean failIfNoTests )
370     {
371         this.failIfNoTests = failIfNoTests;
372     }
373 
374     @Override
375     public int getFailOnFlakeCount()
376     {
377         return failOnFlakeCount;
378     }
379 
380     @Override
381     public void setFailOnFlakeCount( int failOnFlakeCount )
382     {
383         this.failOnFlakeCount = failOnFlakeCount;
384     }
385 
386     private boolean existsSummaryFile()
387     {
388         return summaryFile != null && summaryFile.isFile();
389     }
390 
391     private boolean existsSummaryFiles()
392     {
393         return summaryFiles != null && summaryFiles.length != 0;
394     }
395 
396     private boolean existsSummary()
397     {
398         return existsSummaryFile() || existsSummaryFiles();
399     }
400 
401     private Collection<CommandLineOption> commandLineOptions()
402     {
403         return SurefireHelper.commandLineOptions( session, getConsoleLogger() );
404     }
405 
406     private void logDebugOrCliShowErrors( String s )
407     {
408         SurefireHelper.logDebugOrCliShowErrors( s, getConsoleLogger(), cli );
409     }
410 
411 }