View Javadoc

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