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