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