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