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