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