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