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 static org.codehaus.plexus.util.IOUtil.*;
23  
24  import java.io.BufferedInputStream;
25  import java.io.BufferedOutputStream;
26  import java.io.BufferedReader;
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.InputStreamReader;
32  import java.io.OutputStreamWriter;
33  import java.io.Writer;
34  import java.util.ArrayList;
35  import java.util.HashMap;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Properties;
39  
40  import org.apache.maven.artifact.Artifact;
41  import org.apache.maven.artifact.factory.ArtifactFactory;
42  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
43  import org.apache.maven.artifact.repository.ArtifactRepository;
44  import org.apache.maven.artifact.resolver.ArtifactResolver;
45  import org.apache.maven.execution.MavenSession;
46  import org.apache.maven.plugin.MojoExecution;
47  import org.apache.maven.plugin.MojoExecutionException;
48  import org.apache.maven.plugin.MojoFailureException;
49  import org.apache.maven.plugin.descriptor.PluginDescriptor;
50  import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
51  import org.apache.maven.plugin.surefire.Summary;
52  import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
53  import org.apache.maven.project.MavenProject;
54  import org.apache.maven.surefire.booter.ProviderConfiguration;
55  import org.apache.maven.surefire.failsafe.model.FailsafeSummary;
56  import org.apache.maven.surefire.failsafe.model.io.xpp3.FailsafeSummaryXpp3Reader;
57  import org.apache.maven.surefire.failsafe.model.io.xpp3.FailsafeSummaryXpp3Writer;
58  import org.apache.maven.surefire.suite.RunResult;
59  import org.apache.maven.toolchain.ToolchainManager;
60  import org.codehaus.plexus.util.ReaderFactory;
61  import org.codehaus.plexus.util.StringUtils;
62  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
63  
64  /**
65   * Run integration tests using Surefire.
66   *
67   * @author Jason van Zyl
68   * @author Stephen Connolly
69   * @requiresProject true
70   * @requiresDependencyResolution test
71   * @goal integration-test
72   * @phase integration-test
73   * @threadSafe
74   * @noinspection JavaDoc, UnusedDeclaration
75   */
76  public class IntegrationTestMojo
77      extends AbstractSurefireMojo
78  {
79  
80      private static final String FAILSAFE_IN_PROGRESS_CONTEXT_KEY = "failsafe-in-progress";
81  
82      /**
83       * Information about this plugin, mainly used to lookup this plugin's configuration from the currently executing
84       * project.
85       * 
86       * @parameter default-value="${plugin}"
87       * @readonly
88       * @since 2.12
89       */
90      private PluginDescriptor pluginDescriptor;
91  
92      /**
93       * Set this to "true" to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite
94       * convenient on occasion.
95       *
96       * @parameter default-value="false" expression="${skipTests}"
97       * @since 2.4
98       */
99      private boolean skipTests;
100 
101     /**
102      * Set this to "true" to skip running integration tests, but still compile them. Its use is NOT RECOMMENDED, but
103      * quite convenient on occasion.
104      *
105      * @parameter expression="${skipITs}"
106      * @since 2.4.3-alpha-2
107      */
108     private boolean skipITs;
109 
110     /**
111      * This old parameter is just like <code>skipTests</code>, but bound to the old property "maven.test.skip.exec".
112      *
113      * @parameter expression="${maven.test.skip.exec}"
114      * @since 2.3
115      * @deprecated Use skipTests instead.
116      */
117     private boolean skipExec;
118 
119     /**
120      * Set this to "true" to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you enable it using
121      * the "maven.test.skip" property, because maven.test.skip disables both running the tests and compiling the tests.
122      * Consider using the <code>skipTests parameter</code> instead.
123      *
124      * @parameter default-value="false" expression="${maven.test.skip}"
125      */
126     private boolean skip;
127 
128     /**
129      * The base directory of the project being tested. This can be obtained in your integration test via
130      * System.getProperty("basedir").
131      *
132      * @parameter default-value="${basedir}"
133      */
134     private File basedir;
135 
136     /**
137      * The directory containing generated test classes of the project being tested. This will be included at the
138      * beginning of the test classpath.
139      *
140      * @parameter default-value="${project.build.testOutputDirectory}"
141      */
142     private File testClassesDirectory;
143 
144     /**
145      * The directory containing generated classes of the project being tested. This will be included after the test
146      * classes in the test classpath.
147      *
148      * @parameter default-value="${project.build.outputDirectory}"
149      */
150     private File classesDirectory;
151 
152     /**
153      * The Maven Project Object.
154      *
155      * @parameter default-value="${project}"
156      * @readonly
157      */
158     private MavenProject project;
159 
160     /**
161      * List of dependencies to exclude from the test classpath. Each dependency string must follow the format
162      * <i>groupId:artifactId</i>. For example: <i>org.acme:project-a</i>
163      *
164      * @parameter
165      * @since 2.6
166      */
167     private List<String> classpathDependencyExcludes;
168 
169     /**
170      * A dependency scope to exclude from the test classpath. The scope should be one of the scopes defined by
171      * org.apache.maven.artifact.Artifact. This includes the following:
172      * <p/>
173      * <ul>
174      * <li><i>compile</i> - system, provided, compile
175      * <li><i>runtime</i> - compile, runtime
176      * <li><i>compile+runtime</i> - system, provided, compile, runtime
177      * <li><i>runtime+system</i> - system, compile, runtime
178      * <li><i>test</i> - system, provided, compile, runtime, test
179      * </ul>
180      *
181      * @parameter default-value=""
182      * @since 2.6
183      */
184     private String classpathDependencyScopeExclude;
185 
186     /**
187      * Additional elements to be appended to the classpath.
188      *
189      * @parameter
190      * @since 2.4
191      */
192     private List<String> additionalClasspathElements;
193 
194     /**
195      * Base directory where all reports are written to.
196      *
197      * @parameter default-value="${project.build.directory}/failsafe-reports"
198      */
199     private File reportsDirectory;
200 
201     /**
202      * The test source directory containing test class sources.
203      *
204      * @parameter default-value="${project.build.testSourceDirectory}"
205      * @required
206      * @since 2.2
207      */
208     private File testSourceDirectory;
209 
210     /**
211      * Specify this parameter to run individual tests by file name, overriding the <code>includes/excludes</code>
212      * parameters. Each pattern you specify here will be used to create an include pattern formatted like
213      * <code>**&#47;${test}.java</code>, so you can just type "-Dit.test=MyTest" to run a single test called
214      * "foo/MyTest.java".<br/>
215      * This parameter overrides the <code>includes/excludes</code> parameters, and the TestNG <code>suiteXmlFiles</code>
216      * parameter.
217      * <p/>
218      * since 2.7.3 You can execute a limited number of method in the test with adding #myMethod or #my*ethod. Si type
219      * "-Dtest=MyTest#myMethod" <b>supported for junit 4.x and testNg</b>
220      *
221      * @parameter expression="${it.test}"
222      */
223     private String test;
224 
225     /**
226      * A list of &lt;include> elements specifying the tests (by pattern) that should be included in testing. When not
227      * specified and when the <code>test</code> parameter is not specified, the default includes will be <code><br/>
228      * &lt;includes><br/>
229      * &nbsp;&lt;include>**&#47;IT*.java&lt;/include><br/>
230      * &nbsp;&lt;include>**&#47;*IT.java&lt;/include><br/>
231      * &nbsp;&lt;include>**&#47;*ITCase.java&lt;/include><br/>
232      * &lt;/includes><br/>
233      * </code>
234      * <p/>
235      * Each include item may also contain a comma-separated sublist of items, which will be treated as multiple
236      * &nbsp;&lt;include> entries.<br/>
237      * <p/>
238      * This parameter is ignored if the TestNG <code>suiteXmlFiles</code> parameter is specified.
239      *
240      * @parameter
241      */
242     private List<String> includes;
243 
244     /**
245      * A list of &lt;exclude> elements specifying the tests (by pattern) that should be excluded in testing. When not
246      * specified and when the <code>test</code> parameter is not specified, the default excludes will be <code><br/>
247      * &lt;excludes><br/>
248      * &nbsp;&lt;exclude>**&#47;*$*&lt;/exclude><br/>
249      * &lt;/excludes><br/>
250      * </code> (which excludes all inner classes).<br>
251      * This parameter is ignored if the TestNG <code>suiteXmlFiles</code> parameter is specified.
252      * <p/>
253      * Each exclude item may also contain a comma-separated sublist of items, which will be treated as multiple
254      * &nbsp;&lt;exclude> entries.<br/>
255      *
256      * @parameter
257      */
258     private List<String> excludes;
259 
260     /**
261      * ArtifactRepository of the localRepository. To obtain the directory of localRepository in unit tests use
262      * System.getProperty("localRepository").
263      *
264      * @parameter expression="${localRepository}"
265      * @required
266      * @readonly
267      */
268     private ArtifactRepository localRepository;
269 
270     /**
271      * List of System properties to pass to the JUnit tests.
272      *
273      * @parameter
274      * @deprecated Use systemPropertyVariables instead.
275      */
276     private Properties systemProperties;
277 
278     /**
279      * List of System properties to pass to the JUnit tests.
280      *
281      * @parameter
282      * @since 2.5
283      */
284     private Map<String,String> systemPropertyVariables;
285 
286     /**
287      * List of System properties, loaded from a file, to pass to the JUnit tests.
288      *
289      * @parameter
290      * @since 2.8.2
291      */
292     private File systemPropertiesFile;
293 
294     /**
295      * List of properties for configuring all TestNG related configurations. This is the new preferred method of
296      * configuring TestNG.
297      *
298      * @parameter
299      * @since 2.4
300      */
301     private Properties properties;
302 
303     /**
304      * Map of plugin artifacts.
305      *
306      * @parameter expression="${plugin.artifactMap}"
307      * @required
308      * @readonly
309      */
310     private Map<String,Artifact> pluginArtifactMap;
311 
312     /**
313      * Map of project artifacts.
314      *
315      * @parameter expression="${project.artifactMap}"
316      * @required
317      * @readonly
318      */
319     private Map<String,Artifact> projectArtifactMap;
320 
321     /**
322      * The summary file to write integration test results to.
323      *
324      * @parameter expression="${project.build.directory}/failsafe-reports/failsafe-summary.xml"
325      * @required
326      */
327     private File summaryFile;
328 
329     /**
330      * Option to print summary of test suites or just print the test cases that have errors.
331      *
332      * @parameter expression="${failsafe.printSummary}" default-value="true"
333      */
334     private boolean printSummary;
335 
336     /**
337      * Selects the formatting for the test report to be generated. Can be set as "brief" or "plain".
338      *
339      * @parameter expression="${failsafe.reportFormat}" default-value="brief"
340      */
341     private String reportFormat;
342 
343     /**
344      * Add custom text into report filename: TEST-testClassName-reportNameSuffix.xml,
345      * testClassName-reportNameSuffix.txt and testClassName-reportNameSuffix-output.txt.
346      * File TEST-testClassName-reportNameSuffix.xml has changed attributes 'testsuite'--'name'
347      * and 'testcase'--'classname' - reportNameSuffix is added to the attribute value.
348      *
349      * @parameter expression="${surefire.reportNameSuffix}" default-value=""
350      */
351     private String reportNameSuffix;
352 
353     /**
354      * Option to generate a file test report or just output the test report to the console.
355      *
356      * @parameter expression="${failsafe.useFile}" default-value="true"
357      */
358     private boolean useFile;
359 
360     /**
361      * Set this to "true" to redirect the unit test standard output to a file (found in
362      * reportsDirectory/testName-output.txt).
363      *
364      * @parameter expression="${maven.test.redirectTestOutputToFile}" default-value="false"
365      * @since 2.3
366      */
367     private boolean redirectTestOutputToFile;
368 
369     /**
370      * Set this to "true" to cause a failure if there are no tests to run. Defaults to "false".
371      *
372      * @parameter expression="${failIfNoTests}"
373      * @since 2.4
374      */
375     private Boolean failIfNoTests;
376 
377     /**
378      * Set this to "true" to cause a failure if the none of the tests specified in -Dtest=... are run. Defaults to
379      * "true".
380      * 
381      * @parameter expression="${it.failIfNoSpecifiedTests}"
382      * @since 2.12
383      */
384     private Boolean failIfNoSpecifiedTests;
385 
386     /**
387      * Option to specify the forking mode. Can be "never", "once", "always" or "perthread". "none" and "pertest" are also accepted
388      * for backwards compatibility. "always" forks for each test-class. "perthread" will create "threadCount" parallel forks.
389      *
390      * @parameter expression="${forkMode}" default-value="once"
391      * @since 2.1
392      */
393     private String forkMode;
394 
395     /**
396      * Option to specify the jvm (or path to the java executable) to use with the forking options. For the default, the
397      * jvm will be a new instance of the same VM as the one used to run Maven. JVM settings are not inherited from
398      * MAVEN_OPTS.
399      *
400      * @parameter expression="${jvm}"
401      * @since 2.1
402      */
403     private String jvm;
404 
405     /**
406      * Arbitrary JVM options to set on the command line.
407      *
408      * @parameter expression="${argLine}"
409      * @since 2.1
410      */
411     private String argLine;
412 
413     /**
414      * Attach a debugger to the forked JVM. If set to "true", the process will suspend and wait for a debugger to attach
415      * on port 5005. If set to some other string, that string will be appended to the argLine, allowing you to configure
416      * arbitrary debuggability options (without overwriting the other options specified through the <code>argLine</code>
417      * parameter).
418      *
419      * @parameter expression="${maven.failsafe.debug}"
420      * @since 2.4
421      */
422     private String debugForkedProcess;
423 
424     /**
425      * Kill the forked test process after a certain number of seconds. If set to 0, wait forever for the process, never
426      * timing out.
427      *
428      * @parameter expression="${failsafe.timeout}"
429      * @since 2.4
430      */
431     private int forkedProcessTimeoutInSeconds;
432 
433     /**
434      * Additional environment variables to set on the command line.
435      *
436      * @parameter
437      * @since 2.1.3
438      */
439     private Map<String,String> environmentVariables = new HashMap<String,String>();
440 
441     /**
442      * Command line working directory.
443      *
444      * @parameter expression="${basedir}"
445      * @since 2.1.3
446      */
447     private File workingDirectory;
448 
449     /**
450      * When false it makes tests run using the standard classloader delegation instead of the default Maven isolated
451      * classloader. Only used when forking (forkMode is not "none").<br/>
452      * Setting it to false helps with some problems caused by conflicts between xml parsers in the classpath and the
453      * Java 5 provider parser.
454      *
455      * @parameter expression="${childDelegation}" default-value="false"
456      * @since 2.1
457      */
458     private boolean childDelegation;
459 
460     /**
461      * (TestNG/JUnit47 provider with JUnit4.8+ only) Groups for this test. Only classes/methods/etc decorated with one of the groups specified here will
462      * be included in test run, if specified.<br/>For JUnit, this parameter forces the use of the 4.7 provider<br/>
463      * This parameter is ignored if the <code>suiteXmlFiles</code> parameter is specified.
464      *
465      * @parameter expression="${groups}"
466      * @since 2.2
467      */
468     private String groups;
469 
470     /**
471      * (TestNG/JUnit47 provider with JUnit4.8+ only) Excluded groups. Any methods/classes/etc with one of the groups specified in this list will
472      * specifically not be run.<br/>For JUnit, this parameter forces the use of the 4.7 provider<br/>
473      * This parameter is ignored if the <code>suiteXmlFiles</code> parameter is specified.
474      *
475      * @parameter expression="${excludedGroups}"
476      * @since 2.2
477      */
478     private String excludedGroups;
479 
480     /**
481      * (TestNG only) List of &lt;suiteXmlFile> elements specifying TestNG suite xml file locations. Note that
482      * <code>suiteXmlFiles</code> is incompatible with several other parameters of this plugin, like
483      * <code>includes/excludes</code>.<br/>
484      * This parameter is ignored if the <code>test</code> parameter is specified (allowing you to run a single test
485      * instead of an entire suite).
486      *
487      * @parameter
488      * @since 2.2
489      */
490     private File[] suiteXmlFiles;
491 
492     /**
493      * Allows you to specify the name of the JUnit artifact. If not set, <code>junit:junit</code> will be used.
494      *
495      * @parameter expression="${junitArtifactName}" default-value="junit:junit"
496      * @since 2.3.1
497      */
498     private String junitArtifactName;
499 
500     /**
501      * Allows you to specify the name of the TestNG artifact. If not set, <code>org.testng:testng</code> will be used.
502      *
503      * @parameter expression="${testNGArtifactName}" default-value="org.testng:testng"
504      * @since 2.3.1
505      */
506     private String testNGArtifactName;
507 
508     /**
509      * (forkMode=perthread or TestNG/JUnit 4.7 provider) The attribute thread-count allows you to specify how many threads should be
510      * allocated for this execution. Only makes sense to use in conjunction with the <code>parallel</code> parameter. (forkMode=perthread
511      * does not support/require the <code>parallel</code> parameter)
512      *
513      * @parameter expression="${threadCount}"
514      * @since 2.2
515      */
516     private int threadCount;
517 
518     /**
519      * (JUnit 4.7 provider) Indicates that threadCount is per cpu core.
520      *
521      * @parameter expression="${perCoreThreadCount}" default-value="true"
522      * @since 2.5
523      */
524     private boolean perCoreThreadCount;
525 
526     /**
527      * (JUnit 4.7 provider) Indicates that the thread pool will be unlimited. The <code>parallel</code> parameter and
528      * the actual number of classes/methods will decide. Setting this to "true" effectively disables
529      * <code>perCoreThreadCount</code> and <code>threadCount</code>. Defaults to "false".
530      *
531      * @parameter expression="${useUnlimitedThreads}" default-value="false"
532      * @since 2.5
533      */
534     private boolean useUnlimitedThreads;
535 
536     /**
537      * (TestNG only) When you use the <code>parallel</code> attribute, TestNG will try to run all your test methods in
538      * separate threads, except for methods that depend on each other, which will be run in the same thread in order to
539      * respect their order of execution.
540      * <p/>
541      * (JUnit 4.7 provider) Supports values "classes"/"methods"/"both" to run in separate threads, as controlled by
542      * <code>threadCount</code>.
543      *
544      * @parameter expression="${parallel}"
545      * @todo test how this works with forking, and console/file output parallelism
546      * @since 2.2
547      */
548     private String parallel;
549 
550     /**
551      * Whether to trim the stack trace in the reports to just the lines within the test, or show the full trace.
552      *
553      * @parameter expression="${trimStackTrace}" default-value="true"
554      * @since 2.2
555      */
556     private boolean trimStackTrace;
557 
558     /**
559      * Resolves the artifacts needed.
560      *
561      * @component
562      */
563     private ArtifactResolver artifactResolver;
564 
565     /**
566      * Creates the artifact.
567      *
568      * @component
569      */
570     private ArtifactFactory artifactFactory;
571 
572     /**
573      * The remote plugin repositories declared in the POM.
574      *
575      * @parameter expression="${project.pluginArtifactRepositories}"
576      * @since 2.2
577      */
578     private List remoteRepositories;
579 
580     /**
581      * For retrieval of artifact's metadata.
582      *
583      * @component
584      */
585     private ArtifactMetadataSource metadataSource;
586 
587     private Properties originalSystemProperties;
588 
589     /**
590      * systemPropertyVariables + systemProperties
591      */
592     private Properties internalSystemProperties = new Properties();
593 
594     /**
595      * Flag to disable the generation of report files in xml format.
596      *
597      * @parameter expression="${disableXmlReport}" default-value="false"
598      * @since 2.2
599      */
600     private boolean disableXmlReport;
601 
602     /**
603      * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
604      * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
605      * classloader.
606      *
607      * @parameter expression="${failsafe.useSystemClassLoader}" default-value="true"
608      * @since 2.3
609      */
610     private boolean useSystemClassLoader;
611 
612     /**
613      * By default, Surefire forks your tests using a manifest-only JAR; set this parameter to "false" to force it to
614      * launch your tests with a plain old Java classpath. (See
615      * http://maven.apache.org/plugins/maven-surefire-plugin/examples/class-loading.html for a more detailed explanation
616      * of manifest-only JARs and their benefits.)
617      * <p/>
618      * Beware, setting this to "false" may cause your tests to fail on Windows if your classpath is too long.
619      *
620      * @parameter expression="${failsafe.useManifestOnlyJar}" default-value="true"
621      * @since 2.4.3
622      */
623     private boolean useManifestOnlyJar;
624 
625     /**
626      * By default, Surefire enables JVM assertions for the execution of your test cases. To disable the assertions, set
627      * this flag to "false".
628      *
629      * @parameter expression="${enableAssertions}" default-value="true"
630      * @since 2.3.1
631      */
632     private boolean enableAssertions;
633 
634     /**
635      * The current build session instance.
636      *
637      * @parameter expression="${session}"
638      * @required
639      * @readonly
640      */
641     private MavenSession session;
642 
643     /**
644      * (TestNG only) Define the factory class used to create all test instances.
645      *
646      * @parameter expression="${objectFactory}"
647      * @since 2.5
648      */
649     private String objectFactory;
650 
651     /**
652      * The character encoding scheme to be applied.
653      *
654      * @parameter expression="${encoding}" default-value="${project.reporting.outputEncoding}"
655      */
656     private String encoding;
657 
658     /**
659      * @parameter default-value="${session.parallel}"
660      * @readonly
661      */
662     private Boolean parallelMavenExecution;
663 
664     /**
665      * Defines the order the tests will be run in. Supported values are "alphabetical", "reversealphabetical", "random",
666      * "hourly" (alphabetical on even hours, reverse alphabetical on odd hours), "failedfirst", "balanced" and "filesystem".
667      * <p/>
668      * <p/>
669      * Odd/Even for hourly is determined at the time the of scanning the classpath, meaning it could change during a
670      * multi-module build.
671      * <p/>
672      * Failed first will run tests that failed on previous run first, as well as new tests for this run.
673      * <p/>
674      * Balanced is only relevant with parallel=classes, and will try to optimize the run-order of the tests to
675      * make all tests complete at the same time, reducing the overall execution time.
676      * <p/>
677      * Note that the statistics are stored in a file named .surefire-XXXXXXXXX beside pom.xml, and should not
678      * be checked into version control. The "XXXXX" is the SHA1 checksum of the entire surefire configuration,
679      * so different configurations will have different statistics files, meaning if you change any config
680      * settings you will re-run once before new statistics data can be established.
681      *
682      * @parameter default-value="filesystem"
683      * @since 2.7
684      */
685     private String runOrder;
686 
687     /**
688      * @component
689      */
690     private ToolchainManager toolchainManager;
691 
692     protected void handleSummary( Summary summary )
693         throws MojoExecutionException, MojoFailureException
694     {
695         FailsafeSummary failsafeSummary = createFailsafeSummaryFromSummary( summary );
696         writeSummary( failsafeSummary );
697     }
698 
699     private FailsafeSummary createFailsafeSummaryFromSummary( Summary summary )
700     {
701         FailsafeSummary failsafeSummary = new FailsafeSummary();
702         if ( summary.isErrorFree() )
703         {
704             RunResult result = summary.getResultOfLastSuccessfulRun();
705             if ( result != null )
706             {
707                 failsafeSummary.setResult( result.getForkedProcessCode() );
708             }
709         }
710         else
711         {
712             failsafeSummary.setResult( ProviderConfiguration.TESTS_FAILED_EXIT_CODE );
713             //noinspection ThrowableResultOfMethodCallIgnored
714             failsafeSummary.setException( summary.getFirstException().getMessage() );
715         }
716         return failsafeSummary;
717     }
718 
719     @SuppressWarnings( "unchecked" )
720     private void writeSummary( FailsafeSummary summary )
721         throws MojoExecutionException
722     {
723         File summaryFile = getSummaryFile();
724         if ( !summaryFile.getParentFile().isDirectory() )
725         {
726             summaryFile.getParentFile().mkdirs();
727         }
728 
729         FileOutputStream fout = null;
730         FileInputStream fin = null;
731         try
732         {
733             FailsafeSummary mergedSummary = summary;
734             Object token = getPluginContext().get( FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
735             if ( summaryFile.exists() && token != null )
736             {
737                 fin = new FileInputStream( summaryFile );
738 
739                 mergedSummary =
740                     new FailsafeSummaryXpp3Reader().read( new InputStreamReader( new BufferedInputStream( fin ),
741                                                                                  getEncodingOrDefault() ) );
742                 
743                 mergedSummary.merge( summary );
744             }
745 
746             fout = new FileOutputStream( summaryFile );
747             BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( fout );
748             Writer writer = new OutputStreamWriter( bufferedOutputStream, getEncodingOrDefault() );
749             FailsafeSummaryXpp3Writer xpp3Writer = new FailsafeSummaryXpp3Writer();
750             xpp3Writer.write( writer, mergedSummary );
751             writer.close();
752             bufferedOutputStream.close();
753         }
754         catch ( IOException e )
755         {
756             throw new MojoExecutionException( e.getMessage(), e );
757         }
758         catch ( XmlPullParserException e )
759         {
760             throw new MojoExecutionException( e.getMessage(), e );
761         }
762         finally
763         {
764             close( fin );
765             close( fout );
766         }
767 
768         getPluginContext().put( FAILSAFE_IN_PROGRESS_CONTEXT_KEY, FAILSAFE_IN_PROGRESS_CONTEXT_KEY );
769     }
770 
771     private String getEncodingOrDefault()
772     {
773         if ( StringUtils.isEmpty( encoding ) )
774         {
775             getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING +
776                                ", i.e. build is platform dependent!" );
777             return ReaderFactory.FILE_ENCODING;
778         }
779         else
780         {
781             return encoding;
782         }
783     }
784 
785     protected boolean isSkipExecution()
786     {
787         return isSkip() || isSkipTests() || isSkipITs() || isSkipExec();
788     }
789 
790     protected String getPluginName()
791     {
792         return "failsafe";
793     }
794 
795     protected String[] getDefaultIncludes()
796     {
797         return new String[]{ "**/IT*.java", "**/*IT.java", "**/*ITCase.java" };
798     }
799 
800     public boolean isSkipTests()
801     {
802         return skipTests;
803     }
804 
805     public void setSkipTests( boolean skipTests )
806     {
807         this.skipTests = skipTests;
808     }
809 
810     public boolean isSkipITs()
811     {
812         return skipITs;
813     }
814 
815     public void setSkipITs( boolean skipITs )
816     {
817         this.skipITs = skipITs;
818     }
819 
820     public boolean isSkipExec()
821     {
822         return skipExec;
823     }
824 
825     public void setSkipExec( boolean skipExec )
826     {
827         this.skipExec = skipExec;
828     }
829 
830     public boolean isSkip()
831     {
832         return skip;
833     }
834 
835     public void setSkip( boolean skip )
836     {
837         this.skip = skip;
838     }
839 
840     public File getBasedir()
841     {
842         return basedir;
843     }
844 
845     public void setBasedir( File basedir )
846     {
847         this.basedir = basedir;
848     }
849 
850     public File getTestClassesDirectory()
851     {
852         return testClassesDirectory;
853     }
854 
855     public void setTestClassesDirectory( File testClassesDirectory )
856     {
857         this.testClassesDirectory = testClassesDirectory;
858     }
859 
860     public File getClassesDirectory()
861     {
862         return classesDirectory;
863     }
864 
865     public void setClassesDirectory( File classesDirectory )
866     {
867         this.classesDirectory = classesDirectory;
868     }
869 
870     public MavenProject getProject()
871     {
872         return project;
873     }
874 
875     public void setProject( MavenProject project )
876     {
877         this.project = project;
878     }
879 
880     public List getClasspathDependencyExcludes()
881     {
882         return classpathDependencyExcludes;
883     }
884 
885     public void setClasspathDependencyExcludes( List classpathDependencyExcludes )
886     {
887         this.classpathDependencyExcludes = classpathDependencyExcludes;
888     }
889 
890     public String getClasspathDependencyScopeExclude()
891     {
892         return classpathDependencyScopeExclude;
893     }
894 
895     public void setClasspathDependencyScopeExclude( String classpathDependencyScopeExclude )
896     {
897         this.classpathDependencyScopeExclude = classpathDependencyScopeExclude;
898     }
899 
900     public List getAdditionalClasspathElements()
901     {
902         return additionalClasspathElements;
903     }
904 
905     public void setAdditionalClasspathElements( List additionalClasspathElements )
906     {
907         this.additionalClasspathElements = additionalClasspathElements;
908     }
909 
910     public File getReportsDirectory()
911     {
912         return reportsDirectory;
913     }
914 
915     public void setReportsDirectory( File reportsDirectory )
916     {
917         this.reportsDirectory = reportsDirectory;
918     }
919 
920     public File getTestSourceDirectory()
921     {
922         return testSourceDirectory;
923     }
924 
925     public void setTestSourceDirectory( File testSourceDirectory )
926     {
927         this.testSourceDirectory = testSourceDirectory;
928     }
929 
930     public String getTest()
931     {
932         if ( StringUtils.isBlank( test ) )
933         {
934             return null;
935         }
936         int index = test.indexOf( '#' );
937         if ( index >= 0 )
938         {
939             return test.substring( 0, index );
940         }
941         return test;
942     }
943 
944     public void setTest( String test )
945     {
946         this.test = test;
947     }
948 
949     /**
950      * @since 2.7.3
951      */
952     public String getTestMethod()
953     {
954         if ( StringUtils.isBlank( test ) )
955         {
956             return null;
957         }
958         int index = this.test.indexOf( '#' );
959         if ( index >= 0 )
960         {
961             return this.test.substring( index + 1, this.test.length() );
962         }
963         return null;
964     }
965 
966     public List<String> getIncludes()
967     {
968         return includes;
969     }
970 
971     public void setIncludes( List<String> includes )
972     {
973         this.includes = includes;
974     }
975 
976     public List<String> getExcludes()
977     {
978         return excludes;
979     }
980 
981     public void setExcludes( List<String> excludes )
982     {
983         this.excludes = excludes;
984     }
985 
986     public ArtifactRepository getLocalRepository()
987     {
988         return localRepository;
989     }
990 
991     public void setLocalRepository( ArtifactRepository localRepository )
992     {
993         this.localRepository = localRepository;
994     }
995 
996     public Properties getSystemProperties()
997     {
998         return systemProperties;
999     }
1000 
1001     public void setSystemProperties( Properties systemProperties )
1002     {
1003         this.systemProperties = systemProperties;
1004     }
1005 
1006     public Map<String,String> getSystemPropertyVariables()
1007     {
1008         return systemPropertyVariables;
1009     }
1010 
1011     public void setSystemPropertyVariables( Map<String,String> systemPropertyVariables )
1012     {
1013         this.systemPropertyVariables = systemPropertyVariables;
1014     }
1015 
1016     public File getSystemPropertiesFile()
1017     {
1018         return systemPropertiesFile;
1019     }
1020 
1021     public void setSystemPropertiesFile( File systemPropertiesFile )
1022     {
1023         this.systemPropertiesFile = systemPropertiesFile;
1024     }
1025 
1026     public Properties getProperties()
1027     {
1028         return properties;
1029     }
1030 
1031     public void setProperties( Properties properties )
1032     {
1033         this.properties = properties;
1034     }
1035 
1036     public Map<String,Artifact> getPluginArtifactMap()
1037     {
1038         return pluginArtifactMap;
1039     }
1040 
1041     public void setPluginArtifactMap( Map<String,Artifact> pluginArtifactMap )
1042     {
1043         this.pluginArtifactMap = pluginArtifactMap;
1044     }
1045 
1046     public Map getProjectArtifactMap()
1047     {
1048         return projectArtifactMap;
1049     }
1050 
1051     public void setProjectArtifactMap( Map projectArtifactMap )
1052     {
1053         this.projectArtifactMap = projectArtifactMap;
1054     }
1055 
1056     public File getSummaryFile()
1057     {
1058         return summaryFile;
1059     }
1060 
1061     public void setSummaryFile( File summaryFile )
1062     {
1063         this.summaryFile = summaryFile;
1064     }
1065 
1066     public boolean isPrintSummary()
1067     {
1068         return printSummary;
1069     }
1070 
1071     public void setPrintSummary( boolean printSummary )
1072     {
1073         this.printSummary = printSummary;
1074     }
1075 
1076     public String getReportFormat()
1077     {
1078         return reportFormat;
1079     }
1080 
1081     public void setReportFormat( String reportFormat )
1082     {
1083         this.reportFormat = reportFormat;
1084     }
1085 
1086     public String getReportNameSuffix()
1087     {
1088         return reportNameSuffix;
1089     }
1090 
1091     public void setReportNameSuffix( String reportNameSuffix )
1092     {
1093         this.reportNameSuffix = reportNameSuffix;
1094     }
1095 
1096     public boolean isUseFile()
1097     {
1098         return useFile;
1099     }
1100 
1101     public void setUseFile( boolean useFile )
1102     {
1103         this.useFile = useFile;
1104     }
1105 
1106     public boolean isRedirectTestOutputToFile()
1107     {
1108         return redirectTestOutputToFile;
1109     }
1110 
1111     public void setRedirectTestOutputToFile( boolean redirectTestOutputToFile )
1112     {
1113         this.redirectTestOutputToFile = redirectTestOutputToFile;
1114     }
1115 
1116     public Boolean getFailIfNoTests()
1117     {
1118         return failIfNoTests;
1119     }
1120 
1121     public void setFailIfNoTests( Boolean failIfNoTests )
1122     {
1123         this.failIfNoTests = failIfNoTests;
1124     }
1125 
1126     public String getForkMode()
1127     {
1128         return forkMode;
1129     }
1130 
1131     public void setForkMode( String forkMode )
1132     {
1133         this.forkMode = forkMode;
1134     }
1135 
1136     public String getJvm()
1137     {
1138         return jvm;
1139     }
1140 
1141     public void setJvm( String jvm )
1142     {
1143         this.jvm = jvm;
1144     }
1145 
1146     public String getArgLine()
1147     {
1148         return argLine;
1149     }
1150 
1151     public void setArgLine( String argLine )
1152     {
1153         this.argLine = argLine;
1154     }
1155 
1156     public String getDebugForkedProcess()
1157     {
1158         return debugForkedProcess;
1159     }
1160 
1161     public void setDebugForkedProcess( String debugForkedProcess )
1162     {
1163         this.debugForkedProcess = debugForkedProcess;
1164     }
1165 
1166     public int getForkedProcessTimeoutInSeconds()
1167     {
1168         return forkedProcessTimeoutInSeconds;
1169     }
1170 
1171     public void setForkedProcessTimeoutInSeconds( int forkedProcessTimeoutInSeconds )
1172     {
1173         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
1174     }
1175 
1176     public Map<String,String> getEnvironmentVariables()
1177     {
1178         return environmentVariables;
1179     }
1180 
1181     public void setEnvironmentVariables( Map<String,String> environmentVariables )
1182     {
1183         this.environmentVariables = environmentVariables;
1184     }
1185 
1186     public File getWorkingDirectory()
1187     {
1188         return workingDirectory;
1189     }
1190 
1191     public void setWorkingDirectory( File workingDirectory )
1192     {
1193         this.workingDirectory = workingDirectory;
1194     }
1195 
1196     public boolean isChildDelegation()
1197     {
1198         return childDelegation;
1199     }
1200 
1201     public void setChildDelegation( boolean childDelegation )
1202     {
1203         this.childDelegation = childDelegation;
1204     }
1205 
1206     public String getGroups()
1207     {
1208         return groups;
1209     }
1210 
1211     public void setGroups( String groups )
1212     {
1213         this.groups = groups;
1214     }
1215 
1216     public String getExcludedGroups()
1217     {
1218         return excludedGroups;
1219     }
1220 
1221     public void setExcludedGroups( String excludedGroups )
1222     {
1223         this.excludedGroups = excludedGroups;
1224     }
1225 
1226     public File[] getSuiteXmlFiles()
1227     {
1228         return suiteXmlFiles;
1229     }
1230 
1231     public void setSuiteXmlFiles( File[] suiteXmlFiles )
1232     {
1233         this.suiteXmlFiles = suiteXmlFiles;
1234     }
1235 
1236     public String getJunitArtifactName()
1237     {
1238         return junitArtifactName;
1239     }
1240 
1241     public void setJunitArtifactName( String junitArtifactName )
1242     {
1243         this.junitArtifactName = junitArtifactName;
1244     }
1245 
1246     public String getTestNGArtifactName()
1247     {
1248         return testNGArtifactName;
1249     }
1250 
1251     public void setTestNGArtifactName( String testNGArtifactName )
1252     {
1253         this.testNGArtifactName = testNGArtifactName;
1254     }
1255 
1256     public int getThreadCount()
1257     {
1258         return threadCount;
1259     }
1260 
1261     public void setThreadCount( int threadCount )
1262     {
1263         this.threadCount = threadCount;
1264     }
1265 
1266     public boolean getPerCoreThreadCount()
1267     {
1268         return perCoreThreadCount;
1269     }
1270 
1271     public void setPerCoreThreadCount( boolean perCoreThreadCount )
1272     {
1273         this.perCoreThreadCount = perCoreThreadCount;
1274     }
1275 
1276     public boolean getUseUnlimitedThreads()
1277     {
1278         return useUnlimitedThreads;
1279     }
1280 
1281     public void setUseUnlimitedThreads( boolean useUnlimitedThreads )
1282     {
1283         this.useUnlimitedThreads = useUnlimitedThreads;
1284     }
1285 
1286     public String getParallel()
1287     {
1288         return parallel;
1289     }
1290 
1291     public void setParallel( String parallel )
1292     {
1293         this.parallel = parallel;
1294     }
1295 
1296     public boolean isTrimStackTrace()
1297     {
1298         return trimStackTrace;
1299     }
1300 
1301     public void setTrimStackTrace( boolean trimStackTrace )
1302     {
1303         this.trimStackTrace = trimStackTrace;
1304     }
1305 
1306     public ArtifactResolver getArtifactResolver()
1307     {
1308         return artifactResolver;
1309     }
1310 
1311     public void setArtifactResolver( ArtifactResolver artifactResolver )
1312     {
1313         this.artifactResolver = artifactResolver;
1314     }
1315 
1316     public ArtifactFactory getArtifactFactory()
1317     {
1318         return artifactFactory;
1319     }
1320 
1321     public void setArtifactFactory( ArtifactFactory artifactFactory )
1322     {
1323         this.artifactFactory = artifactFactory;
1324     }
1325 
1326     public List getRemoteRepositories()
1327     {
1328         return remoteRepositories;
1329     }
1330 
1331     public void setRemoteRepositories( List remoteRepositories )
1332     {
1333         this.remoteRepositories = remoteRepositories;
1334     }
1335 
1336     public ArtifactMetadataSource getMetadataSource()
1337     {
1338         return metadataSource;
1339     }
1340 
1341     public void setMetadataSource( ArtifactMetadataSource metadataSource )
1342     {
1343         this.metadataSource = metadataSource;
1344     }
1345 
1346     public Properties getOriginalSystemProperties()
1347     {
1348         return originalSystemProperties;
1349     }
1350 
1351     public void setOriginalSystemProperties( Properties originalSystemProperties )
1352     {
1353         this.originalSystemProperties = originalSystemProperties;
1354     }
1355 
1356     public Properties getInternalSystemProperties()
1357     {
1358         return internalSystemProperties;
1359     }
1360 
1361     public void setInternalSystemProperties( Properties internalSystemProperties )
1362     {
1363         this.internalSystemProperties = internalSystemProperties;
1364     }
1365 
1366     public boolean isDisableXmlReport()
1367     {
1368         return disableXmlReport;
1369     }
1370 
1371     public void setDisableXmlReport( boolean disableXmlReport )
1372     {
1373         this.disableXmlReport = disableXmlReport;
1374     }
1375 
1376     public boolean isUseSystemClassLoader()
1377     {
1378         return useSystemClassLoader;
1379     }
1380 
1381     public void setUseSystemClassLoader( boolean useSystemClassLoader )
1382     {
1383         this.useSystemClassLoader = useSystemClassLoader;
1384     }
1385 
1386     public boolean isUseManifestOnlyJar()
1387     {
1388         return useManifestOnlyJar;
1389     }
1390 
1391     public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
1392     {
1393         this.useManifestOnlyJar = useManifestOnlyJar;
1394     }
1395 
1396     public boolean isEnableAssertions()
1397     {
1398         return enableAssertions;
1399     }
1400 
1401     public void setEnableAssertions( boolean enableAssertions )
1402     {
1403         this.enableAssertions = enableAssertions;
1404     }
1405 
1406     public MavenSession getSession()
1407     {
1408         return session;
1409     }
1410 
1411     public void setSession( MavenSession session )
1412     {
1413         this.session = session;
1414     }
1415 
1416     public String getObjectFactory()
1417     {
1418         return objectFactory;
1419     }
1420 
1421     public void setObjectFactory( String objectFactory )
1422     {
1423         this.objectFactory = objectFactory;
1424     }
1425 
1426     public ToolchainManager getToolchainManager()
1427     {
1428         return toolchainManager;
1429     }
1430 
1431     public void setToolchainManager( ToolchainManager toolchainManager )
1432     {
1433         this.toolchainManager = toolchainManager;
1434     }
1435 
1436     // the following will be refactored out once the common code is all in one place
1437 
1438     public boolean isTestFailureIgnore()
1439     {
1440         return true; // ignore
1441     }
1442 
1443     public void setTestFailureIgnore( boolean testFailureIgnore )
1444     {
1445         // ignore
1446     }
1447 
1448     public boolean isMavenParallel()
1449     {
1450         return parallelMavenExecution != null && parallelMavenExecution;
1451     }
1452 
1453     public String getRunOrder()
1454     {
1455         return runOrder;
1456     }
1457 
1458     public void setRunOrder( String runOrder )
1459     {
1460         this.runOrder = runOrder;
1461     }
1462 
1463     protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
1464     {
1465         checksum.add( skipITs );
1466         checksum.add( summaryFile );
1467     }
1468 
1469     public Boolean getFailIfNoSpecifiedTests()
1470     {
1471         return failIfNoSpecifiedTests;
1472     }
1473 
1474     public void setFailIfNoSpecifiedTests( Boolean failIfNoSpecifiedTests )
1475     {
1476         this.failIfNoSpecifiedTests = failIfNoSpecifiedTests;
1477     }
1478 
1479     public PluginDescriptor getPluginDescriptor()
1480     {
1481         return pluginDescriptor;
1482     }
1483 
1484 }