View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.failsafe;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.util.List;
24  
25  import org.apache.maven.plugin.MojoExecutionException;
26  import org.apache.maven.plugin.MojoFailureException;
27  import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
28  import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
29  import org.apache.maven.plugins.annotations.LifecyclePhase;
30  import org.apache.maven.plugins.annotations.Mojo;
31  import org.apache.maven.plugins.annotations.Parameter;
32  import org.apache.maven.plugins.annotations.ResolutionScope;
33  import org.apache.maven.surefire.api.suite.RunResult;
34  import org.apache.maven.surefire.extensions.ForkNodeFactory;
35  
36  import static org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils.writeSummary;
37  
38  /**
39   * Run integration tests using Surefire.
40   *
41   * @author Jason van Zyl
42   * @author Stephen Connolly
43   */
44  @Mojo(
45          name = "integration-test",
46          requiresProject = true,
47          requiresDependencyResolution = ResolutionScope.TEST,
48          defaultPhase = LifecyclePhase.INTEGRATION_TEST,
49          threadSafe = true)
50  public class IntegrationTestMojo extends AbstractSurefireMojo {
51  
52      private static final String FAILSAFE_IN_PROGRESS_CONTEXT_KEY = "failsafe-in-progress";
53  
54      /**
55       * The path representing project <em>JAR</em> file, if exists; Otherwise the directory containing generated
56       * classes of the project being tested. This will be included after the test classes in the test classpath.
57       * Defaults to built artifact <em>JAR</em> file or <code>${project.build.outputDirectory}</code>.
58       */
59      @Parameter
60      private File classesDirectory;
61  
62      @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true, required = true)
63      private File defaultClassesDirectory;
64  
65      /**
66       * Set this to "true" to skip running integration tests, but still compile them. Its use is NOT RECOMMENDED, but
67       * quite convenient on occasion.
68       *
69       * @since 2.4.3-alpha-2
70       */
71      @Parameter(property = "skipITs")
72      private boolean skipITs;
73  
74      /**
75       * Base directory where all reports are written to.
76       */
77      @Parameter(defaultValue = "${project.build.directory}/failsafe-reports")
78      private File reportsDirectory;
79  
80      @SuppressWarnings("checkstyle:linelength")
81      /**
82       * Specify this parameter to run individual tests by file name, overriding parameter {@code includes} and
83       * {@code excludes}. Each pattern you specify here will be used to create an include pattern formatted like
84       * <code>**{@literal /}${it.test}.java</code>, so you can just type {@code -Dit.test=MyIT} to run
85       * a single test file called "foo/MyIT.java". The test patterns prefixed with a <em>!</em> will be excluded.
86       * <br>
87       * This parameter overrides the parameter {@code includes} and {@code excludes}.
88       * <br>
89       * Since 2.7.3 You can execute a limited number of methods in the test with adding <i>#myMethod</i> or
90       * <i>#my*ethod</i>. E.g. type {@code -Dit.test=MyIT#myMethod} <b>supported for junit 4.x and TestNg.</b>
91       * <br>
92       * Since 2.19 a complex syntax is supported in one parameter:
93       * <pre><code>"-Dit.test=???IT, !Unstable*, pkg{@literal /}**{@literal /}Ci*leIT.java, *IT#test*One+testTwo?????, #fast*+slowTest"</code></pre>
94       * or e.g.
95       * <br>
96       * <pre><code>"-Dit.test=Basic*, !%regex[.*.Unstable.*], !%regex[.*.MyIT.class#one.*|two.*], %regex[#fast.*|slow.*]"</code></pre>
97       * <br>
98       * The Parameterized JUnit runner {@code describes} test methods using an index in brackets, so the non-regex
99       * method pattern would become: {@code #testMethod[*]}. If using <code>@Parameters(name="{index}: fib({0})={1}")</code>
100      * and selecting the index e.g. 5 in pattern, the non-regex method pattern would become {@code #testMethod[5:*]}.
101      */
102     @Parameter(property = "it.test")
103     private String test;
104 
105     /**
106      * The summary file to write integration test results to.
107      */
108     @Parameter(defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true)
109     private File summaryFile;
110 
111     /**
112      * Option to print summary of test suites or just print the test cases that have errors.
113      */
114     @Parameter(property = "failsafe.printSummary", defaultValue = "true")
115     private boolean printSummary;
116 
117     /**
118      * Selects the formatting for the test report to be generated. Can be set as "brief" or "plain".
119      * Only applies to the output format of the output files  (target/surefire-reports/testName.txt)
120      */
121     @Parameter(property = "failsafe.reportFormat", defaultValue = "brief")
122     private String reportFormat;
123 
124     /**
125      * Option to generate a file test report or just output the test report to the console.
126      */
127     @Parameter(property = "failsafe.useFile", defaultValue = "true")
128     private boolean useFile;
129 
130     /**
131      * Set this to "false" to prevent a failure if none of the tests specified in -Dit.test=... are run. Defaults to
132      * "true".
133      *
134      * @since 2.12
135      * @deprecated Since 3.0.0-M8, use "failsafe.failIfNoSpecifiedTests" instead.
136      */
137     @Deprecated
138     @Parameter(property = "it.failIfNoSpecifiedTests", defaultValue = "true")
139     private boolean failIfNoSpecifiedTestsDeprecated;
140 
141     /**
142      * Set this to "false" to prevent a failure if none of the tests specified in -Dit.test=... are run. Defaults to
143      * "true".
144      * Replacing "it.failIfNoSpecifiedTests" to be consistent with surefire plugin.
145      *
146      * @since 3.0.0-M8
147      */
148     @Parameter(property = "failsafe.failIfNoSpecifiedTests", defaultValue = "true")
149     private boolean failIfNoSpecifiedTests;
150 
151     /**
152      * Attach a debugger to the forked JVM. If set to "true", the process will suspend and wait for a debugger to attach
153      * on port 5005. If set to some other string, that string will be appended to the argLine, allowing you to configure
154      * arbitrary debugging ability options (without overwriting the other options specified through the {@code argLine}
155      * parameter).
156      *
157      * @since 2.4
158      */
159     @Parameter(property = "maven.failsafe.debug")
160     private String debugForkedProcess;
161 
162     /**
163      * Kill the forked test process after a certain number of seconds. If set to 0, wait forever for the process, never
164      * timing out.
165      *
166      * @since 2.4
167      */
168     @Parameter(property = "failsafe.timeout")
169     private int forkedProcessTimeoutInSeconds;
170 
171     /**
172      * Forked process is normally terminated without any significant delay after given tests have completed.
173      * If the particular tests started non-daemon Thread(s), the process hangs instead of been properly terminated
174      * by {@code System.exit()}. Use this parameter in order to determine the timeout of terminating the process.
175      * <a href="http://maven.apache.org/surefire/maven-failsafe-plugin/examples/shutdown.html">see the documentation:
176      * http://maven.apache.org/surefire/maven-failsafe-plugin/examples/shutdown.html</a>
177      *
178      * @since 2.20
179      */
180     @Parameter(property = "failsafe.exitTimeout", defaultValue = "30")
181     private int forkedProcessExitTimeoutInSeconds;
182 
183     /**
184      * Stop executing queued parallel JUnit tests after a certain number of seconds.
185      * <br>
186      * Example values: "3.5", "4"<br>
187      * <br>
188      * If set to 0, wait forever, never timing out.
189      * Makes sense with specified {@code parallel} different from "none".
190      *
191      * @since 2.16
192      */
193     @Parameter(property = "failsafe.parallel.timeout")
194     private double parallelTestsTimeoutInSeconds;
195 
196     /**
197      * Stop executing queued parallel JUnit tests
198      * and <i>interrupt</i> currently running tests after a certain number of seconds.
199      * <br>
200      * Example values: "3.5", "4"<br>
201      * <br>
202      * If set to 0, wait forever, never timing out.
203      * Makes sense with specified {@code parallel} different from "none".
204      *
205      * @since 2.16
206      */
207     @Parameter(property = "failsafe.parallel.forcedTimeout")
208     private double parallelTestsTimeoutForcedInSeconds;
209 
210     @SuppressWarnings("checkstyle:linelength")
211     /**
212      * A list of {@literal <include>} elements specifying the test filter (by pattern) of tests which should be
213      * included in testing. If it is not specified and the {@code test} parameter is unspecified as well, the default
214      * includes is
215      * <pre><code>
216      * {@literal <includes>}
217      *     {@literal <include>}**{@literal /}IT*.java{@literal </include>}
218      *     {@literal <include>}**{@literal /}*IT.java{@literal </include>}
219      *     {@literal <include>}**{@literal /}*ITCase.java{@literal </include>}
220      * {@literal </includes>}
221      * </code></pre>
222      * <br>
223      * Each include item may also contain a comma-separated sublist of items, which will be treated as multiple
224      * {@literal <include>} entries.<br>
225      * Since 2.19 a complex syntax is supported in one parameter (JUnit 4, JUnit 4.7+, TestNG):
226      * <pre><code>
227      * {@literal <include>}%regex[.*[Cat|Dog].*], Basic????, !Unstable*{@literal </include>}
228      * {@literal <include>}%regex[.*[Cat|Dog].*], !%regex[pkg.*Slow.*.class], pkg{@literal /}**{@literal /}*Fast*.java{@literal </include>}
229      * </code></pre>
230      * <br>
231      * <br>
232      * <b>Notice that</b> these values are relative to the directory containing generated test classes of the project
233      * being tested. This directory is declared by the parameter {@code testClassesDirectory} which defaults
234      * to the POM property <code>${project.build.testOutputDirectory}</code>, typically
235      * <code>{@literal src/test/java}</code> unless overridden.
236      */
237     @Parameter(property = "failsafe.includes")
238     // TODO use regex for fully qualified class names in 3.0 and change the filtering abilities
239     private List<String> includes;
240 
241     /**
242      * A list of {@literal <exclude>} elements specifying the tests (by pattern) that should be excluded in testing.
243      * When not specified and when the {@code test} parameter is not specified, the default excludes will be <br>
244      * <pre><code>
245      * {@literal <excludes>}
246      *     {@literal <exclude>}**{@literal /}*$*{@literal </exclude>}
247      * {@literal </excludes>}
248      * </code></pre>
249      * (which excludes all inner classes).
250      * <br>
251      * Each exclude item may also contain a comma-separated sub-list of items, which will be treated as multiple
252      * {@literal <exclude>} entries.<br>
253      * Since 2.19 a complex syntax is supported in one parameter (JUnit 4, JUnit 4.7+, TestNG):
254      * <pre><code>
255      * {@literal <exclude>}%regex[pkg.*Slow.*.class], Unstable*{@literal </exclude>}
256      * </code></pre>
257      * <br>
258      * <b>Notice that</b> these values are relative to the directory containing generated test classes of the project
259      * being tested. This directory is declared by the parameter {@code testClassesDirectory} which defaults
260      * to the POM property <code>${project.build.testOutputDirectory}</code>, typically
261      * <code>{@literal src/test/java}</code> unless overridden.
262      */
263     @Parameter(property = "failsafe.excludes")
264     // TODO use regex for fully qualified class names in 3.0 and change the filtering abilities
265     private List<String> excludes;
266 
267     /**
268      * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
269      * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
270      * classloader.
271      *
272      * @since 2.3
273      */
274     @Parameter(property = "failsafe.useSystemClassLoader", defaultValue = "true")
275     private boolean useSystemClassLoader;
276 
277     /**
278      * By default, Surefire forks your tests using a manifest-only JAR; set this parameter to "false" to force it to
279      * launch your tests with a plain old Java classpath. (See the
280      * <a href="http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html">
281      * http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html</a>
282      * for a more detailed explanation of manifest-only JARs and their benefits.)
283      * <br>
284      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
285      *
286      * @since 2.4.3
287      */
288     @Parameter(property = "failsafe.useManifestOnlyJar", defaultValue = "true")
289     private boolean useManifestOnlyJar;
290 
291     /**
292      * The character encoding scheme to be applied while generating test report
293      * files (see target/surefire-reports/yourTestName.txt).
294      * The report output files (*-out.txt) are still encoded with JVM's encoding used in standard out/err pipes.
295      *
296      * @since 3.0.0-M1
297      */
298     @Parameter(property = "encoding", defaultValue = "${project.reporting.outputEncoding}")
299     private String encoding;
300 
301     /**
302      * (JUnit 4+ providers and JUnit 5+ providers since 3.0.0-M4)
303      * The number of times each failing test will be rerun. If set larger than 0, rerun failing tests immediately after
304      * they fail. If a failing test passes in any of those reruns, it will be marked as pass and reported as a "flake".
305      * However, all the failing attempts will be recorded.
306      */
307     @Parameter(property = "failsafe.rerunFailingTestsCount", defaultValue = "0")
308     private int rerunFailingTestsCount;
309 
310     /**
311      * @deprecated not supported after 3.6.0, please use groups or Junit suite support
312      * (TestNG) List of &lt;suiteXmlFile&gt; elements specifying TestNG suite xml file locations. Note that
313      * {@code suiteXmlFiles} is incompatible with several other parameters of this plugin, like
314      * {@code includes} and {@code excludes}.<br>
315      * This parameter is ignored if the {@code test} parameter is specified (allowing you to run a single test
316      * instead of an entire suite).
317      *
318      * @since 2.2
319      */
320     @Parameter(property = "failsafe.suiteXmlFiles")
321     @Deprecated
322     private File[] suiteXmlFiles;
323 
324     /**
325      * Defines the order the tests will be run in. Supported values are {@code alphabetical},
326      * {@code reversealphabetical}, {@code random}, {@code failedfirst}, {@code balanced} and {@code filesystem}.
327      * <br>
328      * Failed first will run tests that failed on previous run first, as well as new tests for this run.
329      * <br>
330      * <br>
331      * Balanced is only relevant with parallel=classes, and will try to optimize the run-order of the tests reducing the
332      * overall execution time. Initially a statistics file is created and every next test run will reorder classes.
333      * <br>
334      * <br>
335      * Note that the statistics are stored in a file named <b>.surefire-XXXXXXXXX</b> beside <i>pom.xml</i> and
336      * should not be checked into version control. The "XXXXX" is the SHA1 checksum of the entire surefire
337      * configuration, so different configurations will have different statistics files, meaning if you change any
338      * configuration settings you will re-run once before new statistics data can be established.
339      *
340      * @since 2.7
341      */
342     @Parameter(property = "failsafe.runOrder", defaultValue = "filesystem")
343     private String runOrder;
344 
345     /**
346      * Sets the random seed that will be used to order the tests if {@code failsafe.runOrder} is set to {@code random}.
347      * <br>
348      * <br>
349      * If no seeds are set and {@code failsafe.runOrder} is set to {@code random}, then the seed used will be
350      * outputted (search for "To reproduce ordering use flag -Dfailsafe.runOrder.random.seed").
351      * <br>
352      * <br>
353      * To deterministically reproduce any random test order that was run before, simply set the seed to
354      * be the same value.
355      *
356      * @since 3.0.0-M6
357      */
358     @Parameter(property = "failsafe.runOrder.random.seed")
359     private Long runOrderRandomSeed;
360 
361     /**
362      * Used to override the checksum in the name of the statistics file
363      * when {@code failsafe.runOrder} is set to "balanced".
364      *
365      * @since 3.5.5
366      */
367     @Parameter(property = "failsafe.runOrder.statisticsFile.checksum")
368     private String runOrderStatisticsFileChecksum;
369 
370     /**
371      * A file containing include patterns, each in a next line. Blank lines, or lines starting with # are ignored.
372      * If {@code includes} are also specified, these patterns are appended. Example with path, simple and regex
373      * includes:
374      * <pre><code>
375      * *{@literal /}it{@literal /}*
376      * **{@literal /}NotIncludedByDefault.java
377      * %regex[.*IT.*|.*Not.*]
378      * </code></pre>
379      * <br>
380      * Since 3.0.0-M6, method filtering support is provided in the inclusions file as well, example:
381      * <pre><code>
382      * pkg.SomeIT#testMethod
383      * </code></pre>
384      *
385      * @since 2.13
386      */
387     @Parameter(property = "failsafe.includesFile")
388     private File includesFile;
389 
390     /**
391      * A file containing exclude patterns, each in a next line. Blank lines, or lines starting with # are ignored.
392      * If {@code excludes} are also specified, these patterns are appended.
393      * Example with path, simple and regex excludes:
394      * <pre><code>
395      * *{@literal /}it{@literal /}*
396      * **{@literal /}DontRunIT.*
397      * %regex[.*IT.*|.*Not.*]
398      * </code></pre>
399      * <br>
400      * Since 3.0.0-M6, method filtering support is provided in the exclusions file as well, example:
401      * <pre><code>
402      * pkg.SomeIT#testMethod
403      * </code></pre>
404      *
405      * @since 2.13
406      */
407     @Parameter(property = "failsafe.excludesFile")
408     private File excludesFile;
409 
410     /**
411      * Set to error/failure count in order to skip remaining tests.
412      * Due to race conditions in parallel/forked execution this may not be fully guaranteed.<br>
413      * Enable with system property {@code -Dfailsafe.skipAfterFailureCount=1} or any number greater than zero.
414      * Defaults to "0".<br>
415      * See the prerequisites and limitations in documentation:<br>
416      * <a href="http://maven.apache.org/plugins/maven-failsafe-plugin/examples/skip-after-failure.html">
417      * http://maven.apache.org/plugins/maven-failsafe-plugin/examples/skip-after-failure.html</a>
418      *
419      * @since 2.19
420      */
421     @Parameter(property = "failsafe.skipAfterFailureCount", defaultValue = "0")
422     private int skipAfterFailureCount;
423 
424     /**
425      * After the plugin process is shutdown by sending <i>SIGTERM signal (CTRL+C)</i>, <i>SHUTDOWN command</i> is
426      * received by every forked JVM.
427      * <br>
428      * The value is set to ({@code shutdown=exit}) by default (changed in version 3.0.0-M4).
429      * <br>
430      * The parameter can be configured with other two values {@code testset} and {@code kill}.
431      * <br>
432      * With({@code shutdown=testset}) the test set may still continue to run in forked JVM.
433      * <br>
434      * Using {@code exit} forked JVM executes {@code System.exit(1)} after the plugin process has received
435      * <i>SIGTERM signal</i>.
436      * <br>
437      * Using {@code kill} the JVM executes {@code Runtime.halt(1)} and kills itself.
438      *
439      * @since 2.19
440      */
441     @Parameter(property = "failsafe.shutdown", defaultValue = "exit")
442     private String shutdown;
443 
444     /**
445      * When {@code true}, uses the modulepath when executing with JDK 9+ and <i>module-info.java</i> is
446      * present. When {@code false}, always uses the classpath.
447      * <br>
448      * Defaults to {@code true}.
449      *
450      * @since 3.0.0-M2
451      */
452     @Parameter(property = "failsafe.useModulePath", defaultValue = "true")
453     private boolean useModulePath;
454 
455     /**
456      * This parameter configures the forked node. Currently, you can select the communication protocol, i.e. process
457      * pipes or TCP/IP sockets.
458      * The plugin uses process pipes by default which will be turned to TCP/IP in the version 3.0.0.
459      * Alternatively, you can implement your own factory and SPI.
460      * <br>
461      * See the documentation for more details:<br>
462      * <a href="https://maven.apache.org/plugins/maven-surefire-plugin/examples/process-communication.html">
463      *     https://maven.apache.org/plugins/maven-surefire-plugin/examples/process-communication.html</a>
464      *
465      * @since 3.0.0-M5
466      */
467     @Parameter(property = "failsafe.forkNode")
468     private ForkNodeFactory forkNode;
469 
470     /**
471      * You can selectively exclude individual environment variables by enumerating their keys.
472      * <br>
473      * The environment is a system-dependent mapping from keys to values which is inherited from the Maven process
474      * to the forked Surefire processes. The keys must literally (case sensitive) match in order to exclude
475      * their environment variable.
476      * <br>
477      * Example to exclude three environment variables:
478      * <br>
479      * <i>mvn test -Dfailsafe.excludedEnvironmentVariables=ACME1,ACME2,ACME3</i>
480      *
481      * @since 3.0.0-M4
482      */
483     @Parameter(property = "failsafe.excludedEnvironmentVariables")
484     private String[] excludedEnvironmentVariables;
485 
486     /**
487      * Since 3.0.0-M4 the process checkers are disabled.
488      * You can enable them namely by setting {@code ping} and {@code native} or {@code all} in this parameter.
489      * <br>
490      * The checker is useful in situations when you kill the build on a CI system and you want the Surefire forked JVM
491      * to kill the tests asap and free all handlers on the file system been previously used by the JVM and by the tests.
492      *
493      * <br>
494      *
495      * The {@code ping} should be safely used together with ZGC or Shenandoah Garbage Collector.
496      * Due to the {@code ping} relies on timing of the PING (triggered every 30 seconds), slow GCs may pause
497      * the timers and pretend that the parent process of the forked JVM does not exist.
498      *
499      * <br>
500      *
501      * The {@code native} is very fast checker.
502      * It is useful mechanism on Unix based systems, Linux distributions and Alpine/BusyBox Linux.
503      * See the JIRA <a href="https://issues.apache.org/jira/browse/SUREFIRE-1631">SUREFIRE-1631</a> for Windows issues.
504      *
505      * <br>
506      *
507      * Another useful configuration parameter is {@code forkedProcessTimeoutInSeconds}.
508      * <br>
509      * See the Frequently Asked Questions page with more details:<br>
510      * <a href="http://maven.apache.org/surefire/maven-surefire-plugin/faq.html#kill-jvm">
511      *     http://maven.apache.org/surefire/maven-surefire-plugin/faq.html#kill-jvm</a>
512      * <br>
513      * <a href="http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#kill-jvm">
514      *     http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#kill-jvm</a>
515      *
516      * <br>
517      *
518      * Example of use:
519      * <br>
520      * <i>mvn test -Dfailsafe.enableProcessChecker=all</i>
521      *
522      * @since 3.0.0-M4
523      */
524     @Parameter(property = "failsafe.enableProcessChecker")
525     private String enableProcessChecker;
526 
527     /**
528      * Properties file being used as system properties passed to the provider.
529      *
530      * @see AbstractSurefireMojo#systemPropertyVariables {@code systemPropertyVariables} for how the effective provider properties are calculated
531      */
532     @Parameter(property = "failsafe.systemPropertiesFile")
533     private File systemPropertiesFile;
534 
535     /**
536      * Provide the ID/s of an JUnit engine to be included in the test run.
537      *
538      * @since 3.0.0-M6
539      */
540     @Parameter(property = "failsafe.includeJUnit5Engines")
541     private String[] includeJUnit5Engines;
542 
543     /**
544      * Provide the ID/s of an JUnit engine to be excluded in the test run.
545      *
546      * @since 3.0.0-M6
547      */
548     @Parameter(property = "failsafe.excludeJUnit5Engines")
549     private String[] excludeJUnit5Engines;
550 
551     @Override
552     protected int getRerunFailingTestsCount() {
553         return rerunFailingTestsCount;
554     }
555 
556     @Override
557     @SuppressWarnings("unchecked")
558     protected void handleSummary(RunResult summary, Exception firstForkException)
559             throws MojoExecutionException, MojoFailureException {
560         try {
561             if (!summary.isNoTestsRun()) {
562                 Object token = getPluginContext().get(FAILSAFE_IN_PROGRESS_CONTEXT_KEY);
563                 writeSummary(summary, getSummaryFile(), token != null);
564             }
565         } catch (Exception e) {
566             throw new MojoExecutionException(e.getMessage(), e);
567         }
568 
569         getPluginContext().put(FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY);
570     }
571 
572     private boolean isJarArtifact(File artifactFile) {
573         return artifactFile != null
574                 && artifactFile.isFile()
575                 && artifactFile.getName().toLowerCase().endsWith(".jar");
576     }
577 
578     private static File toAbsoluteCanonical(File f) {
579         try {
580             return f == null ? null : f.getAbsoluteFile().getCanonicalFile();
581         } catch (IOException e) {
582             throw new IllegalStateException(e.getLocalizedMessage(), e);
583         }
584     }
585 
586     @Override
587     @SuppressWarnings("deprecation")
588     protected boolean isSkipExecution() {
589         return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
590     }
591 
592     @Override
593     protected String getPluginName() {
594         return "failsafe";
595     }
596 
597     @Override
598     protected String[] getDefaultIncludes() {
599         return new String[] {"**/IT*.java", "**/*IT.java", "**/*ITCase.java"};
600     }
601 
602     @Override
603     protected String getReportSchemaLocation() {
604         return "https://maven.apache.org/surefire/maven-failsafe-plugin/xsd/failsafe-test-report.xsd";
605     }
606 
607     @Override
608     public boolean isSkipTests() {
609         return skipTests;
610     }
611 
612     @Override
613     @Deprecated
614     public void setSkipTests(boolean skipTests) {
615         this.skipTests = skipTests;
616     }
617 
618     public boolean isSkipITs() {
619         return skipITs;
620     }
621 
622     public void setSkipITs(boolean skipITs) {
623         this.skipITs = skipITs;
624     }
625 
626     @Override
627     @Deprecated
628     public boolean isSkipExec() {
629         return skipExec;
630     }
631 
632     @Override
633     @Deprecated
634     public void setSkipExec(boolean skipExec) {
635         this.skipExec = skipExec;
636     }
637 
638     @Override
639     public boolean isSkip() {
640         return skip;
641     }
642 
643     @Override
644     public void setSkip(boolean skip) {
645         this.skip = skip;
646     }
647 
648     @Override
649     public File getBasedir() {
650         return basedir;
651     }
652 
653     @Override
654     public void setBasedir(File basedir) {
655         this.basedir = basedir;
656     }
657 
658     @Override
659     public File getTestClassesDirectory() {
660         return testClassesDirectory;
661     }
662 
663     @Override
664     public void setTestClassesDirectory(File testClassesDirectory) {
665         this.testClassesDirectory = testClassesDirectory;
666     }
667 
668     /**
669      * @return Output directory, or artifact file if artifact type is "jar". If not forking the JVM, parameter
670      * {@link #useSystemClassLoader} is ignored and the {@link org.apache.maven.surefire.booter.IsolatedClassLoader} is
671      * used instead. See the resolution of {@link #getClassLoaderConfiguration() ClassLoaderConfiguration}.
672      */
673     @Override
674     public File getMainBuildPath() {
675         File artifact = getProject().getArtifact().getFile();
676         boolean isDefaultClsDir = classesDirectory == null;
677         return isDefaultClsDir ? (isJarArtifact(artifact) ? artifact : defaultClassesDirectory) : classesDirectory;
678     }
679 
680     @Override
681     public void setMainBuildPath(File mainBuildPath) {
682         classesDirectory = toAbsoluteCanonical(mainBuildPath);
683     }
684 
685     public void setDefaultClassesDirectory(File defaultClassesDirectory) {
686         this.defaultClassesDirectory = toAbsoluteCanonical(defaultClassesDirectory);
687     }
688 
689     @Override
690     public File getReportsDirectory() {
691         return reportsDirectory;
692     }
693 
694     @Override
695     public void setReportsDirectory(File reportsDirectory) {
696         this.reportsDirectory = reportsDirectory;
697     }
698 
699     @Override
700     public String getTest() {
701         return test;
702     }
703 
704     @Override
705     public void setTest(String test) {
706         this.test = test;
707     }
708 
709     public File getSummaryFile() {
710         return summaryFile;
711     }
712 
713     public void setSummaryFile(File summaryFile) {
714         this.summaryFile = summaryFile;
715     }
716 
717     @Override
718     public boolean isPrintSummary() {
719         return printSummary;
720     }
721 
722     @Override
723     public void setPrintSummary(boolean printSummary) {
724         this.printSummary = printSummary;
725     }
726 
727     @Override
728     public String getReportFormat() {
729         return reportFormat;
730     }
731 
732     @Override
733     public void setReportFormat(String reportFormat) {
734         this.reportFormat = reportFormat;
735     }
736 
737     @Override
738     public boolean isUseFile() {
739         return useFile;
740     }
741 
742     @Override
743     public void setUseFile(boolean useFile) {
744         this.useFile = useFile;
745     }
746 
747     @Override
748     public String getDebugForkedProcess() {
749         return debugForkedProcess;
750     }
751 
752     @Override
753     public void setDebugForkedProcess(String debugForkedProcess) {
754         this.debugForkedProcess = debugForkedProcess;
755     }
756 
757     @Override
758     public int getForkedProcessTimeoutInSeconds() {
759         return forkedProcessTimeoutInSeconds;
760     }
761 
762     @Override
763     public void setForkedProcessTimeoutInSeconds(int forkedProcessTimeoutInSeconds) {
764         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
765     }
766 
767     @Override
768     public int getForkedProcessExitTimeoutInSeconds() {
769         return forkedProcessExitTimeoutInSeconds;
770     }
771 
772     @Override
773     public void setForkedProcessExitTimeoutInSeconds(int forkedProcessExitTimeoutInSeconds) {
774         this.forkedProcessExitTimeoutInSeconds = forkedProcessExitTimeoutInSeconds;
775     }
776 
777     @Override
778     public double getParallelTestsTimeoutInSeconds() {
779         return parallelTestsTimeoutInSeconds;
780     }
781 
782     @Override
783     public void setParallelTestsTimeoutInSeconds(double parallelTestsTimeoutInSeconds) {
784         this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds;
785     }
786 
787     @Override
788     public double getParallelTestsTimeoutForcedInSeconds() {
789         return parallelTestsTimeoutForcedInSeconds;
790     }
791 
792     @Override
793     public void setParallelTestsTimeoutForcedInSeconds(double parallelTestsTimeoutForcedInSeconds) {
794         this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds;
795     }
796 
797     @Override
798     public boolean isUseSystemClassLoader() {
799         return useSystemClassLoader;
800     }
801 
802     @Override
803     public void setUseSystemClassLoader(boolean useSystemClassLoader) {
804         this.useSystemClassLoader = useSystemClassLoader;
805     }
806 
807     @Override
808     public boolean isUseManifestOnlyJar() {
809         return useManifestOnlyJar;
810     }
811 
812     @Override
813     public void setUseManifestOnlyJar(boolean useManifestOnlyJar) {
814         this.useManifestOnlyJar = useManifestOnlyJar;
815     }
816 
817     @Override
818     public String getEncoding() {
819         return encoding;
820     }
821 
822     @Override
823     public void setEncoding(String encoding) {
824         this.encoding = encoding;
825     }
826 
827     // the following will be refactored out once the common code is all in one place
828 
829     public boolean isTestFailureIgnore() {
830         return true; // ignore
831     }
832 
833     public void setTestFailureIgnore(boolean testFailureIgnore) {
834         // ignore
835     }
836 
837     @Override
838     protected void addPluginSpecificChecksumItems(ChecksumCalculator checksum) {
839         checksum.add(skipITs);
840         checksum.add(summaryFile);
841     }
842 
843     @Override
844     public File getSystemPropertiesFile() {
845         return systemPropertiesFile;
846     }
847 
848     @Override
849     public void setSystemPropertiesFile(File systemPropertiesFile) {
850         this.systemPropertiesFile = systemPropertiesFile;
851     }
852 
853     @Override
854     @SuppressWarnings("deprecation")
855     public boolean getFailIfNoSpecifiedTests() {
856         if (!failIfNoSpecifiedTestsDeprecated) {
857             getConsoleLogger()
858                     .warning("Use " + getPluginName()
859                             + ".failIfNoSpecifiedTests property instead of obsolete it.failIfNoSpecifiedTests.");
860         }
861         // since both have default "true", assuming that any "false" is set by user on purpose
862         return failIfNoSpecifiedTests && failIfNoSpecifiedTestsDeprecated;
863     }
864 
865     @Override
866     public void setFailIfNoSpecifiedTests(boolean failIfNoSpecifiedTests) {
867         this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
868     }
869 
870     @Override
871     public int getSkipAfterFailureCount() {
872         return skipAfterFailureCount;
873     }
874 
875     @Override
876     public String getShutdown() {
877         return shutdown;
878     }
879 
880     @Override
881     public List<String> getIncludes() {
882         return includes;
883     }
884 
885     @Override
886     public void setIncludes(List<String> includes) {
887         this.includes = includes;
888     }
889 
890     @Override
891     public List<String> getExcludes() {
892         return excludes;
893     }
894 
895     @Override
896     public void setExcludes(List<String> excludes) {
897         this.excludes = excludes;
898     }
899 
900     @Override
901     public String getRunOrder() {
902         return runOrder;
903     }
904 
905     @Override
906     @SuppressWarnings("UnusedDeclaration")
907     public void setRunOrder(String runOrder) {
908         this.runOrder = runOrder;
909     }
910 
911     @Override
912     public Long getRunOrderRandomSeed() {
913         return runOrderRandomSeed;
914     }
915 
916     @Override
917     public void setRunOrderRandomSeed(Long runOrderRandomSeed) {
918         this.runOrderRandomSeed = runOrderRandomSeed;
919     }
920 
921     @Override
922     public String getRunOrderStatisticsFileChecksum() {
923         return runOrderStatisticsFileChecksum;
924     }
925 
926     @Override
927     public void setRunOrderStatisticsFileChecksum(String runOrderStatisticsFileChecksum) {
928         this.runOrderStatisticsFileChecksum = runOrderStatisticsFileChecksum;
929     }
930 
931     @Override
932     public File getIncludesFile() {
933         return includesFile;
934     }
935 
936     @Override
937     public File getExcludesFile() {
938         return excludesFile;
939     }
940 
941     @Override
942     protected boolean useModulePath() {
943         return useModulePath;
944     }
945 
946     @Override
947     protected void setUseModulePath(boolean useModulePath) {
948         this.useModulePath = useModulePath;
949     }
950 
951     @Override
952     protected final ForkNodeFactory getForkNode() {
953         return forkNode;
954     }
955 
956     @Override
957     protected final String[] getExcludedEnvironmentVariables() {
958         return excludedEnvironmentVariables == null ? new String[0] : excludedEnvironmentVariables;
959     }
960 
961     void setExcludedEnvironmentVariables(String[] excludedEnvironmentVariables) {
962         this.excludedEnvironmentVariables = excludedEnvironmentVariables;
963     }
964 
965     @Override
966     protected final String getEnableProcessChecker() {
967         return enableProcessChecker;
968     }
969 
970     public String[] getIncludeJUnit5Engines() {
971         return includeJUnit5Engines;
972     }
973 
974     @SuppressWarnings("UnusedDeclaration")
975     public void setIncludeJUnit5Engines(String[] includeJUnit5Engines) {
976         this.includeJUnit5Engines = includeJUnit5Engines;
977     }
978 
979     public String[] getExcludeJUnit5Engines() {
980         return excludeJUnit5Engines;
981     }
982 
983     @SuppressWarnings("UnusedDeclaration")
984     public void setExcludeJUnit5Engines(String[] excludeJUnit5Engines) {
985         this.excludeJUnit5Engines = excludeJUnit5Engines;
986     }
987 }