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