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.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  
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.surefire.api.suite.RunResult;
36  import org.apache.maven.surefire.extensions.ForkNodeFactory;
37  
38  import static org.apache.maven.plugin.failsafe.util.FailsafeSummaryXmlUtils.writeSummary;
39  
40  /**
41   * Run integration tests using Surefire.
42   *
43   * @author Jason van Zyl
44   * @author Stephen Connolly
45   */
46  @Mojo(
47          name = "integration-test",
48          requiresProject = true,
49          requiresDependencyResolution = ResolutionScope.TEST,
50          defaultPhase = LifecyclePhase.INTEGRATION_TEST,
51          threadSafe = true)
52  public class IntegrationTestMojo extends AbstractSurefireMojo {
53  
54      private static final String FAILSAFE_IN_PROGRESS_CONTEXT_KEY = "failsafe-in-progress";
55  
56      /**
57       * The path representing project <em>JAR</em> file, if exists; Otherwise the directory containing generated
58       * classes of the project being tested. This will be included after the test classes in the test classpath.
59       * Defaults to built artifact <em>JAR</em> file or <code>${project.build.outputDirectory}</code>.
60       */
61      @Parameter
62      private File classesDirectory;
63  
64      @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true, required = true)
65      private File defaultClassesDirectory;
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       * Base directory where all reports are written to.
78       */
79      @Parameter(defaultValue = "${project.build.directory}/failsafe-reports")
80      private File reportsDirectory;
81  
82      @SuppressWarnings("checkstyle:linelength")
83      /**
84       * Specify this parameter to run individual tests by file name, overriding parameter {@code includes} and
85       * {@code excludes}. Each pattern you specify here will be used to create an include pattern formatted like
86       * <code>**{@literal /}${it.test}.java</code>, so you can just type {@code -Dit.test=MyIT} to run
87       * a single test file called "foo/MyIT.java". The test patterns prefixed with a <em>!</em> will be excluded.
88       * <br>
89       * This parameter overrides the parameter {@code includes} and {@code excludes}, and the TestNG parameter
90       * {@code suiteXmlFiles}.
91       * <br>
92       * Since 2.7.3 You can execute a limited number of methods in the test with adding <i>#myMethod</i> or
93       * <i>#my*ethod</i>. E.g. type {@code -Dit.test=MyIT#myMethod} <b>supported for junit 4.x and TestNg.</b>
94       * <br>
95       * Since 2.19 a complex syntax is supported in one parameter (JUnit 4, JUnit 4.7+, TestNG):
96       * <pre><code>"-Dit.test=???IT, !Unstable*, pkg{@literal /}**{@literal /}Ci*leIT.java, *IT#test*One+testTwo?????, #fast*+slowTest"</code></pre>
97       * or e.g.
98       * <br>
99       * <pre><code>"-Dit.test=Basic*, !%regex[.*.Unstable.*], !%regex[.*.MyIT.class#one.*|two.*], %regex[#fast.*|slow.*]"</code></pre>
100      * <br>
101      * The Parameterized JUnit runner {@code describes} test methods using an index in brackets, so the non-regex
102      * method pattern would become: {@code #testMethod[*]}. If using <code>@Parameters(name="{index}: fib({0})={1}")</code>
103      * and selecting the index e.g. 5 in pattern, the non-regex method pattern would become {@code #testMethod[5:*]}.
104      */
105     @Parameter(property = "it.test")
106     private String test;
107 
108     /**
109      * The summary file to write integration test results to.
110      */
111     @Parameter(defaultValue = "${project.build.directory}/failsafe-reports/failsafe-summary.xml", required = true)
112     private File summaryFile;
113 
114     /**
115      * Option to print summary of test suites or just print the test cases that have errors.
116      */
117     @Parameter(property = "failsafe.printSummary", defaultValue = "true")
118     private boolean printSummary;
119 
120     /**
121      * Selects the formatting for the test report to be generated. Can be set as "brief" or "plain".
122      * Only applies to the output format of the output files  (target/surefire-reports/testName.txt)
123      */
124     @Parameter(property = "failsafe.reportFormat", defaultValue = "brief")
125     private String reportFormat;
126 
127     /**
128      * Option to generate a file test report or just output the test report to the console.
129      */
130     @Parameter(property = "failsafe.useFile", defaultValue = "true")
131     private boolean useFile;
132 
133     /**
134      * Set this to "false" to prevent a failure if none of the tests specified in -Dit.test=... are run. Defaults to
135      * "true".
136      *
137      * @since 2.12
138      * @deprecated Since 3.0.0-M8, use "failsafe.failIfNoSpecifiedTests" instead.
139      */
140     @Deprecated
141     @Parameter(property = "it.failIfNoSpecifiedTests", defaultValue = "true")
142     private boolean failIfNoSpecifiedTestsDeprecated;
143 
144     /**
145      * Set this to "false" to prevent a failure if none of the tests specified in -Dit.test=... are run. Defaults to
146      * "true".
147      * Replacing "it.failIfNoSpecifiedTests" to be consistent with surefire plugin.
148      *
149      * @since 3.0.0-M8
150      */
151     @Parameter(property = "failsafe.failIfNoSpecifiedTests", defaultValue = "true")
152     private boolean failIfNoSpecifiedTests;
153 
154     /**
155      * Attach a debugger to the forked JVM. If set to "true", the process will suspend and wait for a debugger to attach
156      * on port 5005. If set to some other string, that string will be appended to the argLine, allowing you to configure
157      * arbitrary debugging ability options (without overwriting the other options specified through the {@code argLine}
158      * parameter).
159      *
160      * @since 2.4
161      */
162     @Parameter(property = "maven.failsafe.debug")
163     private String debugForkedProcess;
164 
165     /**
166      * Kill the forked test process after a certain number of seconds. If set to 0, wait forever for the process, never
167      * timing out.
168      *
169      * @since 2.4
170      */
171     @Parameter(property = "failsafe.timeout")
172     private int forkedProcessTimeoutInSeconds;
173 
174     /**
175      * Forked process is normally terminated without any significant delay after given tests have completed.
176      * If the particular tests started non-daemon Thread(s), the process hangs instead of been properly terminated
177      * by {@code System.exit()}. Use this parameter in order to determine the timeout of terminating the process.
178      * <a href="http://maven.apache.org/surefire/maven-failsafe-plugin/examples/shutdown.html">see the documentation:
179      * http://maven.apache.org/surefire/maven-failsafe-plugin/examples/shutdown.html</a>
180      *
181      * @since 2.20
182      */
183     @Parameter(property = "failsafe.exitTimeout", defaultValue = "30")
184     private int forkedProcessExitTimeoutInSeconds;
185 
186     /**
187      * Stop executing queued parallel JUnit tests after a certain number of seconds.
188      * <br>
189      * Example values: "3.5", "4"<br>
190      * <br>
191      * If set to 0, wait forever, never timing out.
192      * Makes sense with specified {@code parallel} different from "none".
193      *
194      * @since 2.16
195      */
196     @Parameter(property = "failsafe.parallel.timeout")
197     private double parallelTestsTimeoutInSeconds;
198 
199     /**
200      * Stop executing queued parallel JUnit tests
201      * and <i>interrupt</i> currently running tests after a certain number of seconds.
202      * <br>
203      * Example values: "3.5", "4"<br>
204      * <br>
205      * If set to 0, wait forever, never timing out.
206      * Makes sense with specified {@code parallel} different from "none".
207      *
208      * @since 2.16
209      */
210     @Parameter(property = "failsafe.parallel.forcedTimeout")
211     private double parallelTestsTimeoutForcedInSeconds;
212 
213     @SuppressWarnings("checkstyle:linelength")
214     /**
215      * A list of {@literal <include>} elements specifying the test filter (by pattern) of tests which should be
216      * included in testing. If it is not specified and the {@code test} parameter is unspecified as well, the default
217      * includes is
218      * <pre><code>
219      * {@literal <includes>}
220      *     {@literal <include>}**{@literal /}IT*.java{@literal </include>}
221      *     {@literal <include>}**{@literal /}*IT.java{@literal </include>}
222      *     {@literal <include>}**{@literal /}*ITCase.java{@literal </include>}
223      * {@literal </includes>}
224      * </code></pre>
225      * <br>
226      * Each include item may also contain a comma-separated sublist of items, which will be treated as multiple
227      * {@literal <include>} entries.<br>
228      * Since 2.19 a complex syntax is supported in one parameter (JUnit 4, JUnit 4.7+, TestNG):
229      * <pre><code>
230      * {@literal <include>}%regex[.*[Cat|Dog].*], Basic????, !Unstable*{@literal </include>}
231      * {@literal <include>}%regex[.*[Cat|Dog].*], !%regex[pkg.*Slow.*.class], pkg{@literal /}**{@literal /}*Fast*.java{@literal </include>}
232      * </code></pre>
233      * <br>
234      * This parameter is ignored if the TestNG {@code suiteXmlFiles} parameter is specified.<br>
235      * <br>
236      * <b>Notice that</b> these values are relative to the directory containing generated test classes of the project
237      * being tested. This directory is declared by the parameter {@code testClassesDirectory} which defaults
238      * to the POM property <code>${project.build.testOutputDirectory}</code>, typically
239      * <code>{@literal src/test/java}</code> unless overridden.
240      */
241     @Parameter(property = "failsafe.includes")
242     // TODO use regex for fully qualified class names in 3.0 and change the filtering abilities
243     private List<String> includes;
244 
245     /**
246      * A list of {@literal <exclude>} elements specifying the tests (by pattern) that should be excluded in testing.
247      * When not specified and when the {@code test} parameter is not specified, the default excludes will be <br>
248      * <pre><code>
249      * {@literal <excludes>}
250      *     {@literal <exclude>}**{@literal /}*$*{@literal </exclude>}
251      * {@literal </excludes>}
252      * </code></pre>
253      * (which excludes all inner classes).
254      * <br>
255      * This parameter is ignored if the TestNG {@code suiteXmlFiles} parameter is specified.
256      * <br>
257      * Each exclude item may also contain a comma-separated sub-list of items, which will be treated as multiple
258      * {@literal <exclude>} entries.<br>
259      * Since 2.19 a complex syntax is supported in one parameter (JUnit 4, JUnit 4.7+, TestNG):
260      * <pre><code>
261      * {@literal <exclude>}%regex[pkg.*Slow.*.class], Unstable*{@literal </exclude>}
262      * </code></pre>
263      * <br>
264      * <b>Notice that</b> these values are relative to the directory containing generated test classes of the project
265      * being tested. This directory is declared by the parameter {@code testClassesDirectory} which defaults
266      * to the POM property <code>${project.build.testOutputDirectory}</code>, typically
267      * <code>{@literal src/test/java}</code> unless overridden.
268      */
269     @Parameter(property = "failsafe.excludes")
270     // TODO use regex for fully qualified class names in 3.0 and change the filtering abilities
271     private List<String> excludes;
272 
273     /**
274      * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
275      * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
276      * classloader.
277      *
278      * @since 2.3
279      */
280     @Parameter(property = "failsafe.useSystemClassLoader", defaultValue = "true")
281     private boolean useSystemClassLoader;
282 
283     /**
284      * By default, Surefire forks your tests using a manifest-only JAR; set this parameter to "false" to force it to
285      * launch your tests with a plain old Java classpath. (See the
286      * <a href="http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html">
287      * http://maven.apache.org/plugins/maven-failsafe-plugin/examples/class-loading.html</a>
288      * for a more detailed explanation of manifest-only JARs and their benefits.)
289      * <br>
290      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
291      *
292      * @since 2.4.3
293      */
294     @Parameter(property = "failsafe.useManifestOnlyJar", defaultValue = "true")
295     private boolean useManifestOnlyJar;
296 
297     /**
298      * The character encoding scheme to be applied while generating test report
299      * files (see target/surefire-reports/yourTestName.txt).
300      * The report output files (*-out.txt) are still encoded with JVM's encoding used in standard out/err pipes.
301      *
302      * @since 3.0.0-M1
303      */
304     @Parameter(property = "encoding", defaultValue = "${project.reporting.outputEncoding}")
305     private String encoding;
306 
307     /**
308      * (JUnit 4+ providers and JUnit 5+ providers since 3.0.0-M4)
309      * The number of times each failing test will be rerun. If set larger than 0, rerun failing tests immediately after
310      * they fail. If a failing test passes in any of those reruns, it will be marked as pass and reported as a "flake".
311      * However, all the failing attempts will be recorded.
312      */
313     @Parameter(property = "failsafe.rerunFailingTestsCount", defaultValue = "0")
314     private int rerunFailingTestsCount;
315 
316     /**
317      * (TestNG) List of &lt;suiteXmlFile&gt; elements specifying TestNG suite xml file locations. Note that
318      * {@code suiteXmlFiles} is incompatible with several other parameters of this plugin, like
319      * {@code includes} and {@code excludes}.<br>
320      * This parameter is ignored if the {@code test} parameter is specified (allowing you to run a single test
321      * instead of an entire suite).
322      *
323      * @since 2.2
324      */
325     @Parameter(property = "failsafe.suiteXmlFiles")
326     private File[] suiteXmlFiles;
327 
328     /**
329      * Defines the order the tests will be run in. Supported values are {@code alphabetical},
330      * {@code reversealphabetical}, {@code random}, {@code hourly} (alphabetical on even hours, reverse alphabetical
331      * on odd hours), {@code failedfirst}, {@code balanced} and {@code filesystem}.
332      * <br>
333      * <br>
334      * Odd/Even for hourly is determined at the time the of scanning the classpath, meaning it could change during a
335      * multi-module build.
336      * <br>
337      * <br>
338      * Failed first will run tests that failed on previous run first, as well as new tests for this run.
339      * <br>
340      * <br>
341      * Balanced is only relevant with parallel=classes, and will try to optimize the run-order of the tests reducing the
342      * overall execution time. Initially a statistics file is created and every next test run will reorder classes.
343      * <br>
344      * <br>
345      * Note that the statistics are stored in a file named <b>.surefire-XXXXXXXXX</b> beside <i>pom.xml</i> and
346      * should not be checked into version control. The "XXXXX" is the SHA1 checksum of the entire surefire
347      * configuration, so different configurations will have different statistics files, meaning if you change any
348      * configuration settings you will re-run once before new statistics data can be established.
349      *
350      * @since 2.7
351      */
352     @Parameter(property = "failsafe.runOrder", defaultValue = "filesystem")
353     private String runOrder;
354 
355     /**
356      * Sets the random seed that will be used to order the tests if {@code failsafe.runOrder} is set to {@code random}.
357      * <br>
358      * <br>
359      * If no seeds are set and {@code failsafe.runOrder} is set to {@code random}, then the seed used will be
360      * outputted (search for "To reproduce ordering use flag -Dfailsafe.runOrder.random.seed").
361      * <br>
362      * <br>
363      * To deterministically reproduce any random test order that was run before, simply set the seed to
364      * be the same value.
365      *
366      * @since 3.0.0-M6
367      */
368     @Parameter(property = "failsafe.runOrder.random.seed")
369     private Long runOrderRandomSeed;
370 
371     /**
372      * A file containing include patterns, each in a next line. Blank lines, or lines starting with # are ignored.
373      * If {@code includes} are also specified, these patterns are appended. Example with path, simple and regex
374      * includes:
375      * <pre><code>
376      * *{@literal /}it{@literal /}*
377      * **{@literal /}NotIncludedByDefault.java
378      * %regex[.*IT.*|.*Not.*]
379      * </code></pre>
380      * <br>
381      * Since 3.0.0-M6, method filtering support is provided in the inclusions file as well, example:
382      * <pre><code>
383      * pkg.SomeIT#testMethod
384      * </code></pre>
385      *
386      * @since 2.13
387      */
388     @Parameter(property = "failsafe.includesFile")
389     private File includesFile;
390 
391     /**
392      * A file containing exclude patterns, each in a next line. Blank lines, or lines starting with # are ignored.
393      * If {@code excludes} are also specified, these patterns are appended.
394      * Example with path, simple and regex excludes:
395      * <pre><code>
396      * *{@literal /}it{@literal /}*
397      * **{@literal /}DontRunIT.*
398      * %regex[.*IT.*|.*Not.*]
399      * </code></pre>
400      * <br>
401      * Since 3.0.0-M6, method filtering support is provided in the exclusions file as well, example:
402      * <pre><code>
403      * pkg.SomeIT#testMethod
404      * </code></pre>
405      *
406      * @since 2.13
407      */
408     @Parameter(property = "failsafe.excludesFile")
409     private File excludesFile;
410 
411     /**
412      * Set to error/failure count in order to skip remaining tests.
413      * Due to race conditions in parallel/forked execution this may not be fully guaranteed.<br>
414      * Enable with system property {@code -Dfailsafe.skipAfterFailureCount=1} or any number greater than zero.
415      * Defaults to "0".<br>
416      * See the prerequisites and limitations in documentation:<br>
417      * <a href="http://maven.apache.org/plugins/maven-failsafe-plugin/examples/skip-after-failure.html">
418      * http://maven.apache.org/plugins/maven-failsafe-plugin/examples/skip-after-failure.html</a>
419      *
420      * @since 2.19
421      */
422     @Parameter(property = "failsafe.skipAfterFailureCount", defaultValue = "0")
423     private int skipAfterFailureCount;
424 
425     /**
426      * After the plugin process is shutdown by sending <i>SIGTERM signal (CTRL+C)</i>, <i>SHUTDOWN command</i> is
427      * received by every forked JVM.
428      * <br>
429      * The value is set to ({@code shutdown=exit}) by default (changed in version 3.0.0-M4).
430      * <br>
431      * The parameter can be configured with other two values {@code testset} and {@code kill}.
432      * <br>
433      * With({@code shutdown=testset}) the test set may still continue to run in forked JVM.
434      * <br>
435      * Using {@code exit} forked JVM executes {@code System.exit(1)} after the plugin process has received
436      * <i>SIGTERM signal</i>.
437      * <br>
438      * Using {@code kill} the JVM executes {@code Runtime.halt(1)} and kills itself.
439      *
440      * @since 2.19
441      */
442     @Parameter(property = "failsafe.shutdown", defaultValue = "exit")
443     private String shutdown;
444 
445     /**
446      * When {@code true}, uses the modulepath when executing with JDK 9+ and <i>module-info.java</i> is
447      * present. When {@code false}, always uses the classpath.
448      * <br>
449      * Defaults to {@code true}.
450      *
451      * @since 3.0.0-M2
452      */
453     @Parameter(property = "failsafe.useModulePath", defaultValue = "true")
454     private boolean useModulePath;
455 
456     /**
457      * This parameter configures the forked node. Currently, you can select the communication protocol, i.e. process
458      * pipes or TCP/IP sockets.
459      * The plugin uses process pipes by default which will be turned to TCP/IP in the version 3.0.0.
460      * Alternatively, you can implement your own factory and SPI.
461      * <br>
462      * See the documentation for more details:<br>
463      * <a href="https://maven.apache.org/plugins/maven-surefire-plugin/examples/process-communication.html">
464      *     https://maven.apache.org/plugins/maven-surefire-plugin/examples/process-communication.html</a>
465      *
466      * @since 3.0.0-M5
467      */
468     @Parameter(property = "failsafe.forkNode")
469     private ForkNodeFactory forkNode;
470 
471     /**
472      * You can selectively exclude individual environment variables by enumerating their keys.
473      * <br>
474      * The environment is a system-dependent mapping from keys to values which is inherited from the Maven process
475      * to the forked Surefire processes. The keys must literally (case sensitive) match in order to exclude
476      * their environment variable.
477      * <br>
478      * Example to exclude three environment variables:
479      * <br>
480      * <i>mvn test -Dfailsafe.excludedEnvironmentVariables=ACME1,ACME2,ACME3</i>
481      *
482      * @since 3.0.0-M4
483      */
484     @Parameter(property = "failsafe.excludedEnvironmentVariables")
485     private String[] excludedEnvironmentVariables;
486 
487     /**
488      * Since 3.0.0-M4 the process checkers are disabled.
489      * You can enable them namely by setting {@code ping} and {@code native} or {@code all} in this parameter.
490      * <br>
491      * The checker is useful in situations when you kill the build on a CI system and you want the Surefire forked JVM
492      * to kill the tests asap and free all handlers on the file system been previously used by the JVM and by the tests.
493      *
494      * <br>
495      *
496      * The {@code ping} should be safely used together with ZGC or Shenandoah Garbage Collector.
497      * Due to the {@code ping} relies on timing of the PING (triggered every 30 seconds), slow GCs may pause
498      * the timers and pretend that the parent process of the forked JVM does not exist.
499      *
500      * <br>
501      *
502      * The {@code native} is very fast checker.
503      * It is useful mechanism on Unix based systems, Linux distributions and Alpine/BusyBox Linux.
504      * See the JIRA <a href="https://issues.apache.org/jira/browse/SUREFIRE-1631">SUREFIRE-1631</a> for Windows issues.
505      *
506      * <br>
507      *
508      * Another useful configuration parameter is {@code forkedProcessTimeoutInSeconds}.
509      * <br>
510      * See the Frequently Asked Questions page with more details:<br>
511      * <a href="http://maven.apache.org/surefire/maven-surefire-plugin/faq.html#kill-jvm">
512      *     http://maven.apache.org/surefire/maven-surefire-plugin/faq.html#kill-jvm</a>
513      * <br>
514      * <a href="http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#kill-jvm">
515      *     http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html#kill-jvm</a>
516      *
517      * <br>
518      *
519      * Example of use:
520      * <br>
521      * <i>mvn test -Dfailsafe.enableProcessChecker=all</i>
522      *
523      * @since 3.0.0-M4
524      */
525     @Parameter(property = "failsafe.enableProcessChecker")
526     private String enableProcessChecker;
527 
528     @Parameter(property = "failsafe.systemPropertiesFile")
529     private File systemPropertiesFile;
530 
531     /**
532      * Provide the ID/s of an JUnit engine to be included in the test run.
533      *
534      * @since 3.0.0-M6
535      */
536     @Parameter(property = "failsafe.includeJUnit5Engines")
537     private String[] includeJUnit5Engines;
538 
539     /**
540      * Provide the ID/s of an JUnit engine to be excluded in the test run.
541      *
542      * @since 3.0.0-M6
543      */
544     @Parameter(property = "failsafe.excludeJUnit5Engines")
545     private String[] excludeJUnit5Engines;
546 
547     @Override
548     protected int getRerunFailingTestsCount() {
549         return rerunFailingTestsCount;
550     }
551 
552     @Override
553     @SuppressWarnings("unchecked")
554     protected void handleSummary(RunResult summary, Exception firstForkException)
555             throws MojoExecutionException, MojoFailureException {
556         File summaryFile = getSummaryFile();
557         if (!summaryFile.getParentFile().isDirectory()) {
558             //noinspection ResultOfMethodCallIgnored
559             summaryFile.getParentFile().mkdirs();
560         }
561 
562         try {
563             Object token = getPluginContext().get(FAILSAFE_IN_PROGRESS_CONTEXT_KEY);
564             writeSummary(summary, summaryFile, token != null);
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-3.0.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 File[] getSuiteXmlFiles() {
902         return suiteXmlFiles.clone();
903     }
904 
905     @Override
906     @SuppressWarnings("UnusedDeclaration")
907     public void setSuiteXmlFiles(File[] suiteXmlFiles) {
908         this.suiteXmlFiles = suiteXmlFiles.clone();
909     }
910 
911     @Override
912     public String getRunOrder() {
913         return runOrder;
914     }
915 
916     @Override
917     @SuppressWarnings("UnusedDeclaration")
918     public void setRunOrder(String runOrder) {
919         this.runOrder = runOrder;
920     }
921 
922     @Override
923     public Long getRunOrderRandomSeed() {
924         return runOrderRandomSeed;
925     }
926 
927     @Override
928     public void setRunOrderRandomSeed(Long runOrderRandomSeed) {
929         this.runOrderRandomSeed = runOrderRandomSeed;
930     }
931 
932     @Override
933     public File getIncludesFile() {
934         return includesFile;
935     }
936 
937     @Override
938     public File getExcludesFile() {
939         return excludesFile;
940     }
941 
942     @Override
943     protected boolean useModulePath() {
944         return useModulePath;
945     }
946 
947     @Override
948     protected void setUseModulePath(boolean useModulePath) {
949         this.useModulePath = useModulePath;
950     }
951 
952     @Override
953     protected final List<File> suiteXmlFiles() {
954         return hasSuiteXmlFiles() ? Arrays.asList(suiteXmlFiles) : Collections.<File>emptyList();
955     }
956 
957     @Override
958     protected final boolean hasSuiteXmlFiles() {
959         return suiteXmlFiles != null && suiteXmlFiles.length != 0;
960     }
961 
962     @Override
963     protected final ForkNodeFactory getForkNode() {
964         return forkNode;
965     }
966 
967     @Override
968     protected final String[] getExcludedEnvironmentVariables() {
969         return excludedEnvironmentVariables == null ? new String[0] : excludedEnvironmentVariables;
970     }
971 
972     void setExcludedEnvironmentVariables(String[] excludedEnvironmentVariables) {
973         this.excludedEnvironmentVariables = excludedEnvironmentVariables;
974     }
975 
976     @Override
977     protected final String getEnableProcessChecker() {
978         return enableProcessChecker;
979     }
980 
981     public String[] getIncludeJUnit5Engines() {
982         return includeJUnit5Engines;
983     }
984 
985     @SuppressWarnings("UnusedDeclaration")
986     public void setIncludeJUnit5Engines(String[] includeJUnit5Engines) {
987         this.includeJUnit5Engines = includeJUnit5Engines;
988     }
989 
990     public String[] getExcludeJUnit5Engines() {
991         return excludeJUnit5Engines;
992     }
993 
994     @SuppressWarnings("UnusedDeclaration")
995     public void setExcludeJUnit5Engines(String[] excludeJUnit5Engines) {
996         this.excludeJUnit5Engines = excludeJUnit5Engines;
997     }
998 }