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