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