View Javadoc
1   // CHECKSTYLE_OFF: FileLength|RegexpHeader
2   package org.apache.maven.plugin.surefire;
3   
4   /*
5    * Licensed to the Apache Software Foundation (ASF) under one
6    * or more contributor license agreements.  See the NOTICE file
7    * distributed with this work for additional information
8    * regarding copyright ownership.  The ASF licenses this file
9    * to you under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License.  You may obtain a copy of the License at
12   *
13   *     http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on an
17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied.  See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21   */
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.lang.reflect.Method;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.LinkedHashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Map.Entry;
35  import java.util.Properties;
36  import java.util.Set;
37  
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.artifact.factory.ArtifactFactory;
40  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
41  import org.apache.maven.artifact.repository.ArtifactRepository;
42  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
43  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
44  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
45  import org.apache.maven.artifact.resolver.ArtifactResolver;
46  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
47  import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
48  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
49  import org.apache.maven.artifact.versioning.ArtifactVersion;
50  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
51  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
52  import org.apache.maven.artifact.versioning.VersionRange;
53  import org.apache.maven.execution.MavenSession;
54  import org.apache.maven.model.Plugin;
55  import org.apache.maven.plugin.AbstractMojo;
56  import org.apache.maven.plugin.MojoExecutionException;
57  import org.apache.maven.plugin.MojoFailureException;
58  import org.apache.maven.plugin.descriptor.PluginDescriptor;
59  import org.apache.maven.plugin.logging.Log;
60  import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
61  import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
62  import org.apache.maven.plugin.surefire.booterclient.ForkStarter;
63  import org.apache.maven.plugin.surefire.util.DependencyScanner;
64  import org.apache.maven.plugin.surefire.util.DirectoryScanner;
65  import org.apache.maven.plugins.annotations.Component;
66  import org.apache.maven.plugins.annotations.Parameter;
67  import org.apache.maven.project.MavenProject;
68  import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
69  import org.apache.maven.shared.utils.StringUtils;
70  import org.apache.maven.shared.utils.io.FileUtils;
71  import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
72  import org.apache.maven.surefire.booter.Classpath;
73  import org.apache.maven.surefire.booter.ClasspathConfiguration;
74  import org.apache.maven.surefire.booter.KeyValueSource;
75  import org.apache.maven.surefire.booter.ProviderConfiguration;
76  import org.apache.maven.surefire.booter.ProviderParameterNames;
77  import org.apache.maven.surefire.booter.StartupConfiguration;
78  import org.apache.maven.surefire.booter.SurefireBooterForkException;
79  import org.apache.maven.surefire.booter.SurefireExecutionException;
80  import org.apache.maven.surefire.report.ReporterConfiguration;
81  import org.apache.maven.surefire.suite.RunResult;
82  import org.apache.maven.surefire.testset.DirectoryScannerParameters;
83  import org.apache.maven.surefire.testset.RunOrderParameters;
84  import org.apache.maven.surefire.testset.TestArtifactInfo;
85  import org.apache.maven.surefire.testset.TestRequest;
86  import org.apache.maven.surefire.testset.TestSetFailedException;
87  import org.apache.maven.surefire.util.DefaultScanResult;
88  import org.apache.maven.surefire.util.RunOrder;
89  import org.apache.maven.toolchain.Toolchain;
90  import org.apache.maven.toolchain.ToolchainManager;
91  
92  import javax.annotation.Nonnull;
93  
94  /**
95   * Abstract base class for running tests using Surefire.
96   *
97   * @author Stephen Connolly
98   * @version $Id: SurefirePlugin.java 945065 2010-05-17 10:26:22Z stephenc $
99   */
100 public abstract class AbstractSurefireMojo
101     extends AbstractMojo
102     implements SurefireExecutionParameters
103 {
104 
105     // common mojo parameters
106 
107     /**
108      * Information about this plugin, mainly used to lookup this plugin's configuration from the currently executing
109      * project.
110      *
111      * @since 2.12
112      */
113     @Parameter( defaultValue = "${plugin}", readonly = true )
114     protected PluginDescriptor pluginDescriptor;
115 
116     /**
117      * Set this to "true" to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite
118      * convenient on occasion.
119      *
120      * @since 2.4
121      */
122     @Parameter( property = "skipTests", defaultValue = "false" )
123     protected boolean skipTests;
124 
125     /**
126      * This old parameter is just like <code>skipTests</code>, but bound to the old property "maven.test.skip.exec".
127      *
128      * @since 2.3
129      * @deprecated Use skipTests instead.
130      */
131     @Parameter( property = "maven.test.skip.exec" )
132     protected boolean skipExec;
133 
134     /**
135      * Set this to "true" to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you enable it using
136      * the "maven.test.skip" property, because maven.test.skip disables both running the tests and compiling the tests.
137      * Consider using the <code>skipTests</code> parameter instead.
138      */
139     @Parameter( property = "maven.test.skip", defaultValue = "false" )
140     protected boolean skip;
141 
142     /**
143      * The Maven Project Object.
144      */
145     @Component
146     protected MavenProject project;
147 
148     /**
149      * The base directory of the project being tested. This can be obtained in your integration test via
150      * System.getProperty("basedir").
151      */
152     @Parameter( defaultValue = "${basedir}" )
153     protected File basedir;
154 
155     /**
156      * The directory containing generated test classes of the project being tested. This will be included at the
157      * beginning of the test classpath. *
158      */
159     @Parameter( defaultValue = "${project.build.testOutputDirectory}" )
160     protected File testClassesDirectory;
161 
162     /**
163      * The directory containing generated classes of the project being tested. This will be included after the test
164      * classes in the test classpath.
165      */
166     @Parameter( defaultValue = "${project.build.outputDirectory}" )
167     protected File classesDirectory;
168 
169     /**
170      * List of dependencies to exclude from the test classpath. Each dependency string must follow the format
171      * <i>groupId:artifactId</i>. For example: <i>org.acme:project-a</i>
172      *
173      * @since 2.6
174      */
175     @Parameter( property = "maven.test.dependency.excludes" )
176     private String[] classpathDependencyExcludes;
177 
178     /**
179      * A dependency scope to exclude from the test classpath. The scope should be one of the scopes defined by
180      * org.apache.maven.artifact.Artifact. This includes the following:
181      * <p/>
182      * <ul>
183      * <li><i>compile</i> - system, provided, compile
184      * <li><i>runtime</i> - compile, runtime
185      * <li><i>compile+runtime</i> - system, provided, compile, runtime
186      * <li><i>runtime+system</i> - system, compile, runtime
187      * <li><i>test</i> - system, provided, compile, runtime, test
188      * </ul>
189      *
190      * @since 2.6
191      */
192     @Parameter( defaultValue = "" )
193     private String classpathDependencyScopeExclude;
194 
195     /**
196      * Additional elements to be appended to the classpath.
197      *
198      * @since 2.4
199      */
200     @Parameter( property = "maven.test.additionalClasspath" )
201     private String[] additionalClasspathElements;
202 
203     /**
204      * The test source directory containing test class sources.
205      *
206      * @since 2.2
207      */
208     @Parameter( defaultValue = "${project.build.testSourceDirectory}", required = true )
209     protected File testSourceDirectory;
210 
211     /**
212      * A file containing include patterns. Blank lines, or lines starting with # are ignored. If {@code includes} are
213      * also specified these patterns are appended.
214      */
215     @Parameter
216     protected File includesFile;
217 
218     /**
219      * A list of &lt;exclude> elements specifying the tests (by pattern) that should be excluded in testing. When not
220      * specified and when the <code>test</code> parameter is not specified, the default excludes will be <code><br/>
221      * &lt;excludes><br/>
222      * &nbsp;&lt;exclude>**&#47;*$*&lt;/exclude><br/>
223      * &lt;/excludes><br/>
224      * </code> (which excludes all inner classes).<br>
225      * This parameter is ignored if the TestNG <code>suiteXmlFiles</code> parameter is specified.
226      * <p/>
227      * Each exclude item may also contain a comma-separated sublist of items, which will be treated as multiple
228      * &nbsp;&lt;exclude> entries.<br/>
229      * <br/>
230      * <em>Notice that</em> these values are relative to the directory containing generated test classes of the project
231      * being tested. This directory is declared by the parameter <code>testClassesDirectory</code> which defaults
232      * to the POM property <code>${project.build.testOutputDirectory}</code>, typically <em>src/test/java</em>
233      * unless overridden.
234      */
235     @Parameter
236     protected List<String> excludes;
237 
238     /**
239      * A file containing exclude patterns. Blank lines, or lines starting with # are ignored. If {@code excludes} are
240      * also specified these patterns are appended.
241      */
242     @Parameter
243     protected File excludesFile;
244 
245     /**
246      * ArtifactRepository of the localRepository. To obtain the directory of localRepository in unit tests use
247      * System.getProperty("localRepository").
248      */
249     @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
250     protected ArtifactRepository localRepository;
251 
252     /**
253      * List of System properties to pass to the JUnit tests.
254      *
255      * @deprecated Use systemPropertyVariables instead.
256      */
257     @Parameter
258     protected Properties systemProperties;
259 
260     /**
261      * List of System properties to pass to the JUnit tests.
262      *
263      * @since 2.5
264      */
265     @Parameter
266     protected Map<String, String> systemPropertyVariables;
267 
268     /**
269      * List of System properties, loaded from a file, to pass to the JUnit tests.
270      *
271      * @since 2.8.2
272      */
273     @Parameter
274     protected File systemPropertiesFile;
275 
276     /**
277      * List of properties for configuring all TestNG related configurations. This is the new preferred method of
278      * configuring TestNG.
279      *
280      * @since 2.4
281      */
282     @Parameter
283     protected Properties properties;
284 
285     /**
286      * Map of plugin artifacts.
287      */
288     // olamy: would make more sense using defaultValue but doesn't work with maven 2.x
289     @Parameter( property = "plugin.artifactMap", required = true, readonly = true )
290     protected Map<String, Artifact> pluginArtifactMap;
291 
292     /**
293      * Map of project artifacts.
294      */
295     // olamy: would make more sense using defaultValue but doesn't work with maven 2.x
296     @Parameter( property = "project.artifactMap", readonly = true, required = true )
297     protected Map<String, Artifact> projectArtifactMap;
298 
299     /**
300      * Add custom text into report filename: TEST-testClassName-reportNameSuffix.xml,
301      * testClassName-reportNameSuffix.txt and testClassName-reportNameSuffix-output.txt.
302      * File TEST-testClassName-reportNameSuffix.xml has changed attributes 'testsuite'--'name'
303      * and 'testcase'--'classname' - reportNameSuffix is added to the attribute value.
304      */
305     @Parameter( property = "surefire.reportNameSuffix", defaultValue = "" )
306     protected String reportNameSuffix;
307 
308     /**
309      * Set this to "true" to redirect the unit test standard output to a file (found in
310      * reportsDirectory/testName-output.txt).
311      *
312      * @since 2.3
313      */
314     @Parameter( property = "maven.test.redirectTestOutputToFile", defaultValue = "false" )
315     protected boolean redirectTestOutputToFile;
316 
317     /**
318      * Set this to "true" to cause a failure if there are no tests to run. Defaults to "false".
319      *
320      * @since 2.4
321      */
322     @Parameter( property = "failIfNoTests" )
323     protected Boolean failIfNoTests;
324 
325     /**
326      * <strong>DEPRECATED</strong> since version 2.14. Use <code>forkCount</code> and <code>reuseForks</code> instead.
327      * <br/>
328      * <br/>
329      * Option to specify the forking mode. Can be "never", "once", "always", "perthread". "none" and "pertest" are also
330      * accepted for backwards compatibility. "always" forks for each test-class. "perthread" will create
331      * <code>threadCount</code> parallel forks, each executing one test-class. See also parameter
332      * <code>reuseForks</code>.<br/>
333      *
334      * @since 2.1
335      */
336     @Parameter( property = "forkMode", defaultValue = "once" )
337     protected String forkMode;
338 
339     /**
340      * Option to specify the jvm (or path to the java executable) to use with the forking options. For the default, the
341      * jvm will be a new instance of the same VM as the one used to run Maven. JVM settings are not inherited from
342      * MAVEN_OPTS.
343      *
344      * @since 2.1
345      */
346     @Parameter( property = "jvm" )
347     protected String jvm;
348 
349     /**
350      * Arbitrary JVM options to set on the command line.
351      * <br/>
352      * <br/>
353      * Using an alternate syntax for <em>argLine</em>, <pre>@{...}</pre> allows late replacement of properties when the
354      * plugin is executed, so properties that have been modified by other plugins will be picked up correctly.
355      * See the Frequently Asked Questions page with more details:<br/>
356      * <a href="http://maven.apache.org/surefire/maven-surefire-plugin/faq.html">
357      *     http://maven.apache.org/surefire/maven-surefire-plugin/faq.html</a>;
358      * <br/>
359      * <a href="http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html">
360      *     http://maven.apache.org/surefire/maven-failsafe-plugin/faq.html</a>;
361      *
362      * @since 2.1
363      */
364     @Parameter( property = "argLine" )
365     protected String argLine;
366 
367     /**
368      * Additional environment variables to set on the command line.
369      *
370      * @since 2.1.3
371      */
372     @Parameter
373     protected Map<String, String> environmentVariables = new HashMap<String, String>();
374 
375     /**
376      * Command line working directory.
377      *
378      * @since 2.1.3
379      */
380     @Parameter( property = "basedir" )
381     protected File workingDirectory;
382 
383     /**
384      * When false it makes tests run using the standard classloader delegation instead of the default Maven isolated
385      * classloader. Only used when forking (forkMode is not "none").<br/>
386      * Setting it to false helps with some problems caused by conflicts between xml parsers in the classpath and the
387      * Java 5 provider parser.
388      *
389      * @since 2.1
390      */
391     @Parameter( property = "childDelegation", defaultValue = "false" )
392     protected boolean childDelegation;
393 
394     /**
395      * (TestNG/JUnit47 provider with JUnit4.8+ only) Groups for this test. Only classes/methods/etc decorated with one
396      * of the groups specified here will be included in test run, if specified.<br/>
397      * For JUnit, this parameter forces the use of the 4.7 provider<br/>
398      * This parameter is ignored if the <code>suiteXmlFiles</code> parameter is specified.<br/>
399      * Since version 2.18.1 and JUnit 4.12, the <em>@Category<em> annotation type is automatically inherited from
400      * superclasses, see <em>@java.lang.annotation.Inherited</em>. Make sure that test class inheritance still makes
401      * sense together with <em>@Category<em> annotation of the JUnit 4.12 or higher appeared in superclass.
402      *
403      * @since 2.2
404      */
405     @Parameter( property = "groups" )
406     protected String groups;
407 
408     /**
409      * (TestNG/JUnit47 provider with JUnit4.8+ only) Excluded groups. Any methods/classes/etc with one of the groups
410      * specified in this list will specifically not be run.<br/>
411      * For JUnit, this parameter forces the use of the 4.7 provider<br/>
412      * This parameter is ignored if the <code>suiteXmlFiles</code> parameter is specified.<br/>
413      * Since version 2.18.1 and JUnit 4.12, the <em>@Category<em> annotation type is automatically inherited from
414      * superclasses, see <em>@java.lang.annotation.Inherited</em>. Make sure that test class inheritance still makes
415      * sense together with <em>@Category<em> annotation of the JUnit 4.12 or higher appeared in superclass.
416      *
417      * @since 2.2
418      */
419     @Parameter( property = "excludedGroups" )
420     protected String excludedGroups;
421 
422     /**
423      * Allows you to specify the name of the JUnit artifact. If not set, <code>junit:junit</code> will be used.
424      *
425      * @since 2.3.1
426      */
427     @Parameter( property = "junitArtifactName", defaultValue = "junit:junit" )
428     protected String junitArtifactName;
429 
430     /**
431      * Allows you to specify the name of the TestNG artifact. If not set, <code>org.testng:testng</code> will be used.
432      *
433      * @since 2.3.1
434      */
435     @Parameter( property = "testNGArtifactName", defaultValue = "org.testng:testng" )
436     protected String testNGArtifactName;
437 
438     /**
439      * (TestNG/JUnit 4.7 provider) The attribute thread-count allows you to specify how many threads should be
440      * allocated for this execution. Only makes sense to use in conjunction with the <code>parallel</code> parameter.
441      *
442      * @since 2.2
443      */
444     @Parameter( property = "threadCount" )
445     protected int threadCount;
446 
447     /**
448      * Option to specify the number of VMs to fork in parallel in order to execute the tests. When terminated with "C",
449      * the number part is multiplied with the number of CPU cores. Floating point value are only accepted together with
450      * "C". If set to "0", no VM is forked and all tests are executed within the main process.<br/>
451      * <br/>
452      * Example values: "1.5C", "4"<br/>
453      * <br/>
454      * The system properties and the <code>argLine</code> of the forked processes may contain the place holder string
455      * <code>${surefire.forkNumber}</code>, which is replaced with a fixed number for each of the parallel forks,
456      * ranging from <code>1</code> to the effective value of <code>forkCount</code> times the maximum number of parallel
457      * Surefire executions in maven parallel builds, i.e. the effective value of the <code>-T</code> command line
458      * argument of maven core.
459      *
460      * @since 2.14
461      */
462     @Parameter( property = "forkCount", defaultValue = "1" )
463     private String forkCount;
464 
465     /**
466      * Indicates if forked VMs can be reused. If set to "false", a new VM is forked for each test class to be executed.
467      * If set to "true", up to <code>forkCount</code> VMs will be forked and then reused to execute all tests.
468      *
469      * @since 2.13
470      */
471 
472     @Parameter( property = "reuseForks", defaultValue = "true" )
473     private boolean reuseForks;
474 
475     /**
476      * (JUnit 4.7 provider) Indicates that threadCount, threadCountSuites, threadCountClasses, threadCountMethods
477      * are per cpu core.
478      *
479      * @since 2.5
480      */
481     @Parameter( property = "perCoreThreadCount", defaultValue = "true" )
482     protected boolean perCoreThreadCount;
483 
484     /**
485      * (JUnit 4.7 provider) Indicates that the thread pool will be unlimited. The <code>parallel</code> parameter and
486      * the actual number of classes/methods will decide. Setting this to "true" effectively disables
487      * <code>perCoreThreadCount</code> and <code>threadCount</code>. Defaults to "false".
488      *
489      * @since 2.5
490      */
491     @Parameter( property = "useUnlimitedThreads", defaultValue = "false" )
492     protected boolean useUnlimitedThreads;
493 
494     /**
495      * (TestNG provider) When you use the <code>parallel</code> attribute, TestNG will try to run all your test methods
496      * in separate threads, except for methods that depend on each other, which will be run in the same thread in order
497      * to respect their order of execution.
498      * <p/>
499      * (JUnit 4.7 provider) Supports values "classes"/"methods"/"both" to run in separate threads, as controlled by
500      * <code>threadCount</code>.<br/>
501      * <br/>
502      * Since version 2.16 (JUnit 4.7 provider), the value "both" is <strong>DEPRECATED</strong>.
503      * Use <strong>"classesAndMethods"</strong> instead.<br/>
504      * <br/>
505      * Since version 2.16 (JUnit 4.7 provider), additional vales are available
506      * "suites"/"suitesAndClasses"/"suitesAndMethods"/"classesAndMethods"/"all".
507      *
508      * @since 2.2
509      */
510     @Parameter( property = "parallel" )
511     protected String parallel;
512 
513     /**
514      * (JUnit 4.7 / provider only) The thread counts do not exceed the number of parallel suite, class runners and
515      * average number of methods per class if set to <strong>true</strong>.
516      * <p/>
517      * True by default.
518      *
519      * @since 2.17
520      */
521     @Parameter( property = "parallelOptimized", defaultValue = "true" )
522     protected boolean parallelOptimized;
523 
524     /**
525      * (JUnit 4.7 provider) This attribute allows you to specify the concurrency in test suites, i.e.:
526      * <ul>
527      *  <li>number of concurrent suites if <code>threadCount</code> is 0 or unspecified</li>
528      *  <li>limited suites concurrency if <code>useUnlimitedThreads</code> is set to <strong>true</strong></li>
529      *  <li>if <code>threadCount</code> and certain thread-count parameters are &gt; 0 for <code>parallel</code>, the
530      *  concurrency is computed from ratio. For instance parallel=all and the ratio between
531      *      <em>threadCountSuites</em>:<code>threadCountClasses</code>:<code>threadCountMethods</code> is
532      *      <em>2</em>:3:5, there is 20% of <code>threadCount</code> in concurrent suites.</li>
533      * </ul>
534      *
535      * Only makes sense to use in conjunction with the <code>parallel</code> parameter.
536      * The default value <code>0</code> behaves same as unspecified one.
537      *
538      * @since 2.16
539      */
540     @Parameter( property = "threadCountSuites", defaultValue = "0" )
541     protected int threadCountSuites;
542 
543     /**
544      * (JUnit 4.7 provider) This attribute allows you to specify the concurrency in test classes, i.e.:
545      * <ul>
546      *  <li>number of concurrent classes if <code>threadCount</code> is 0 or unspecified</li>
547      *  <li>limited classes concurrency if <code>useUnlimitedThreads</code> is set to <strong>true</strong></li>
548      *  <li>if <code>threadCount</code> and certain thread-count parameters are &gt; 0 for <code>parallel</code>, the
549      *  concurrency is computed from ratio. For instance parallel=all and the ratio between
550      *      <code>threadCountSuites</code>:<em>threadCountClasses</em>:<code>threadCountMethods</code> is
551      *      2:<em>3</em>:5, there is 30% of <code>threadCount</code> in concurrent classes.</li>
552      *  <li>as in the previous case but without this leaf thread-count. Example: parallel=suitesAndClasses,
553      *  threadCount=16, threadCountSuites=5, threadCountClasses is unspecified leaf, the number of concurrent classes
554      *  is varying from &gt;= 11 to 14 or 15. The threadCountSuites become number of threads.
555      *  </li>
556      * </ul>
557      *
558      * Only makes sense to use in conjunction with the <code>parallel</code> parameter.
559      * The default value <code>0</code> behaves same as unspecified one.
560      *
561      * @since 2.16
562      */
563     @Parameter( property = "threadCountClasses", defaultValue = "0" )
564     protected int threadCountClasses;
565 
566     /**
567      * (JUnit 4.7 provider) This attribute allows you to specify the concurrency in test methods, i.e.:
568      * <ul>
569      * <li>number of concurrent methods if <code>threadCount</code> is 0 or unspecified</li>
570      * <li>limited concurrency of methods if <code>useUnlimitedThreads</code> is set to <strong>true</strong></li>
571      * <li>if <code>threadCount</code> and certain thread-count parameters are &gt; 0 for <code>parallel</code>, the
572      * concurrency is computed from ratio. For instance parallel=all and the ratio between
573      * <code>threadCountSuites</code>:<code>threadCountClasses</code>:<em>threadCountMethods</em> is 2:3:<em>5</em>,
574      * there is 50% of <code>threadCount</code> in concurrent methods.</li>
575      * <li>as in the previous case but without this leaf thread-count. Example: parallel=all, threadCount=16,
576      * threadCountSuites=2, threadCountClasses=3, but threadCountMethods is unspecified leaf, the number of concurrent
577      * methods is varying from &gt;= 11 to 14 or 15. The threadCountSuites and threadCountClasses become number of
578      * threads.</li>
579      * </ul>
580      * Only makes sense to use in conjunction with the <code>parallel</code> parameter. The default value <code>0</code>
581      * behaves same as unspecified one.
582      *
583      * @since 2.16
584      */
585     @Parameter( property = "threadCountMethods", defaultValue = "0" )
586     protected int threadCountMethods;
587 
588     /**
589      * Whether to trim the stack trace in the reports to just the lines within the test, or show the full trace.
590      *
591      * @since 2.2
592      */
593     @Parameter( property = "trimStackTrace", defaultValue = "true" )
594     protected boolean trimStackTrace;
595 
596     /**
597      * Resolves the artifacts needed.
598      */
599     @Component
600     protected ArtifactResolver artifactResolver;
601 
602     /**
603      * Creates the artifact.
604      */
605     @Component
606     protected ArtifactFactory artifactFactory;
607 
608     /**
609      * The remote plugin repositories declared in the POM.
610      *
611      * @since 2.2
612      */
613     @Parameter( defaultValue = "${project.pluginArtifactRepositories}" )
614     protected List<ArtifactRepository> remoteRepositories;
615 
616     /**
617      * For retrieval of artifact's metadata.
618      */
619     @Component
620     protected ArtifactMetadataSource metadataSource;
621 
622     /**
623      * Flag to disable the generation of report files in xml format.
624      *
625      * @since 2.2
626      */
627     @Parameter( property = "disableXmlReport", defaultValue = "false" )
628     protected boolean disableXmlReport;
629 
630     /**
631      * By default, Surefire enables JVM assertions for the execution of your test cases. To disable the assertions, set
632      * this flag to "false".
633      *
634      * @since 2.3.1
635      */
636     @Parameter( property = "enableAssertions", defaultValue = "true" )
637     protected boolean enableAssertions;
638 
639     /**
640      * The current build session instance.
641      */
642     @Component
643     protected MavenSession session;
644 
645     /**
646      * (TestNG only) Define the factory class used to create all test instances.
647      *
648      * @since 2.5
649      */
650     @Parameter( property = "objectFactory" )
651     protected String objectFactory;
652 
653     /**
654      *
655      */
656     @Parameter( defaultValue = "${session.parallel}", readonly = true )
657     protected Boolean parallelMavenExecution;
658 
659     /**
660      * List of dependencies to scan for test classes to include in the test run.
661      * The child elements of this element must be &lt;dependency&gt; elements, and the
662      * contents of each of these elements must be a string which follows the format:
663      *
664      * <i>groupId:artifactId</i>. For example: <i>org.acme:project-a</i>.
665      *
666      * @since 2.15
667      */
668     @Parameter( property = "dependenciesToScan" )
669     private String[] dependenciesToScan;
670 
671     /**
672      *
673      */
674     @Component
675     protected ToolchainManager toolchainManager;
676 
677     private Artifact surefireBooterArtifact;
678 
679     private Toolchain toolchain;
680 
681     private int effectiveForkCount = -1;
682 
683     /**
684      * The placeholder that is replaced by the executing thread's running number. The thread number
685      * range starts with 1
686      * Deprecated.
687      */
688     public static final String THREAD_NUMBER_PLACEHOLDER = "${surefire.threadNumber}";
689 
690     /**
691      * The placeholder that is replaced by the executing fork's running number. The fork number
692      * range starts with 1
693      */
694     public static final String FORK_NUMBER_PLACEHOLDER = "${surefire.forkNumber}";
695 
696     protected abstract String getPluginName();
697 
698     protected abstract int getRerunFailingTestsCount();
699 
700     private SurefireDependencyResolver dependencyResolver;
701 
702     public void execute()
703         throws MojoExecutionException, MojoFailureException
704     {
705         // Stuff that should have been final
706         setupStuff();
707 
708         if ( verifyParameters() && !hasExecutedBefore() )
709         {
710             DefaultScanResult scan = scanForTestClasses();
711             if ( !isValidSuiteXmlFileConfig() && scan.isEmpty() )
712             {
713                 if ( getEffectiveFailIfNoTests() )
714                 {
715                     throw new MojoFailureException(
716                         "No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)" );
717                 }
718                 handleSummary( RunResult.noTestsRun(), null );
719                 return;
720             }
721             logReportsDirectory();
722             executeAfterPreconditionsChecked( scan );
723         }
724     }
725 
726     private void setupStuff()
727     {
728         createDependencyResolver();
729         surefireBooterArtifact = getSurefireBooterArtifact();
730         toolchain = getToolchain();
731     }
732 
733     private DefaultScanResult scanForTestClasses()
734     {
735         DefaultScanResult scan = scanDirectories();
736         DefaultScanResult scanDeps = scanDependencies();
737         return scan.append( scanDeps );
738     }
739 
740     private DefaultScanResult scanDirectories()
741     {
742         return new DirectoryScanner( getTestClassesDirectory(), getIncludeList(), getExcludeList(),
743                                      getSpecificTests() ).scan();
744     }
745 
746     private DefaultScanResult scanDependencies()
747     {
748         if ( getDependenciesToScan() == null )
749         {
750             return null;
751         }
752         else
753         {
754             try
755             {
756                 // noinspection unchecked
757                 return new DependencyScanner( DependencyScanner.filter( project.getTestArtifacts(),
758                                                                         Arrays.asList( getDependenciesToScan() ) ),
759                                               getIncludeList(), getExcludeList(), getSpecificTests() ).scan();
760             }
761             catch ( Exception e )
762             {
763                 throw new RuntimeException( e );
764             }
765         }
766     }
767 
768     boolean verifyParameters()
769         throws MojoFailureException, MojoExecutionException
770     {
771         setProperties( new SurefireProperties( getProperties() ) );
772         if ( isSkipExecution() )
773         {
774             getLog().info( "Tests are skipped." );
775             return false;
776         }
777 
778         String jvmToUse = getJvm();
779         if ( toolchain != null )
780         {
781             getLog().info( "Toolchain in maven-" + getPluginName() + "-plugin: " + toolchain );
782             if ( jvmToUse != null )
783             {
784                 getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + jvmToUse );
785             }
786         }
787 
788         if ( !getTestClassesDirectory().exists()
789             && ( getDependenciesToScan() == null || getDependenciesToScan().length == 0 ) )
790         {
791             if ( Boolean.TRUE.equals( getFailIfNoTests() ) )
792             {
793                 throw new MojoFailureException( "No tests to run!" );
794             }
795             getLog().info( "No tests to run." );
796         }
797         else
798         {
799             convertDeprecatedForkMode();
800             ensureWorkingDirectoryExists();
801             ensureParallelRunningCompatibility();
802             ensureThreadCountWithPerThread();
803             warnIfUselessUseSystemClassLoaderParameter();
804             warnIfDefunctGroupsCombinations();
805         }
806         return true;
807     }
808 
809     protected abstract boolean isSkipExecution();
810 
811     protected void executeAfterPreconditionsChecked( DefaultScanResult scanResult )
812         throws MojoExecutionException, MojoFailureException
813     {
814 
815         List<ProviderInfo> providers = createProviders();
816 
817         RunResult current = RunResult.noTestsRun();
818 
819         Exception firstForkException = null;
820         for ( ProviderInfo provider : providers )
821         {
822             try
823             {
824                 current = current.aggregate( executeProvider( provider, scanResult ) );
825             }
826             catch ( SurefireBooterForkException e )
827             {
828                 if ( firstForkException == null )
829                 {
830                     firstForkException = e;
831                 }
832             }
833             catch ( SurefireExecutionException e )
834             {
835                 if ( firstForkException == null )
836                 {
837                     firstForkException = e;
838                 }
839             }
840             catch ( TestSetFailedException e )
841             {
842                 if ( firstForkException == null )
843                 {
844                     firstForkException = e;
845                 }
846             }
847         }
848 
849         if ( firstForkException != null )
850         {
851             current = RunResult.failure( current, firstForkException );
852         }
853 
854         handleSummary( current, firstForkException );
855     }
856 
857 
858     private void createDependencyResolver()
859     {
860         dependencyResolver =
861             new SurefireDependencyResolver( getArtifactResolver(), getArtifactFactory(), getLog(), getLocalRepository(),
862                                             getRemoteRepositories(), getMetadataSource(), getPluginName() );
863     }
864 
865     protected List<ProviderInfo> createProviders()
866         throws MojoFailureException, MojoExecutionException
867     {
868         final Artifact junitDepArtifact = getJunitDepArtifact();
869         ProviderList wellKnownProviders =
870             new ProviderList( new DynamicProviderInfo( null ), new TestNgProviderInfo( getTestNgArtifact() ),
871                               new JUnitCoreProviderInfo( getJunitArtifact(), junitDepArtifact ),
872                               new JUnit4ProviderInfo( getJunitArtifact(), junitDepArtifact ),
873                               new JUnit3ProviderInfo() );
874 
875         return wellKnownProviders.resolve( getLog() );
876     }
877 
878     private SurefireProperties setupProperties()
879     {
880         SurefireProperties sysProps = null;
881         try
882         {
883             sysProps = SurefireProperties.loadProperties( systemPropertiesFile );
884         }
885         catch ( IOException e )
886         {
887             String msg = "The system property file '" + systemPropertiesFile.getAbsolutePath() + "' can't be read.";
888             if ( getLog().isDebugEnabled() )
889             {
890                 getLog().warn( msg, e );
891             }
892             else
893             {
894                 getLog().warn( msg );
895             }
896         }
897 
898         SurefireProperties result =
899             SurefireProperties.calculateEffectiveProperties( getSystemProperties(), getSystemPropertyVariables(),
900                                                              getUserProperties(), sysProps );
901 
902         result.setProperty( "basedir", getBasedir().getAbsolutePath() );
903         result.setProperty( "user.dir", getWorkingDirectory().getAbsolutePath() );
904         result.setProperty( "localRepository", getLocalRepository().getBasedir() );
905         if ( isForking() )
906         {
907             for ( Object o : result.propertiesThatCannotBeSetASystemProperties() )
908             {
909                 if ( getArgLine() == null || !getArgLine().contains( "-D" + o + "=" ) )
910                 {
911                     getLog().warn( o + " cannot be set as system property, use <argLine>-D"
912                                        + o + "=...<argLine> instead" );
913                 }
914             }
915             for ( Object systemPropertyMatchingArgLine : systemPropertiesMatchingArgLine( result ) )
916             {
917                 getLog().warn( "The system property " + systemPropertyMatchingArgLine + " is configured twice! "
918                                    + "The property appears in <argLine/> and any of <systemPropertyVariables/>, "
919                                    + "<systemProperties/> or user property." );
920             }
921         }
922         if ( getLog().isDebugEnabled() )
923         {
924             showToLog( result, getLog(), "system property" );
925         }
926         return result;
927     }
928 
929     private Set<Object> systemPropertiesMatchingArgLine( SurefireProperties result )
930     {
931         Set<Object> intersection = new HashSet<Object>();
932         if ( StringUtils.isNotBlank( getArgLine() ) )
933         {
934             for ( Object systemProperty : result.getStringKeySet() )
935             {
936                 if ( getArgLine().contains( "-D" + systemProperty + "=" ) )
937                 {
938                     intersection.add( systemProperty );
939                 }
940             }
941 
942             Set<Object> ignored = result.propertiesThatCannotBeSetASystemProperties();
943             intersection.removeAll( ignored );
944         }
945         return intersection;
946     }
947 
948     public void showToLog( SurefireProperties props, org.apache.maven.plugin.logging.Log log, String setting )
949     {
950         for ( Object key : props.getStringKeySet() )
951         {
952             String value = props.getProperty( (String) key );
953             log.debug( "Setting " + setting + " [" + key + "]=[" + value + "]" );
954         }
955     }
956 
957 
958     private RunResult executeProvider( ProviderInfo provider, DefaultScanResult scanResult )
959         throws MojoExecutionException, MojoFailureException, SurefireExecutionException, SurefireBooterForkException,
960         TestSetFailedException
961     {
962         SurefireProperties effectiveProperties = setupProperties();
963         ClassLoaderConfiguration classLoaderConfiguration = getClassLoaderConfiguration( isForking() );
964         provider.addProviderProperties();
965         RunOrderParameters runOrderParameters =
966             new RunOrderParameters( getRunOrder(), getStatisticsFileName( getConfigChecksum() ) );
967 
968         if ( isNotForking() )
969         {
970             createCopyAndReplaceForkNumPlaceholder( effectiveProperties, 1 ).copyToSystemProperties();
971 
972             InPluginVMSurefireStarter surefireStarter =
973                 createInprocessStarter( provider, classLoaderConfiguration, runOrderParameters );
974             return surefireStarter.runSuitesInProcess( scanResult );
975         }
976         else
977         {
978             ForkConfiguration forkConfiguration = getForkConfiguration();
979             if ( getLog().isDebugEnabled() )
980             {
981                 showMap( getEnvironmentVariables(), "environment variable" );
982             }
983 
984             Properties originalSystemProperties = (Properties) System.getProperties().clone();
985             try
986             {
987                 ForkStarter forkStarter =
988                     createForkStarter( provider, forkConfiguration, classLoaderConfiguration, runOrderParameters,
989                                        getLog() );
990                 return forkStarter.run( effectiveProperties, scanResult );
991             }
992             finally
993             {
994                 System.setProperties( originalSystemProperties );
995                 cleanupForkConfiguration( forkConfiguration );
996             }
997         }
998     }
999 
1000 
1001     public static SurefireProperties createCopyAndReplaceForkNumPlaceholder(
1002         SurefireProperties effectiveSystemProperties, int threadNumber )
1003     {
1004         SurefireProperties filteredProperties = new SurefireProperties( ( KeyValueSource) effectiveSystemProperties );
1005         String threadNumberString = String.valueOf( threadNumber );
1006         for ( Entry<Object, Object> entry : effectiveSystemProperties.entrySet() )
1007         {
1008             if ( entry.getValue() instanceof String )
1009             {
1010                 String value = (String) entry.getValue();
1011                 value = value.replace( THREAD_NUMBER_PLACEHOLDER, threadNumberString );
1012                 value = value.replace( FORK_NUMBER_PLACEHOLDER, threadNumberString );
1013 
1014                 filteredProperties.put( entry.getKey(), value );
1015             }
1016         }
1017         return filteredProperties;
1018     }
1019 
1020     protected void cleanupForkConfiguration( ForkConfiguration forkConfiguration )
1021     {
1022         if ( !getLog().isDebugEnabled() && forkConfiguration != null )
1023         {
1024             File tempDirectory = forkConfiguration.getTempDirectory();
1025             try
1026             {
1027                 FileUtils.deleteDirectory( tempDirectory );
1028             }
1029             catch ( IOException ioe )
1030             {
1031                 getLog().warn( "Could not delete temp direcotry " + tempDirectory + " because " + ioe.getMessage() );
1032             }
1033         }
1034     }
1035 
1036     protected abstract void handleSummary( RunResult summary, Exception firstForkException )
1037         throws MojoExecutionException, MojoFailureException;
1038 
1039     protected void logReportsDirectory()
1040     {
1041         getLog().info(
1042             StringUtils.capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
1043     }
1044 
1045 
1046     final Toolchain getToolchain()
1047     {
1048         Toolchain tc = null;
1049 
1050         if ( getToolchainManager() != null )
1051         {
1052             tc = getToolchainManager().getToolchainFromBuildContext( "jdk", getSession() );
1053         }
1054 
1055         return tc;
1056     }
1057 
1058     /**
1059      * Converts old TestNG configuration parameters over to new properties based configuration
1060      * method. (if any are defined the old way)
1061      */
1062     private void convertTestNGParameters() throws MojoExecutionException
1063     {
1064         if ( this.getParallel() != null )
1065         {
1066             getProperties().setProperty( ProviderParameterNames.PARALLEL_PROP, this.getParallel() );
1067         }
1068         convertGroupParameters();
1069 
1070         if ( this.getThreadCount() > 0 )
1071         {
1072             getProperties().setProperty( ProviderParameterNames.THREADCOUNT_PROP,
1073                                          Integer.toString( this.getThreadCount() ) );
1074         }
1075         if ( this.getObjectFactory() != null )
1076         {
1077             getProperties().setProperty( "objectfactory", this.getObjectFactory() );
1078         }
1079         if ( this.getTestClassesDirectory() != null )
1080         {
1081             getProperties().setProperty( "testng.test.classpath", getTestClassesDirectory().getAbsolutePath() );
1082         }
1083 
1084         Artifact testNgArtifact = getTestNgArtifact();
1085         if ( testNgArtifact != null )
1086         {
1087             DefaultArtifactVersion defaultArtifactVersion = new DefaultArtifactVersion( testNgArtifact.getVersion() );
1088             getProperties().setProperty( "testng.configurator", getConfiguratorName( defaultArtifactVersion ) );
1089         }
1090 
1091 
1092     }
1093 
1094     private static String getConfiguratorName( ArtifactVersion version )
1095         throws MojoExecutionException
1096     {
1097         try
1098         {
1099             VersionRange range = VersionRange.createFromVersionSpec( "[4.7,5.1]" );
1100             if ( range.containsVersion( version ) )
1101             {
1102                 return "org.apache.maven.surefire.testng.conf.TestNG4751Configurator";
1103             }
1104             range = VersionRange.createFromVersionSpec( "[5.2]" );
1105             if ( range.containsVersion( version ) )
1106             {
1107                 return "org.apache.maven.surefire.testng.conf.TestNG52Configurator";
1108             }
1109             range = VersionRange.createFromVersionSpec( "[5.3,6.4]" );
1110             if ( range.containsVersion( version ) )
1111             {
1112                 return "org.apache.maven.surefire.testng.conf.TestNGMapConfigurator";
1113             }
1114             range = VersionRange.createFromVersionSpec( "[6.5,)" );
1115             if ( range.containsVersion( version ) )
1116             {
1117                 return "org.apache.maven.surefire.testng.conf.TestNG652Configurator";
1118             }
1119 
1120             throw new MojoExecutionException( "Unknown TestNG version " + version );
1121         }
1122         catch ( InvalidVersionSpecificationException invsex )
1123         {
1124             throw new MojoExecutionException( "Bug in plugin. Please report it with the attached stacktrace", invsex );
1125         }
1126     }
1127 
1128 
1129     private void convertGroupParameters()
1130     {
1131         if ( this.getExcludedGroups() != null )
1132         {
1133             getProperties().setProperty( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP, this.getExcludedGroups() );
1134         }
1135         if ( this.getGroups() != null )
1136         {
1137             getProperties().setProperty( ProviderParameterNames.TESTNG_GROUPS_PROP, this.getGroups() );
1138         }
1139     }
1140 
1141     protected boolean isAnyConcurrencySelected()
1142     {
1143         return this.getParallel() != null && this.getParallel().trim().length() > 0;
1144     }
1145 
1146     protected boolean isAnyGroupsSelected()
1147     {
1148         return this.getGroups() != null || this.getExcludedGroups() != null;
1149     }
1150 
1151     /**
1152      * Converts old JUnit configuration parameters over to new properties based configuration
1153      * method. (if any are defined the old way)
1154      */
1155     private void convertJunitCoreParameters() throws MojoExecutionException
1156     {
1157         checkThreadCountEntity( getThreadCountSuites(), "suites" );
1158         checkThreadCountEntity( getThreadCountClasses(), "classes" );
1159         checkThreadCountEntity( getThreadCountMethods(), "methods" );
1160 
1161         String usedParallel = ( getParallel() != null ) ? getParallel() : "none";
1162 
1163         if ( !"none".equals( usedParallel ) )
1164         {
1165             checkNonForkedThreads( parallel );
1166         }
1167 
1168         String usedThreadCount = Integer.toString( getThreadCount() );
1169         getProperties().setProperty( ProviderParameterNames.PARALLEL_PROP, usedParallel );
1170         getProperties().setProperty( ProviderParameterNames.THREADCOUNT_PROP, usedThreadCount );
1171         getProperties().setProperty( "perCoreThreadCount", Boolean.toString( getPerCoreThreadCount() ) );
1172         getProperties().setProperty( "useUnlimitedThreads", Boolean.toString( getUseUnlimitedThreads() ) );
1173         getProperties().setProperty( ProviderParameterNames.THREADCOUNTSUITES_PROP,
1174                                      Integer.toString( getThreadCountSuites() ) );
1175         getProperties().setProperty( ProviderParameterNames.THREADCOUNTCLASSES_PROP,
1176                                      Integer.toString( getThreadCountClasses() ) );
1177         getProperties().setProperty( ProviderParameterNames.THREADCOUNTMETHODS_PROP,
1178                                      Integer.toString( getThreadCountMethods() ) );
1179         getProperties().setProperty( ProviderParameterNames.PARALLEL_TIMEOUT_PROP,
1180                 Double.toString( getParallelTestsTimeoutInSeconds() ) );
1181         getProperties().setProperty( ProviderParameterNames.PARALLEL_TIMEOUTFORCED_PROP,
1182                 Double.toString( getParallelTestsTimeoutForcedInSeconds() ) );
1183         getProperties().setProperty( ProviderParameterNames.PARALLEL_OPTIMIZE_PROP,
1184                                      Boolean.toString( isParallelOptimized() ) );
1185 
1186         String message =
1187             "parallel='" + usedParallel + '\'' + ", perCoreThreadCount=" + getPerCoreThreadCount() + ", threadCount="
1188                 + usedThreadCount + ", useUnlimitedThreads=" + getUseUnlimitedThreads()
1189                 + ", threadCountSuites=" + getThreadCountSuites()
1190                 + ", threadCountClasses=" + getThreadCountClasses()
1191                 + ", threadCountMethods=" + getThreadCountMethods()
1192                 + ", parallelOptimized=" + isParallelOptimized();
1193 
1194         getLog().info( message );
1195     }
1196 
1197     private void checkNonForkedThreads( String parallel ) throws MojoExecutionException
1198     {
1199         if ( "suites".equals( parallel ) )
1200         {
1201             if ( !( getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountSuites() > 0 ) )
1202             {
1203                 throw new MojoExecutionException(
1204                         "Use threadCount or threadCountSuites > 0 or useUnlimitedThreads=true for parallel='suites'" );
1205             }
1206             setThreadCountClasses( 0 );
1207             setThreadCountMethods( 0 );
1208         }
1209         else if ( "classes".equals( parallel ) )
1210         {
1211             if ( !( getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountClasses() > 0 ) )
1212             {
1213                 throw new MojoExecutionException(
1214                         "Use threadCount or threadCountClasses > 0 or useUnlimitedThreads=true for parallel='classes'"
1215                       );
1216             }
1217             setThreadCountSuites( 0 );
1218             setThreadCountMethods( 0 );
1219         }
1220         else if ( "methods".equals( parallel ) )
1221         {
1222             if ( !( getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountMethods() > 0 ) )
1223             {
1224                 throw new MojoExecutionException(
1225                         "Use threadCount or threadCountMethods > 0 or useUnlimitedThreads=true for parallel='methods'"
1226                       );
1227             }
1228             setThreadCountSuites( 0 );
1229             setThreadCountClasses( 0 );
1230         }
1231         else if ( "suitesAndClasses".equals( parallel ) )
1232         {
1233             if ( !( getUseUnlimitedThreads()
1234                     || onlyThreadCount()
1235                     || getThreadCountSuites() > 0 && getThreadCountClasses() > 0
1236                         && getThreadCount() == 0 && getThreadCountMethods() == 0
1237                     || getThreadCount() > 0 && getThreadCountSuites() > 0 && getThreadCountClasses() > 0
1238                         && getThreadCountMethods() == 0
1239                     || getThreadCount() > 0 && getThreadCountSuites() > 0 && getThreadCount() > getThreadCountSuites()
1240                         && getThreadCountClasses() == 0 && getThreadCountMethods() == 0 ) )
1241             {
1242                 throw new MojoExecutionException( "Use useUnlimitedThreads=true, "
1243                         + "or only threadCount > 0, "
1244                         + "or (threadCountSuites > 0 and threadCountClasses > 0), "
1245                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0) "
1246                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) "
1247                         + "for parallel='suitesAndClasses' or 'both'" );
1248             }
1249             setThreadCountMethods( 0 );
1250         }
1251         else if ( "suitesAndMethods".equals( parallel ) )
1252         {
1253             if ( !( getUseUnlimitedThreads()
1254                     || onlyThreadCount()
1255                     || getThreadCountSuites() > 0 && getThreadCountMethods() > 0
1256                         && getThreadCount() == 0 && getThreadCountClasses() == 0
1257                     || getThreadCount() > 0 && getThreadCountSuites() > 0 && getThreadCountMethods() > 0
1258                         && getThreadCountClasses() == 0
1259                     || getThreadCount() > 0 && getThreadCountSuites() > 0 && getThreadCount() > getThreadCountSuites()
1260                         && getThreadCountClasses() == 0 && getThreadCountMethods() == 0 ) )
1261             {
1262                 throw new MojoExecutionException( "Use useUnlimitedThreads=true, "
1263                         + "or only threadCount > 0, "
1264                         + "or (threadCountSuites > 0 and threadCountMethods > 0), "
1265                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountMethods > 0), "
1266                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) "
1267                         + "for parallel='suitesAndMethods'" );
1268             }
1269             setThreadCountClasses( 0 );
1270         }
1271         else if ( "both".equals( parallel ) || "classesAndMethods".equals( parallel ) )
1272         {
1273             if ( !( getUseUnlimitedThreads()
1274                     || onlyThreadCount()
1275                     || getThreadCountClasses() > 0 && getThreadCountMethods() > 0
1276                         && getThreadCount() == 0 && getThreadCountSuites() == 0
1277                     || getThreadCount() > 0 && getThreadCountClasses() > 0 && getThreadCountMethods() > 0
1278                         && getThreadCountSuites() == 0
1279                     || getThreadCount() > 0 && getThreadCountClasses() > 0 && getThreadCount() > getThreadCountClasses()
1280                         && getThreadCountSuites() == 0 && getThreadCountMethods() == 0 ) )
1281             {
1282                 throw new MojoExecutionException( "Use useUnlimitedThreads=true, "
1283                         + "or only threadCount > 0, "
1284                         + "or (threadCountClasses > 0 and threadCountMethods > 0), "
1285                         + "or (threadCount > 0 and threadCountClasses > 0 and threadCountMethods > 0), "
1286                         + "or (threadCount > 0 and threadCountClasses > 0 and threadCount > threadCountClasses) "
1287                         + "for parallel='both' or parallel='classesAndMethods'" );
1288             }
1289             setThreadCountSuites( 0 );
1290         }
1291         else if ( "all".equals( parallel ) )
1292         {
1293             if ( !( getUseUnlimitedThreads()
1294                     || onlyThreadCount()
1295                     || getThreadCountSuites() > 0 && getThreadCountClasses() > 0 && getThreadCountMethods() > 0
1296                     || getThreadCount() > 0 && getThreadCountSuites() > 0 && getThreadCountClasses() > 0
1297                         && getThreadCountMethods() == 0
1298                         && getThreadCount() > ( getThreadCountSuites() + getThreadCountClasses() ) ) )
1299             {
1300                 throw new MojoExecutionException( "Use useUnlimitedThreads=true, "
1301                         + "or only threadCount > 0, "
1302                         + "or (threadCountSuites > 0 and threadCountClasses > 0 and threadCountMethods > 0), "
1303                         + "or every thread-count is specified, "
1304                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0 "
1305                         + "and threadCount > threadCountSuites + threadCountClasses) "
1306                         + "for parallel='all'" );
1307             }
1308         }
1309         else
1310         {
1311             throw new MojoExecutionException( "Illegal parallel='" + parallel + "'" );
1312         }
1313     }
1314 
1315     private boolean onlyThreadCount()
1316     {
1317         return getThreadCount() > 0 && getThreadCountSuites() == 0 && getThreadCountClasses() == 0
1318                 && getThreadCountMethods() == 0;
1319     }
1320 
1321     private static void checkThreadCountEntity( int count, String entity )
1322         throws MojoExecutionException
1323     {
1324         if ( count < 0 )
1325         {
1326             throw new MojoExecutionException(
1327                     "parallel maven execution does not allow negative thread-count" + entity );
1328         }
1329     }
1330 
1331     private boolean isJunit47Compatible( Artifact artifact )
1332     {
1333         return dependencyResolver.isWithinVersionSpec( artifact, "[4.7,)" );
1334     }
1335 
1336     private boolean isAnyJunit4( Artifact artifact )
1337     {
1338         return dependencyResolver.isWithinVersionSpec( artifact, "[4.0,)" );
1339     }
1340 
1341     static boolean isForkModeNever( String forkMode )
1342     {
1343         return ForkConfiguration.FORK_NEVER.equals( forkMode );
1344     }
1345 
1346     boolean isForking()
1347     {
1348         return 0 < getEffectiveForkCount();
1349     }
1350 
1351     String getEffectiveForkMode()
1352     {
1353         String forkMode1 = getForkMode();
1354 
1355         if ( toolchain != null && isForkModeNever( forkMode1 ) )
1356         {
1357             return ForkConfiguration.FORK_ONCE;
1358         }
1359 
1360         return ForkConfiguration.getEffectiveForkMode( forkMode1 );
1361     }
1362 
1363     private List<RunOrder> getRunOrders()
1364     {
1365         String runOrderString = getRunOrder();
1366         RunOrder[] runOrder = runOrderString == null ? RunOrder.DEFAULT : RunOrder.valueOfMulti( runOrderString );
1367         return Arrays.asList( runOrder );
1368     }
1369 
1370     private boolean requiresRunHistory()
1371     {
1372         final List<RunOrder> runOrders = getRunOrders();
1373         return runOrders.contains( RunOrder.BALANCED ) || runOrders.contains( RunOrder.FAILEDFIRST );
1374     }
1375 
1376     private boolean getEffectiveFailIfNoTests()
1377     {
1378         if ( isSpecificTestSpecified() )
1379         {
1380             if ( getFailIfNoSpecifiedTests() != null )
1381             {
1382                 return getFailIfNoSpecifiedTests();
1383             }
1384             else if ( getFailIfNoTests() != null )
1385             {
1386                 return getFailIfNoTests();
1387             }
1388             else
1389             {
1390                 return true;
1391             }
1392         }
1393         else
1394         {
1395             return getFailIfNoTests() != null && getFailIfNoTests();
1396         }
1397     }
1398 
1399     private ProviderConfiguration createProviderConfiguration( RunOrderParameters runOrderParameters )
1400         throws MojoExecutionException, MojoFailureException
1401     {
1402         ReporterConfiguration reporterConfiguration =
1403             new ReporterConfiguration( getReportsDirectory(), isTrimStackTrace() );
1404 
1405         Artifact testNgArtifact;
1406         testNgArtifact = getTestNgArtifact();
1407 
1408         DirectoryScannerParameters directoryScannerParameters = null;
1409         final boolean isTestNg = testNgArtifact != null;
1410         TestArtifactInfo testNg =
1411             isTestNg ? new TestArtifactInfo( testNgArtifact.getVersion(), testNgArtifact.getClassifier() ) : null;
1412         List<File> testXml = getSuiteXmlFiles() != null ? Arrays.asList( getSuiteXmlFiles() ) : null;
1413         TestRequest testSuiteDefinition =
1414             new TestRequest( testXml, getTestSourceDirectory(), getTest(), getTestMethod(),
1415                              getRerunFailingTestsCount() );
1416 
1417         final boolean actualFailIfNoTests;
1418 
1419         if ( isValidSuiteXmlFileConfig() && getTest() == null )
1420         {
1421             actualFailIfNoTests = getFailIfNoTests() != null && getFailIfNoTests();
1422             if ( !isTestNg )
1423             {
1424                 throw new MojoExecutionException( "suiteXmlFiles is configured, but there is no TestNG dependency" );
1425             }
1426         }
1427         else
1428         {
1429             if ( isSpecificTestSpecified() )
1430             {
1431                 actualFailIfNoTests = getEffectiveFailIfNoTests();
1432                 setFailIfNoTests( actualFailIfNoTests );
1433             }
1434             else
1435             {
1436                 actualFailIfNoTests = getFailIfNoTests() != null && getFailIfNoTests();
1437             }
1438 
1439             List<String> actualIncludes = getIncludeList();
1440             List<String> actualExcludes = getExcludeList();
1441             List<String> specificTests = getSpecificTests();
1442             directoryScannerParameters =
1443                 new DirectoryScannerParameters( getTestClassesDirectory(), actualIncludes, actualExcludes,
1444                                                 specificTests, actualFailIfNoTests, getRunOrder() );
1445         }
1446 
1447         Properties providerProperties = getProperties();
1448 
1449         return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, actualFailIfNoTests,
1450                                           reporterConfiguration, testNg, testSuiteDefinition, providerProperties, null,
1451                                           false );
1452     }
1453 
1454     public String getStatisticsFileName( String configurationHash )
1455     {
1456         return getReportsDirectory().getParentFile().getParentFile() + File.separator + ".surefire-"
1457             + configurationHash;
1458     }
1459 
1460 
1461     StartupConfiguration createStartupConfiguration( ProviderInfo provider,
1462                                                      ClassLoaderConfiguration classLoaderConfiguration )
1463         throws MojoExecutionException, MojoFailureException
1464     {
1465 
1466         try
1467         {
1468             // cache the provider lookup
1469             String providerName = provider.getProviderName();
1470             Classpath providerClasspath = ClasspathCache.getCachedClassPath( providerName );
1471             if ( providerClasspath == null )
1472             {
1473                 providerClasspath = provider.getProviderClasspath();
1474                 ClasspathCache.setCachedClasspath( providerName, providerClasspath );
1475 
1476             }
1477             Artifact surefireArtifact = getCommonArtifact();
1478             Classpath inprocClassPath = providerClasspath.
1479                     addClassPathElementUrl( surefireArtifact.getFile().getAbsolutePath() )
1480                     .addClassPathElementUrl( getApiArtifact().getFile().getAbsolutePath() );
1481 
1482             final Classpath testClasspath = generateTestClasspath();
1483 
1484             getLog().debug( testClasspath.getLogMessage( "test" ) );
1485             getLog().debug( providerClasspath.getLogMessage( "provider" ) );
1486 
1487             getLog().debug( testClasspath.getCompactLogMessage( "test(compact)" ) );
1488             getLog().debug( providerClasspath.getCompactLogMessage( "provider(compact)" ) );
1489 
1490             final ClasspathConfiguration classpathConfiguration =
1491                 new ClasspathConfiguration( testClasspath, providerClasspath, inprocClassPath,
1492                                             effectiveIsEnableAssertions(), isChildDelegation() );
1493 
1494             return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
1495                                              isForking(), false );
1496         }
1497         catch ( ArtifactResolutionException e )
1498         {
1499             throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
1500         }
1501         catch ( ArtifactNotFoundException e )
1502         {
1503             throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
1504         }
1505         catch ( InvalidVersionSpecificationException e )
1506         {
1507             throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
1508         }
1509 
1510     }
1511 
1512     private Artifact getCommonArtifact()
1513     {
1514         return getPluginArtifactMap().get( "org.apache.maven.surefire:maven-surefire-common" );
1515     }
1516 
1517     private Artifact getApiArtifact()
1518     {
1519         return getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-api" );
1520     }
1521 
1522     private StartupReportConfiguration getStartupReportConfiguration( String configChecksum )
1523     {
1524         return new StartupReportConfiguration( isUseFile(), isPrintSummary(), getReportFormat(),
1525                                                isRedirectTestOutputToFile(), isDisableXmlReport(),
1526                                                getReportsDirectory(), isTrimStackTrace(), getReportNameSuffix(),
1527                                                configChecksum, requiresRunHistory(), getRerunFailingTestsCount() );
1528     }
1529 
1530     private boolean isSpecificTestSpecified()
1531     {
1532         return getTest() != null;
1533     }
1534 
1535     private boolean isValidSuiteXmlFileConfig()
1536     {
1537         return getSuiteXmlFiles() != null && getSuiteXmlFiles().length > 0;
1538     }
1539 
1540     @SuppressWarnings( "checkstyle:modifierorder" )
1541     private @Nonnull List<String> readListFromFile( @Nonnull final File file )
1542     {
1543         List<String> list;
1544 
1545         getLog().debug( "Reading list from: " + file );
1546 
1547         if ( !file.exists() )
1548         {
1549             throw new RuntimeException( "Failed to load list from file: " + file );
1550         }
1551 
1552         try
1553         {
1554             list = FileUtils.loadFile( file );
1555         }
1556         catch ( IOException e )
1557         {
1558             throw new RuntimeException( "Failed to load list from file: " + file, e );
1559         }
1560 
1561         if ( getLog().isDebugEnabled() )
1562         {
1563             getLog().debug( "List contents:" );
1564             for ( String entry : list )
1565             {
1566                 getLog().debug( "  " + entry );
1567             }
1568         }
1569         return list;
1570     }
1571 
1572     private void maybeAppendList( final List<String> base, final List<String> list )
1573     {
1574         if ( list != null )
1575         {
1576             base.addAll( list );
1577         }
1578     }
1579 
1580     @SuppressWarnings( "checkstyle:modifierorder" )
1581     private @Nonnull List<String> getExcludeList()
1582     {
1583         List<String> actualExcludes = null;
1584         if ( isSpecificTestSpecified() )
1585         {
1586             // Check to see if we are running a single test. The raw parameter will
1587             // come through if it has not been set.
1588             // FooTest -> **/FooTest.java
1589 
1590             actualExcludes = new ArrayList<String>();
1591         }
1592         else
1593         {
1594             if ( getExcludesFile() != null )
1595             {
1596                 actualExcludes = readListFromFile( getExcludesFile() );
1597             }
1598 
1599             // If we have excludesFile, and we have excludes, then append excludes to excludesFile content
1600             if ( actualExcludes == null )
1601             {
1602                 actualExcludes = this.getExcludes();
1603             }
1604             else
1605             {
1606                 maybeAppendList( actualExcludes, this.getExcludes() );
1607             }
1608 
1609             // defaults here, qdox doesn't like the end javadoc value
1610             // Have to wrap in an ArrayList as surefire expects an ArrayList instead of a List for some reason
1611             if ( actualExcludes == null || actualExcludes.size() == 0 )
1612             {
1613                 actualExcludes = Arrays.asList( "**/*$*" );
1614             }
1615         }
1616         return filterNulls( actualExcludes );
1617     }
1618 
1619     private List<String> getIncludeList()
1620     {
1621         List<String> includes = null;
1622         if ( isSpecificTestSpecified() && !isMultipleExecutionBlocksDetected() )
1623         {
1624             includes = getSpecificTests();
1625         }
1626         else
1627         {
1628             if ( getIncludesFile() != null )
1629             {
1630                 includes = readListFromFile( getIncludesFile() );
1631             }
1632 
1633             // If we have includesFile, and we have includes, then append includes to includesFile content
1634             if ( includes == null )
1635             {
1636                 includes = this.getIncludes();
1637             }
1638             else
1639             {
1640                 maybeAppendList( includes, this.getIncludes() );
1641             }
1642         }
1643 
1644         // defaults here, qdox doesn't like the end javadoc value
1645         // Have to wrap in an ArrayList as surefire expects an ArrayList instead of a List for some reason
1646         if ( includes == null || includes.size() == 0 )
1647         {
1648             includes = Arrays.asList( getDefaultIncludes() );
1649         }
1650 
1651         return filterNulls( includes );
1652     }
1653 
1654     @SuppressWarnings( "checkstyle:modifierorder" )
1655     private @Nonnull List<String> filterNulls( @Nonnull List<String> toFilter )
1656     {
1657         List<String> result = new ArrayList<String>( toFilter.size() );
1658         for ( String item : toFilter )
1659         {
1660             if ( item != null )
1661             {
1662                 result.add( item );
1663             }
1664         }
1665 
1666         return result;
1667     }
1668 
1669     private boolean isMultipleExecutionBlocksDetected()
1670     {
1671         MavenProject project = getProject();
1672         if ( project != null )
1673         {
1674             String key = getPluginDescriptor().getPluginLookupKey();
1675             Plugin plugin = (Plugin) project.getBuild().getPluginsAsMap().get( key );
1676 
1677             if ( plugin != null )
1678             {
1679                 @SuppressWarnings( "rawtypes" ) List executions = plugin.getExecutions();
1680                 return executions != null && executions.size() > 1;
1681             }
1682         }
1683 
1684         return false;
1685     }
1686 
1687     private List<String> getSpecificTests()
1688     {
1689         if ( !isSpecificTestSpecified() )
1690         {
1691             return Collections.emptyList();
1692         }
1693 
1694         List<String> specificTests = new ArrayList<String>();
1695         String[] testRegexes = StringUtils.split( getTest(), "," );
1696 
1697         for ( String testRegexe : testRegexes )
1698         {
1699             String testRegex = testRegexe;
1700             if ( testRegex.endsWith( ".java" ) )
1701             {
1702                 testRegex = testRegex.substring( 0, testRegex.length() - 5 );
1703             }
1704             // Allow paths delimited by '.' or '/'
1705             testRegex = testRegex.replace( '.', '/' );
1706             specificTests.add( "**/" + testRegex + ".java" );
1707         }
1708 
1709         return specificTests;
1710     }
1711 
1712     private Artifact getTestNgArtifact()
1713         throws MojoExecutionException
1714     {
1715         Artifact artifact = getProjectArtifactMap().get( getTestNGArtifactName() );
1716 
1717         if ( artifact != null )
1718         {
1719             VersionRange range = createVersionRange();
1720             if ( !range.containsVersion( new DefaultArtifactVersion( artifact.getVersion() ) ) )
1721             {
1722                 throw new MojoExecutionException(
1723                     "TestNG support requires version 4.7 or above. You have declared version "
1724                         + artifact.getVersion() );
1725             }
1726         }
1727         return artifact;
1728 
1729     }
1730 
1731     private VersionRange createVersionRange()
1732     {
1733         try
1734         {
1735             return VersionRange.createFromVersionSpec( "[4.7,)" );
1736         }
1737         catch ( InvalidVersionSpecificationException e )
1738         {
1739             throw new RuntimeException( e );
1740         }
1741     }
1742 
1743     private Artifact getJunitArtifact()
1744     {
1745         return getProjectArtifactMap().get( getJunitArtifactName() );
1746     }
1747 
1748     private Artifact getJunitDepArtifact()
1749     {
1750         return getProjectArtifactMap().get( "junit:junit-dep" );
1751     }
1752 
1753     protected ForkStarter createForkStarter( ProviderInfo provider, ForkConfiguration forkConfiguration,
1754                                              ClassLoaderConfiguration classLoaderConfiguration,
1755                                              RunOrderParameters runOrderParameters, Log log )
1756         throws MojoExecutionException, MojoFailureException
1757     {
1758         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, classLoaderConfiguration );
1759         String configChecksum = getConfigChecksum();
1760         StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum );
1761         ProviderConfiguration providerConfiguration = createProviderConfiguration( runOrderParameters );
1762         return new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
1763                                 getForkedProcessTimeoutInSeconds(), startupReportConfiguration, log );
1764     }
1765 
1766     protected InPluginVMSurefireStarter createInprocessStarter( ProviderInfo provider,
1767                                                                 ClassLoaderConfiguration classLoaderConfiguration,
1768                                                                 RunOrderParameters runOrderParameters )
1769         throws MojoExecutionException, MojoFailureException
1770     {
1771         StartupConfiguration startupConfiguration = createStartupConfiguration( provider, classLoaderConfiguration );
1772         String configChecksum = getConfigChecksum();
1773         StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum );
1774         ProviderConfiguration providerConfiguration = createProviderConfiguration( runOrderParameters );
1775         return new InPluginVMSurefireStarter( startupConfiguration, providerConfiguration, startupReportConfiguration );
1776 
1777     }
1778 
1779     protected ForkConfiguration getForkConfiguration()
1780     {
1781         File tmpDir = getSurefireTempDir();
1782         //noinspection ResultOfMethodCallIgnored
1783         tmpDir.mkdirs();
1784 
1785         Artifact shadeFire = getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-shadefire" );
1786 
1787         final Classpath bootClasspathConfiguration =
1788             getArtifactClasspath( shadeFire != null ? shadeFire : surefireBooterArtifact );
1789 
1790         return new ForkConfiguration( bootClasspathConfiguration, tmpDir, getEffectiveDebugForkedProcess(),
1791                                       getEffectiveJvm(),
1792                                       getWorkingDirectory() != null ? getWorkingDirectory() : getBasedir(),
1793                                       getProject().getModel().getProperties(),
1794                                       getArgLine(), getEnvironmentVariables(), getLog().isDebugEnabled(),
1795                                       getEffectiveForkCount(), reuseForks );
1796     }
1797 
1798     private void convertDeprecatedForkMode()
1799     {
1800         String effectiveForkMode = getEffectiveForkMode();
1801         // FORK_ONCE (default) is represented by the default values of forkCount and reuseForks
1802         if ( ForkConfiguration.FORK_PERTHREAD.equals( effectiveForkMode ) )
1803         {
1804             forkCount = String.valueOf( threadCount );
1805         }
1806         else if ( ForkConfiguration.FORK_NEVER.equals( effectiveForkMode ) )
1807         {
1808             forkCount = "0";
1809         }
1810         else if ( ForkConfiguration.FORK_ALWAYS.equals( effectiveForkMode ) )
1811         {
1812             forkCount = "1";
1813             reuseForks = false;
1814         }
1815 
1816         if ( !ForkConfiguration.FORK_ONCE.equals( getForkMode() ) )
1817         {
1818             getLog().warn(
1819                 "The parameter forkMode is deprecated since version 2.14. Use forkCount and reuseForks instead." );
1820         }
1821     }
1822 
1823     @SuppressWarnings( "checkstyle:emptyblock" )
1824     protected int getEffectiveForkCount()
1825     {
1826         if ( effectiveForkCount < 0 )
1827         {
1828             try
1829             {
1830                 effectiveForkCount = convertWithCoreCount( forkCount );
1831             }
1832             catch ( NumberFormatException ignored )
1833             {
1834             }
1835 
1836             if ( effectiveForkCount < 0 )
1837             {
1838                 throw new IllegalArgumentException( "Fork count " + forkCount.trim() + " is not a legal value." );
1839             }
1840         }
1841 
1842         return effectiveForkCount;
1843     }
1844 
1845     protected int convertWithCoreCount( String count )
1846     {
1847         String trimmed = count.trim();
1848         if ( trimmed.endsWith( "C" ) )
1849         {
1850             double multiplier = Double.parseDouble( trimmed.substring( 0, trimmed.length() - 1 ) );
1851             double calculated = multiplier * ( (double) Runtime.getRuntime().availableProcessors() );
1852             return calculated > 0d ? Math.max( (int) calculated, 1 ) : 0;
1853         }
1854         else
1855         {
1856             return Integer.parseInt( trimmed );
1857         }
1858     }
1859 
1860     private String getEffectiveDebugForkedProcess()
1861     {
1862         String debugForkedProcess = getDebugForkedProcess();
1863         if ( "true".equals( debugForkedProcess ) )
1864         {
1865             return "-Xdebug -Xnoagent -Djava.compiler=NONE"
1866                 + " -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005";
1867         }
1868         return debugForkedProcess;
1869     }
1870 
1871     private String getEffectiveJvm()
1872     {
1873         String jvmToUse = getJvm();
1874         if ( toolchain != null && jvmToUse == null )
1875         {
1876             jvmToUse = toolchain.findTool( "java" ); //NOI18N
1877         }
1878 
1879         if ( StringUtils.isEmpty( jvmToUse ) )
1880         {
1881             // use the same JVM as the one used to run Maven (the "java.home" one)
1882             jvmToUse = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java";
1883             getLog().debug( "Using JVM: " + jvmToUse );
1884         }
1885 
1886         return jvmToUse;
1887     }
1888 
1889 
1890     private Artifact getSurefireBooterArtifact()
1891     {
1892         Artifact artifact = getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
1893         if ( artifact == null )
1894         {
1895             throw new RuntimeException( "Unable to locate surefire-booter in the list of plugin artifacts" );
1896         }
1897         artifact.isSnapshot(); // MNG-2961: before Maven 2.0.8, fixes getBaseVersion to be -SNAPSHOT if needed
1898         return artifact;
1899     }
1900 
1901 
1902     /**
1903      * Where surefire stores its own temp files
1904      *
1905      * @return A file pointing to the location of surefire's own temp files
1906      */
1907     private File getSurefireTempDir()
1908     {
1909         return new File( getReportsDirectory().getParentFile(), "surefire" );
1910     }
1911 
1912     /**
1913      * Operates on raw plugin paramenters, not the "effective" values.
1914      *
1915      * @return The checksum
1916      */
1917     private String getConfigChecksum()
1918     {
1919         ChecksumCalculator checksum = new ChecksumCalculator();
1920         checksum.add( getPluginName() );
1921         checksum.add( isSkipTests() );
1922         checksum.add( isSkipExec() );
1923         checksum.add( isSkip() );
1924         checksum.add( getTestClassesDirectory() );
1925         checksum.add( getClassesDirectory() );
1926         checksum.add( getClasspathDependencyExcludes() );
1927         checksum.add( getClasspathDependencyScopeExclude() );
1928         checksum.add( getAdditionalClasspathElements() );
1929         checksum.add( getReportsDirectory() );
1930         checksum.add( getTestSourceDirectory() );
1931         checksum.add( getTest() );
1932         checksum.add( getIncludes() );
1933         checksum.add( getExcludes() );
1934         checksum.add( getLocalRepository() );
1935         checksum.add( getSystemProperties() );
1936         checksum.add( getSystemPropertyVariables() );
1937         checksum.add( getSystemPropertiesFile() );
1938         checksum.add( getProperties() );
1939         checksum.add( isPrintSummary() );
1940         checksum.add( getReportFormat() );
1941         checksum.add( getReportNameSuffix() );
1942         checksum.add( isUseFile() );
1943         checksum.add( isRedirectTestOutputToFile() );
1944         checksum.add( getForkMode() );
1945         checksum.add( getForkCount() );
1946         checksum.add( isReuseForks() );
1947         checksum.add( getJvm() );
1948         checksum.add( getArgLine() );
1949         checksum.add( getDebugForkedProcess() );
1950         checksum.add( getForkedProcessTimeoutInSeconds() );
1951         checksum.add( getParallelTestsTimeoutInSeconds() );
1952         checksum.add( getParallelTestsTimeoutForcedInSeconds() );
1953         checksum.add( getEnvironmentVariables() );
1954         checksum.add( getWorkingDirectory() );
1955         checksum.add( isChildDelegation() );
1956         checksum.add( getGroups() );
1957         checksum.add( getExcludedGroups() );
1958         checksum.add( getSuiteXmlFiles() );
1959         checksum.add( getJunitArtifact() );
1960         checksum.add( getTestNGArtifactName() );
1961         checksum.add( getThreadCount() );
1962         checksum.add( getThreadCountSuites() );
1963         checksum.add( getThreadCountClasses() );
1964         checksum.add( getThreadCountMethods() );
1965         checksum.add( getPerCoreThreadCount() );
1966         checksum.add( getUseUnlimitedThreads() );
1967         checksum.add( getParallel() );
1968         checksum.add( isParallelOptimized() );
1969         checksum.add( isTrimStackTrace() );
1970         checksum.add( getRemoteRepositories() );
1971         checksum.add( isDisableXmlReport() );
1972         checksum.add( isUseSystemClassLoader() );
1973         checksum.add( isUseManifestOnlyJar() );
1974         checksum.add( isEnableAssertions() );
1975         checksum.add( getObjectFactory() );
1976         checksum.add( getFailIfNoTests() );
1977         checksum.add( getRunOrder() );
1978         checksum.add( getDependenciesToScan() );
1979         addPluginSpecificChecksumItems( checksum );
1980         return checksum.getSha1();
1981 
1982     }
1983 
1984     protected void addPluginSpecificChecksumItems( ChecksumCalculator checksum )
1985     {
1986 
1987     }
1988 
1989     protected boolean hasExecutedBefore()
1990     {
1991         // A tribute to Linus Torvalds
1992         String configChecksum = getConfigChecksum();
1993         @SuppressWarnings( "unchecked" ) Map<String, String> pluginContext = getPluginContext();
1994         if ( pluginContext.containsKey( configChecksum ) )
1995         {
1996             getLog().info( "Skipping execution of surefire because it has already been run for this configuration" );
1997             return true;
1998         }
1999         pluginContext.put( configChecksum, configChecksum );
2000 
2001         return false;
2002     }
2003 
2004     protected ClassLoaderConfiguration getClassLoaderConfiguration( boolean isForking )
2005     {
2006         return isForking
2007             ? new ClassLoaderConfiguration( isUseSystemClassLoader(), isUseManifestOnlyJar() )
2008             : new ClassLoaderConfiguration( false, false );
2009     }
2010 
2011     protected abstract String[] getDefaultIncludes();
2012 
2013     /**
2014      * Generate the test classpath.
2015      *
2016      * @return List containing the classpath elements
2017      * @throws InvalidVersionSpecificationException
2018      *                                     when it happens
2019      * @throws MojoFailureException        when it happens
2020      * @throws ArtifactNotFoundException   when it happens
2021      * @throws ArtifactResolutionException when it happens
2022      */
2023     Classpath generateTestClasspath()
2024         throws InvalidVersionSpecificationException, MojoFailureException, ArtifactResolutionException,
2025         ArtifactNotFoundException, MojoExecutionException
2026     {
2027         List<String> classpath = new ArrayList<String>( 2 + getProject().getArtifacts().size() );
2028 
2029         classpath.add( getTestClassesDirectory().getAbsolutePath() );
2030 
2031         classpath.add( getClassesDirectory().getAbsolutePath() );
2032 
2033         @SuppressWarnings( "unchecked" ) Set<Artifact> classpathArtifacts = getProject().getArtifacts();
2034 
2035         if ( getClasspathDependencyScopeExclude() != null && !getClasspathDependencyScopeExclude().equals( "" ) )
2036         {
2037             ArtifactFilter dependencyFilter = new ScopeArtifactFilter( getClasspathDependencyScopeExclude() );
2038             classpathArtifacts = this.filterArtifacts( classpathArtifacts, dependencyFilter );
2039         }
2040 
2041         if ( getClasspathDependencyExcludes() != null )
2042         {
2043             ArtifactFilter dependencyFilter =
2044                 new PatternIncludesArtifactFilter( Arrays.asList( getClasspathDependencyExcludes() ) );
2045             classpathArtifacts = this.filterArtifacts( classpathArtifacts, dependencyFilter );
2046         }
2047 
2048         for ( Artifact artifact : classpathArtifacts )
2049         {
2050             if ( artifact.getArtifactHandler().isAddedToClasspath() )
2051             {
2052                 File file = artifact.getFile();
2053                 if ( file != null )
2054                 {
2055                     classpath.add( file.getPath() );
2056                 }
2057             }
2058         }
2059 
2060         // Add additional configured elements to the classpath
2061         if ( getAdditionalClasspathElements() != null )
2062         {
2063             for ( String classpathElement : getAdditionalClasspathElements() )
2064             {
2065                 if ( classpathElement != null )
2066                 {
2067                     classpath.add( classpathElement );
2068                 }
2069             }
2070         }
2071 
2072         // adding TestNG MethodSelector to the classpath
2073         // Todo: move
2074         if ( getTestNgArtifact() != null )
2075         {
2076             addTestNgUtilsArtifacts( classpath );
2077         }
2078 
2079         return new Classpath( classpath );
2080     }
2081 
2082     void addTestNgUtilsArtifacts( List<String> classpath )
2083         throws ArtifactResolutionException, ArtifactNotFoundException
2084     {
2085         Artifact surefireArtifact = getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
2086         String surefireVersion = surefireArtifact.getBaseVersion();
2087 
2088         Artifact[] extraTestNgArtifacts =
2089             { getArtifactFactory().createArtifact( "org.apache.maven.surefire", "surefire-testng-utils",
2090                                                    surefireVersion, "runtime", "jar" ),
2091                 getArtifactFactory().createArtifact( "org.apache.maven.surefire", "surefire-grouper", surefireVersion,
2092                                                      "runtime", "jar" ) };
2093 
2094         for ( Artifact artifact : extraTestNgArtifacts )
2095         {
2096             getArtifactResolver().resolve( artifact, getRemoteRepositories(), getLocalRepository() );
2097 
2098             String path = artifact.getFile().getPath();
2099             classpath.add( path );
2100         }
2101     }
2102 
2103     /**
2104      * Return a new set containing only the artifacts accepted by the given filter.
2105      *
2106      * @param artifacts The unfiltered artifacts
2107      * @param filter    The filter to apply
2108      * @return The filtered result
2109      */
2110     private Set<Artifact> filterArtifacts( Set<Artifact> artifacts, ArtifactFilter filter )
2111     {
2112         Set<Artifact> filteredArtifacts = new LinkedHashSet<Artifact>();
2113 
2114         for ( Artifact artifact : artifacts )
2115         {
2116             if ( !filter.include( artifact ) )
2117             {
2118                 filteredArtifacts.add( artifact );
2119             }
2120         }
2121 
2122         return filteredArtifacts;
2123     }
2124 
2125     private void showMap( Map<?, ?> map, String setting )
2126     {
2127         for ( Object o : map.keySet() )
2128         {
2129             String key = (String) o;
2130             String value = (String) map.get( key );
2131             getLog().debug( "Setting " + setting + " [" + key + "]=[" + value + "]" );
2132         }
2133     }
2134 
2135 
2136     private ArtifactResolutionResult resolveArtifact( Artifact filteredArtifact, Artifact providerArtifact )
2137     {
2138         ArtifactFilter filter = null;
2139         if ( filteredArtifact != null )
2140         {
2141             filter = new ExcludesArtifactFilter(
2142                 Collections.singletonList( filteredArtifact.getGroupId() + ":" + filteredArtifact.getArtifactId() ) );
2143         }
2144 
2145         Artifact originatingArtifact = getArtifactFactory().createBuildArtifact( "dummy", "dummy", "1.0", "jar" );
2146 
2147         try
2148         {
2149             return getArtifactResolver().resolveTransitively( Collections.singleton( providerArtifact ),
2150                                                               originatingArtifact, getLocalRepository(),
2151                                                               getRemoteRepositories(), getMetadataSource(), filter );
2152         }
2153         catch ( ArtifactResolutionException e )
2154         {
2155             throw new RuntimeException( e );
2156         }
2157         catch ( ArtifactNotFoundException e )
2158         {
2159             throw new RuntimeException( e );
2160         }
2161     }
2162 
2163     private Classpath getArtifactClasspath( Artifact surefireArtifact )
2164     {
2165         Classpath existing = ClasspathCache.getCachedClassPath( surefireArtifact.getArtifactId() );
2166         if ( existing == null )
2167         {
2168             ArtifactResolutionResult result = resolveArtifact( null, surefireArtifact );
2169 
2170             List<String> items = new ArrayList<String>();
2171             for ( Object o : result.getArtifacts() )
2172             {
2173                 Artifact artifact = (Artifact) o;
2174 
2175                 getLog().debug(
2176                     "Adding to " + getPluginName() + " booter test classpath: " + artifact.getFile().getAbsolutePath()
2177                     + " Scope: " + artifact.getScope() );
2178 
2179                 items.add( artifact.getFile().getAbsolutePath() );
2180             }
2181             existing = new Classpath( items );
2182             ClasspathCache.setCachedClasspath( surefireArtifact.getArtifactId(), existing );
2183         }
2184         return existing;
2185     }
2186 
2187     private Properties getUserProperties()
2188     {
2189         Properties props = null;
2190         try
2191         {
2192             // try calling MavenSession.getUserProperties() from Maven 2.1.0-M1+
2193             Method getUserProperties = getSession().getClass().getMethod( "getUserProperties" );
2194             props = (Properties) getUserProperties.invoke( getSession() );
2195         }
2196         catch ( Exception e )
2197         {
2198             String msg = "Build uses Maven 2.0.x, cannot propagate system properties"
2199                 + " from command line to tests (cf. SUREFIRE-121)";
2200             if ( getLog().isDebugEnabled() )
2201             {
2202                 getLog().warn( msg, e );
2203             }
2204             else
2205             {
2206                 getLog().warn( msg );
2207             }
2208         }
2209         if ( props == null )
2210         {
2211             props = new Properties();
2212         }
2213         return props;
2214     }
2215 
2216 
2217     void ensureWorkingDirectoryExists()
2218         throws MojoFailureException
2219     {
2220         if ( getWorkingDirectory() == null )
2221         {
2222             throw new MojoFailureException( "workingDirectory cannot be null" );
2223         }
2224 
2225         if ( !getWorkingDirectory().exists() )
2226         {
2227             if ( !getWorkingDirectory().mkdirs() )
2228             {
2229                 throw new MojoFailureException( "Cannot create workingDirectory " + getWorkingDirectory() );
2230             }
2231         }
2232 
2233         if ( !getWorkingDirectory().isDirectory() )
2234         {
2235             throw new MojoFailureException(
2236                 "workingDirectory " + getWorkingDirectory() + " exists and is not a directory" );
2237         }
2238     }
2239 
2240     void ensureParallelRunningCompatibility()
2241         throws MojoFailureException
2242     {
2243         if ( isMavenParallel() && isNotForking() )
2244         {
2245             throw new MojoFailureException( "parallel maven execution is not compatible with surefire forkCount 0" );
2246         }
2247     }
2248 
2249     void ensureThreadCountWithPerThread()
2250         throws MojoFailureException
2251     {
2252         if ( ForkConfiguration.FORK_PERTHREAD.equals( getEffectiveForkMode() ) && getThreadCount() < 1 )
2253         {
2254             throw new MojoFailureException( "Fork mode perthread requires a thread count" );
2255         }
2256     }
2257 
2258     void warnIfUselessUseSystemClassLoaderParameter()
2259     {
2260         if ( isUseSystemClassLoader() && isNotForking() )
2261         {
2262             getLog().warn( "useSystemClassloader setting has no effect when not forking" );
2263         }
2264     }
2265 
2266     private boolean isNotForking()
2267     {
2268         return !isForking();
2269     }
2270 
2271     void warnIfDefunctGroupsCombinations()
2272         throws MojoFailureException, MojoExecutionException
2273     {
2274         if ( isAnyGroupsSelected() )
2275         {
2276             if ( getTestNgArtifact() != null )
2277             {
2278                 return;
2279             }
2280             Artifact junitArtifact = getJunitArtifact();
2281             boolean junit47Compatible = isJunit47Compatible( junitArtifact );
2282             if ( junit47Compatible )
2283             {
2284                 return;
2285             }
2286             if ( junitArtifact != null )
2287             {
2288                 throw new MojoFailureException( "groups/excludedGroups are specified but JUnit version on classpath"
2289                         + " is too old to support groups. Check your dependency:tree to see if your project"
2290                         + " is picking up an old junit version" );
2291             }
2292             throw new MojoFailureException(
2293                 "groups/excludedGroups require TestNG or JUnit48+ on project test classpath" );
2294 
2295         }
2296     }
2297 
2298     class TestNgProviderInfo
2299         implements ProviderInfo
2300     {
2301         private final Artifact testNgArtifact;
2302 
2303         TestNgProviderInfo( Artifact testNgArtifact )
2304         {
2305             this.testNgArtifact = testNgArtifact;
2306         }
2307 
2308         @SuppressWarnings( "checkstyle:modifierorder" )
2309         public @Nonnull String getProviderName()
2310         {
2311             return "org.apache.maven.surefire.testng.TestNGProvider";
2312         }
2313 
2314         public boolean isApplicable()
2315         {
2316             return testNgArtifact != null;
2317         }
2318 
2319         public void addProviderProperties() throws MojoExecutionException
2320         {
2321             convertTestNGParameters();
2322         }
2323 
2324         public Classpath getProviderClasspath()
2325             throws ArtifactResolutionException, ArtifactNotFoundException
2326         {
2327             Artifact surefireArtifact = getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
2328             return dependencyResolver.getProviderClasspath( "surefire-testng", surefireArtifact.getBaseVersion(),
2329                                                             testNgArtifact );
2330         }
2331     }
2332 
2333     class JUnit3ProviderInfo
2334         implements ProviderInfo
2335     {
2336         @Nonnull public String getProviderName()
2337         {
2338             return "org.apache.maven.surefire.junit.JUnit3Provider";
2339         }
2340 
2341         public boolean isApplicable()
2342         {
2343             return true;
2344         }
2345 
2346         public void addProviderProperties() throws MojoExecutionException
2347         {
2348         }
2349 
2350         public Classpath getProviderClasspath()
2351             throws ArtifactResolutionException, ArtifactNotFoundException
2352         {
2353             // add the JUnit provider as default - it doesn't require JUnit to be present,
2354             // since it supports POJO tests.
2355             return dependencyResolver.getProviderClasspath( "surefire-junit3", surefireBooterArtifact.getBaseVersion(),
2356                                                             null );
2357 
2358         }
2359 
2360     }
2361 
2362     class JUnit4ProviderInfo
2363         implements ProviderInfo
2364     {
2365         private final Artifact junitArtifact;
2366 
2367         private final Artifact junitDepArtifact;
2368 
2369         JUnit4ProviderInfo( Artifact junitArtifact, Artifact junitDepArtifact )
2370         {
2371             this.junitArtifact = junitArtifact;
2372             this.junitDepArtifact = junitDepArtifact;
2373         }
2374 
2375         @Nonnull public String getProviderName()
2376         {
2377             return "org.apache.maven.surefire.junit4.JUnit4Provider";
2378         }
2379 
2380         public boolean isApplicable()
2381         {
2382             return junitDepArtifact != null || isAnyJunit4( junitArtifact );
2383         }
2384 
2385         public void addProviderProperties() throws MojoExecutionException
2386         {
2387         }
2388 
2389         public Classpath getProviderClasspath()
2390             throws ArtifactResolutionException, ArtifactNotFoundException
2391         {
2392             return dependencyResolver.getProviderClasspath( "surefire-junit4", surefireBooterArtifact.getBaseVersion(),
2393                                                             null );
2394 
2395         }
2396 
2397     }
2398 
2399     class JUnitCoreProviderInfo
2400         implements ProviderInfo
2401     {
2402         private final Artifact junitArtifact;
2403 
2404         private final Artifact junitDepArtifact;
2405 
2406         JUnitCoreProviderInfo( Artifact junitArtifact, Artifact junitDepArtifact )
2407         {
2408             this.junitArtifact = junitArtifact;
2409             this.junitDepArtifact = junitDepArtifact;
2410         }
2411 
2412         @Nonnull public String getProviderName()
2413         {
2414             return "org.apache.maven.surefire.junitcore.JUnitCoreProvider";
2415         }
2416 
2417         private boolean is47CompatibleJunitDep()
2418         {
2419             return junitDepArtifact != null && isJunit47Compatible( junitDepArtifact );
2420         }
2421 
2422         public boolean isApplicable()
2423         {
2424             final boolean isJunitArtifact47 = isAnyJunit4( junitArtifact ) && isJunit47Compatible( junitArtifact );
2425             final boolean isAny47ProvidersForcers = isAnyConcurrencySelected() || isAnyGroupsSelected();
2426             return isAny47ProvidersForcers && ( isJunitArtifact47 || is47CompatibleJunitDep() );
2427         }
2428 
2429         public void addProviderProperties() throws MojoExecutionException
2430         {
2431             convertJunitCoreParameters();
2432             convertGroupParameters();
2433         }
2434 
2435         public Classpath getProviderClasspath()
2436             throws ArtifactResolutionException, ArtifactNotFoundException
2437         {
2438             return dependencyResolver.getProviderClasspath( "surefire-junit47", surefireBooterArtifact.getBaseVersion(),
2439                                                             null );
2440         }
2441 
2442     }
2443 
2444     /**
2445      * Provides the Provider information for manually configured providers
2446      *
2447      */
2448     public class DynamicProviderInfo
2449         implements ConfigurableProviderInfo
2450     {
2451         final String providerName;
2452 
2453         DynamicProviderInfo( String providerName )
2454         {
2455             this.providerName = providerName;
2456         }
2457 
2458         public ProviderInfo instantiate( String providerName )
2459         {
2460             return new DynamicProviderInfo( providerName );
2461         }
2462 
2463         @Nonnull
2464         public String getProviderName()
2465         {
2466             return providerName;
2467         }
2468 
2469         public boolean isApplicable()
2470         {
2471             return true;
2472         }
2473 
2474         public void addProviderProperties() throws MojoExecutionException
2475         {
2476             // Ok this is a bit lazy.
2477             convertJunitCoreParameters();
2478             convertTestNGParameters();
2479         }
2480 
2481 
2482         public Classpath getProviderClasspath()
2483             throws ArtifactResolutionException, ArtifactNotFoundException
2484         {
2485             final Map<String, Artifact> pluginArtifactMap = getPluginArtifactMap();
2486             Artifact plugin = pluginArtifactMap.get( "org.apache.maven.plugins:maven-surefire-plugin" );
2487             return dependencyResolver.addProviderToClasspath( pluginArtifactMap, plugin );
2488         }
2489 
2490     }
2491 
2492     public abstract List<String> getIncludes();
2493 
2494     public File getIncludesFile()
2495     {
2496         return includesFile;
2497     }
2498 
2499     public abstract void setIncludes( List<String> includes );
2500 
2501     public List<String> getExcludes()
2502     {
2503         return excludes;
2504     }
2505 
2506     public File getExcludesFile()
2507     {
2508         return excludesFile;
2509     }
2510 
2511     public void setExcludes( List<String> excludes )
2512     {
2513         this.excludes = excludes;
2514     }
2515 
2516     public ArtifactRepository getLocalRepository()
2517     {
2518         return localRepository;
2519     }
2520 
2521     public void setLocalRepository( ArtifactRepository localRepository )
2522     {
2523         this.localRepository = localRepository;
2524     }
2525 
2526     /**
2527      * @noinspection deprecation
2528      */
2529     public Properties getSystemProperties()
2530     {
2531         return systemProperties;
2532     }
2533 
2534     @SuppressWarnings( { "UnusedDeclaration", "deprecation" } )
2535     public void setSystemProperties( Properties systemProperties )
2536     {
2537         this.systemProperties = systemProperties;
2538     }
2539 
2540     public Map<String, String> getSystemPropertyVariables()
2541     {
2542         return systemPropertyVariables;
2543     }
2544 
2545     @SuppressWarnings( "UnusedDeclaration" )
2546     public void setSystemPropertyVariables( Map<String, String> systemPropertyVariables )
2547     {
2548         this.systemPropertyVariables = systemPropertyVariables;
2549     }
2550 
2551     public File getSystemPropertiesFile()
2552     {
2553         return systemPropertiesFile;
2554     }
2555 
2556     @SuppressWarnings( "UnusedDeclaration" )
2557     public void setSystemPropertiesFile( File systemPropertiesFile )
2558     {
2559         this.systemPropertiesFile = systemPropertiesFile;
2560     }
2561 
2562     public Properties getProperties()
2563     {
2564         return properties;
2565     }
2566 
2567     public void setProperties( Properties properties )
2568     {
2569         this.properties = properties;
2570     }
2571 
2572     public Map<String, Artifact> getPluginArtifactMap()
2573     {
2574         return pluginArtifactMap;
2575     }
2576 
2577     @SuppressWarnings( "UnusedDeclaration" )
2578     public void setPluginArtifactMap( Map<String, Artifact> pluginArtifactMap )
2579     {
2580         this.pluginArtifactMap = pluginArtifactMap;
2581     }
2582 
2583     public Map<String, Artifact> getProjectArtifactMap()
2584     {
2585         return projectArtifactMap;
2586     }
2587 
2588     @SuppressWarnings( "UnusedDeclaration" )
2589     public void setProjectArtifactMap( Map<String, Artifact> projectArtifactMap )
2590     {
2591         this.projectArtifactMap = projectArtifactMap;
2592     }
2593 
2594 
2595     public String getReportNameSuffix()
2596     {
2597         return reportNameSuffix;
2598     }
2599 
2600     @SuppressWarnings( "UnusedDeclaration" )
2601     public void setReportNameSuffix( String reportNameSuffix )
2602     {
2603         this.reportNameSuffix = reportNameSuffix;
2604     }
2605 
2606 
2607     public boolean isRedirectTestOutputToFile()
2608     {
2609         return redirectTestOutputToFile;
2610     }
2611 
2612     @SuppressWarnings( "UnusedDeclaration" )
2613     public void setRedirectTestOutputToFile( boolean redirectTestOutputToFile )
2614     {
2615         this.redirectTestOutputToFile = redirectTestOutputToFile;
2616     }
2617 
2618 
2619     public Boolean getFailIfNoTests()
2620     {
2621         return failIfNoTests;
2622     }
2623 
2624     public void setFailIfNoTests( Boolean failIfNoTests )
2625     {
2626         this.failIfNoTests = failIfNoTests;
2627     }
2628 
2629     public String getForkMode()
2630     {
2631         return forkMode;
2632     }
2633 
2634     @SuppressWarnings( "UnusedDeclaration" )
2635     public void setForkMode( String forkMode )
2636     {
2637         this.forkMode = forkMode;
2638     }
2639 
2640     public String getJvm()
2641     {
2642         return jvm;
2643     }
2644 
2645     public String getArgLine()
2646     {
2647         return argLine;
2648     }
2649 
2650     @SuppressWarnings( "UnusedDeclaration" )
2651     public void setArgLine( String argLine )
2652     {
2653         this.argLine = argLine;
2654     }
2655 
2656 
2657     public Map<String, String> getEnvironmentVariables()
2658     {
2659         return environmentVariables;
2660     }
2661 
2662     @SuppressWarnings( "UnusedDeclaration" )
2663     public void setEnvironmentVariables( Map<String, String> environmentVariables )
2664     {
2665         this.environmentVariables = environmentVariables;
2666     }
2667 
2668     public File getWorkingDirectory()
2669     {
2670         return workingDirectory;
2671     }
2672 
2673     @SuppressWarnings( "UnusedDeclaration" )
2674     public void setWorkingDirectory( File workingDirectory )
2675     {
2676         this.workingDirectory = workingDirectory;
2677     }
2678 
2679     public boolean isChildDelegation()
2680     {
2681         return childDelegation;
2682     }
2683 
2684     @SuppressWarnings( "UnusedDeclaration" )
2685     public void setChildDelegation( boolean childDelegation )
2686     {
2687         this.childDelegation = childDelegation;
2688     }
2689 
2690     public String getGroups()
2691     {
2692         return groups;
2693     }
2694 
2695     @SuppressWarnings( "UnusedDeclaration" )
2696     public void setGroups( String groups )
2697     {
2698         this.groups = groups;
2699     }
2700 
2701     public String getExcludedGroups()
2702     {
2703         return excludedGroups;
2704     }
2705 
2706     @SuppressWarnings( "UnusedDeclaration" )
2707     public void setExcludedGroups( String excludedGroups )
2708     {
2709         this.excludedGroups = excludedGroups;
2710     }
2711 
2712     public abstract File[] getSuiteXmlFiles();
2713 
2714     public abstract void setSuiteXmlFiles( File[] suiteXmlFiles );
2715 
2716     public String getJunitArtifactName()
2717     {
2718         return junitArtifactName;
2719     }
2720 
2721     @SuppressWarnings( "UnusedDeclaration" )
2722     public void setJunitArtifactName( String junitArtifactName )
2723     {
2724         this.junitArtifactName = junitArtifactName;
2725     }
2726 
2727     public String getTestNGArtifactName()
2728     {
2729         return testNGArtifactName;
2730     }
2731 
2732     @SuppressWarnings( "UnusedDeclaration" )
2733     public void setTestNGArtifactName( String testNGArtifactName )
2734     {
2735         this.testNGArtifactName = testNGArtifactName;
2736     }
2737 
2738     public int getThreadCount()
2739     {
2740         return threadCount;
2741     }
2742 
2743     @SuppressWarnings( "UnusedDeclaration" )
2744     public void setThreadCount( int threadCount )
2745     {
2746         this.threadCount = threadCount;
2747     }
2748 
2749     public boolean getPerCoreThreadCount()
2750     {
2751         return perCoreThreadCount;
2752     }
2753 
2754     @SuppressWarnings( "UnusedDeclaration" )
2755     public void setPerCoreThreadCount( boolean perCoreThreadCount )
2756     {
2757         this.perCoreThreadCount = perCoreThreadCount;
2758     }
2759 
2760     public boolean getUseUnlimitedThreads()
2761     {
2762         return useUnlimitedThreads;
2763     }
2764 
2765     @SuppressWarnings( "UnusedDeclaration" )
2766     public void setUseUnlimitedThreads( boolean useUnlimitedThreads )
2767     {
2768         this.useUnlimitedThreads = useUnlimitedThreads;
2769     }
2770 
2771     public String getParallel()
2772     {
2773         return parallel;
2774     }
2775 
2776     @SuppressWarnings( "UnusedDeclaration" )
2777     public void setParallel( String parallel )
2778     {
2779         this.parallel = parallel;
2780     }
2781 
2782     public boolean isParallelOptimized()
2783     {
2784         return parallelOptimized;
2785     }
2786 
2787     @SuppressWarnings( "UnusedDeclaration" )
2788     public void setParallelOptimized( boolean parallelOptimized )
2789     {
2790         this.parallelOptimized = parallelOptimized;
2791     }
2792 
2793     public int getThreadCountSuites()
2794     {
2795         return threadCountSuites;
2796     }
2797 
2798     public void setThreadCountSuites( int threadCountSuites )
2799     {
2800         this.threadCountSuites = threadCountSuites;
2801     }
2802 
2803     public int getThreadCountClasses()
2804     {
2805         return threadCountClasses;
2806     }
2807 
2808     public void setThreadCountClasses( int threadCountClasses )
2809     {
2810         this.threadCountClasses = threadCountClasses;
2811     }
2812 
2813     public int getThreadCountMethods()
2814     {
2815         return threadCountMethods;
2816     }
2817 
2818     public void setThreadCountMethods( int threadCountMethods )
2819     {
2820         this.threadCountMethods = threadCountMethods;
2821     }
2822 
2823     public boolean isTrimStackTrace()
2824     {
2825         return trimStackTrace;
2826     }
2827 
2828     @SuppressWarnings( "UnusedDeclaration" )
2829     public void setTrimStackTrace( boolean trimStackTrace )
2830     {
2831         this.trimStackTrace = trimStackTrace;
2832     }
2833 
2834     public ArtifactResolver getArtifactResolver()
2835     {
2836         return artifactResolver;
2837     }
2838 
2839     @SuppressWarnings( "UnusedDeclaration" )
2840     public void setArtifactResolver( ArtifactResolver artifactResolver )
2841     {
2842         this.artifactResolver = artifactResolver;
2843     }
2844 
2845     public ArtifactFactory getArtifactFactory()
2846     {
2847         return artifactFactory;
2848     }
2849 
2850     @SuppressWarnings( "UnusedDeclaration" )
2851     public void setArtifactFactory( ArtifactFactory artifactFactory )
2852     {
2853         this.artifactFactory = artifactFactory;
2854     }
2855 
2856     public List<ArtifactRepository> getRemoteRepositories()
2857     {
2858         return remoteRepositories;
2859     }
2860 
2861     @SuppressWarnings( "UnusedDeclaration" )
2862     public void setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
2863     {
2864         this.remoteRepositories = remoteRepositories;
2865     }
2866 
2867     public ArtifactMetadataSource getMetadataSource()
2868     {
2869         return metadataSource;
2870     }
2871 
2872     @SuppressWarnings( "UnusedDeclaration" )
2873     public void setMetadataSource( ArtifactMetadataSource metadataSource )
2874     {
2875         this.metadataSource = metadataSource;
2876     }
2877 
2878 
2879     public boolean isDisableXmlReport()
2880     {
2881         return disableXmlReport;
2882     }
2883 
2884     @SuppressWarnings( "UnusedDeclaration" )
2885     public void setDisableXmlReport( boolean disableXmlReport )
2886     {
2887         this.disableXmlReport = disableXmlReport;
2888     }
2889 
2890 
2891     public boolean isEnableAssertions()
2892     {
2893         return enableAssertions;
2894     }
2895 
2896     public boolean effectiveIsEnableAssertions()
2897     {
2898         if ( getArgLine() != null )
2899         {
2900             List<String> args = Arrays.asList( getArgLine().split( " " ) );
2901             if ( args.contains( "-da" ) || args.contains( "-disableassertions" ) )
2902             {
2903                 return false;
2904             }
2905         }
2906         return isEnableAssertions();
2907     }
2908 
2909     @SuppressWarnings( "UnusedDeclaration" )
2910     public void setEnableAssertions( boolean enableAssertions )
2911     {
2912         this.enableAssertions = enableAssertions;
2913     }
2914 
2915     public MavenSession getSession()
2916     {
2917         return session;
2918     }
2919 
2920     @SuppressWarnings( "UnusedDeclaration" )
2921     public void setSession( MavenSession session )
2922     {
2923         this.session = session;
2924     }
2925 
2926     public String getObjectFactory()
2927     {
2928         return objectFactory;
2929     }
2930 
2931     @SuppressWarnings( "UnusedDeclaration" )
2932     public void setObjectFactory( String objectFactory )
2933     {
2934         this.objectFactory = objectFactory;
2935     }
2936 
2937     public ToolchainManager getToolchainManager()
2938     {
2939         return toolchainManager;
2940     }
2941 
2942     @SuppressWarnings( "UnusedDeclaration" )
2943     public void setToolchainManager( ToolchainManager toolchainManager )
2944     {
2945         this.toolchainManager = toolchainManager;
2946     }
2947 
2948     public boolean isMavenParallel()
2949     {
2950         return parallelMavenExecution != null && parallelMavenExecution;
2951     }
2952 
2953     public abstract String getRunOrder();
2954 
2955     public abstract void setRunOrder( String runOrder );
2956 
2957     public String[] getDependenciesToScan()
2958     {
2959         return dependenciesToScan;
2960     }
2961 
2962     public void setDependenciesToScan( String[] dependenciesToScan )
2963     {
2964         this.dependenciesToScan = dependenciesToScan;
2965     }
2966 
2967     public PluginDescriptor getPluginDescriptor()
2968     {
2969         return pluginDescriptor;
2970     }
2971 
2972     public MavenProject getProject()
2973     {
2974         return project;
2975     }
2976 
2977     @SuppressWarnings( "UnusedDeclaration" )
2978     public void setProject( MavenProject project )
2979     {
2980         this.project = project;
2981     }
2982 
2983     public File getTestSourceDirectory()
2984     {
2985         return testSourceDirectory;
2986     }
2987 
2988     public void setTestSourceDirectory( File testSourceDirectory )
2989     {
2990         this.testSourceDirectory = testSourceDirectory;
2991     }
2992 
2993     public String getForkCount()
2994     {
2995         return forkCount;
2996     }
2997 
2998     public boolean isReuseForks()
2999     {
3000         return reuseForks;
3001     }
3002 
3003     public String[] getAdditionalClasspathElements()
3004     {
3005         return additionalClasspathElements;
3006     }
3007 
3008     public void setAdditionalClasspathElements( String[] additionalClasspathElements )
3009     {
3010         this.additionalClasspathElements = additionalClasspathElements;
3011     }
3012 
3013     public String[] getClasspathDependencyExcludes()
3014     {
3015         return classpathDependencyExcludes;
3016     }
3017 
3018     public void setClasspathDependencyExcludes( String[] classpathDependencyExcludes )
3019     {
3020         this.classpathDependencyExcludes = classpathDependencyExcludes;
3021     }
3022 
3023     public String getClasspathDependencyScopeExclude()
3024     {
3025         return classpathDependencyScopeExclude;
3026     }
3027 
3028     public void setClasspathDependencyScopeExclude( String classpathDependencyScopeExclude )
3029     {
3030         this.classpathDependencyScopeExclude = classpathDependencyScopeExclude;
3031     }
3032 }