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