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