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