1 package org.apache.maven.plugin.surefire;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
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.Iterator;
31 import java.util.LinkedHashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Properties;
35 import java.util.Set;
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
38 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
39 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
40 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
41 import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
42 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
43 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
44 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
45 import org.apache.maven.artifact.versioning.VersionRange;
46 import org.apache.maven.plugin.AbstractMojo;
47 import org.apache.maven.plugin.MojoExecutionException;
48 import org.apache.maven.plugin.MojoFailureException;
49 import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
50 import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
51 import org.apache.maven.plugin.surefire.booterclient.ForkStarter;
52 import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
53 import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
54 import org.apache.maven.surefire.booter.Classpath;
55 import org.apache.maven.surefire.booter.ClasspathConfiguration;
56 import org.apache.maven.surefire.booter.ProviderConfiguration;
57 import org.apache.maven.surefire.booter.StartupConfiguration;
58 import org.apache.maven.surefire.booter.StartupReportConfiguration;
59 import org.apache.maven.surefire.booter.SurefireBooterForkException;
60 import org.apache.maven.surefire.booter.SurefireExecutionException;
61 import org.apache.maven.surefire.report.ReporterConfiguration;
62 import org.apache.maven.surefire.suite.RunResult;
63 import org.apache.maven.surefire.testset.DirectoryScannerParameters;
64 import org.apache.maven.surefire.testset.RunOrderParameters;
65 import org.apache.maven.surefire.testset.TestArtifactInfo;
66 import org.apache.maven.surefire.testset.TestRequest;
67 import org.apache.maven.surefire.util.NestedRuntimeException;
68 import org.apache.maven.surefire.util.RunOrder;
69 import org.apache.maven.toolchain.Toolchain;
70 import org.codehaus.plexus.util.StringUtils;
71
72
73
74
75
76
77
78 public abstract class AbstractSurefireMojo
79 extends AbstractMojo
80 implements SurefireExecutionParameters
81 {
82
83
84
85
86
87 protected abstract String getPluginName();
88
89 private SurefireDependencyResolver dependencyResolver;
90
91 public void execute()
92 throws MojoExecutionException, MojoFailureException
93 {
94 if ( verifyParameters() && !hasExecutedBefore() )
95 {
96 logReportsDirectory();
97 executeAfterPreconditionsChecked();
98 }
99 }
100
101 boolean verifyParameters()
102 throws MojoFailureException
103 {
104 if ( isSkipExecution() )
105 {
106 getLog().info( "Tests are skipped." );
107 return false;
108 }
109
110 if ( !getTestClassesDirectory().exists() )
111 {
112 if ( Boolean.TRUE.equals( getFailIfNoTests() ) )
113 {
114 throw new MojoFailureException( "No tests to run!" );
115 }
116 getLog().info( "No tests to run." );
117 }
118 else
119 {
120 ensureWorkingDirectoryExists();
121 ensureParallelRunningCompatibility();
122 warnIfUselessUseSystemClassLoaderParameter();
123 }
124
125 return true;
126 }
127
128 protected abstract boolean isSkipExecution();
129
130 protected void executeAfterPreconditionsChecked()
131 throws MojoExecutionException, MojoFailureException
132 {
133 createDependencyResolver();
134 Summary summary = executeAllProviders();
135 restoreOriginalSystemPropertiesWhenNotForking( summary );
136 handleSummary( summary );
137 }
138
139 private Artifact surefireBooterArtifact;
140
141 private void createDependencyResolver()
142 {
143 dependencyResolver =
144 new SurefireDependencyResolver( getArtifactResolver(), getArtifactFactory(), getLog(), getLocalRepository(),
145 getRemoteRepositories(), getMetadataSource(), getPluginName() );
146 }
147
148 protected List createProviders()
149 throws MojoFailureException
150 {
151 try
152 {
153 final Artifact junitDepArtifact = getJunitDepArtifact();
154 ProviderList wellKnownProviders = new ProviderList(
155 new ProviderInfo[]{ new TestNgProviderInfo( getTestNgArtifact() ),
156 new JUnitCoreProviderInfo( getJunitArtifact(), junitDepArtifact ),
157 new JUnit4ProviderInfo( getJunitArtifact(), junitDepArtifact ), new JUnit3ProviderInfo() },
158 new DynamicProviderInfo( null ) );
159
160 return wellKnownProviders.resolve( getLog() );
161 }
162 catch ( InvalidVersionSpecificationException e )
163 {
164 throw new NestedRuntimeException( e );
165 }
166 }
167
168 private Summary executeAllProviders()
169 throws MojoExecutionException, MojoFailureException
170 {
171 List providers = createProviders();
172 Summary summary = new Summary();
173 for ( Iterator iter = providers.iterator(); iter.hasNext(); )
174 {
175 ProviderInfo provider = (ProviderInfo) iter.next();
176 executeProvider( provider, summary );
177 }
178 return summary;
179 }
180
181 private void executeProvider( ProviderInfo provider, Summary summary )
182 throws MojoExecutionException, MojoFailureException
183 {
184 ForkConfiguration forkConfiguration = getForkConfiguration();
185 summary.reportForkConfiguration( forkConfiguration );
186 ClassLoaderConfiguration classLoaderConfiguration = getClassLoaderConfiguration( forkConfiguration );
187 try
188 {
189 final RunResult result;
190 if ( ForkConfiguration.FORK_NEVER.equals( forkConfiguration.getForkMode() ) )
191 {
192 InPluginVMSurefireStarter surefireStarter =
193 createInprocessStarter( provider, forkConfiguration, classLoaderConfiguration );
194 result = surefireStarter.runSuitesInProcess();
195 }
196 else
197 {
198 ForkStarter forkStarter = createForkStarter( provider, forkConfiguration, classLoaderConfiguration );
199 result = forkStarter.run();
200 }
201 summary.registerRunResult( result );
202 }
203 catch ( SurefireBooterForkException e )
204 {
205 summary.registerException( e );
206 }
207 catch ( SurefireExecutionException e )
208 {
209 summary.registerException( e );
210 }
211 }
212
213 protected abstract void handleSummary( Summary summary )
214 throws MojoExecutionException, MojoFailureException;
215
216 protected void restoreOriginalSystemPropertiesWhenNotForking( Summary summary )
217 {
218 if ( ( getOriginalSystemProperties() != null ) && ( summary.isForking() ) )
219 {
220 System.setProperties( getOriginalSystemProperties() );
221 }
222 }
223
224 protected void logReportsDirectory()
225 {
226 getLog().info(
227 StringUtils.capitalizeFirstLetter( getPluginName() ) + " report directory: " + getReportsDirectory() );
228 }
229
230
231 final Toolchain getToolchain()
232 {
233 Toolchain tc = null;
234
235 if ( getToolchainManager() != null )
236 {
237 tc = getToolchainManager().getToolchainFromBuildContext( "jdk", getSession() );
238 }
239
240 return tc;
241 }
242
243
244
245
246
247 private void convertTestNGParameters()
248 {
249 if ( getProperties() == null )
250 {
251 setProperties( new Properties() );
252 }
253
254 if ( this.getParallel() != null )
255 {
256 getProperties().setProperty( "parallel", this.getParallel() );
257 }
258 convertGroupParameters();
259
260 if ( this.getThreadCount() > 0 )
261 {
262 getProperties().setProperty( "threadcount", Integer.toString( this.getThreadCount() ) );
263 }
264 if ( this.getObjectFactory() != null )
265 {
266 getProperties().setProperty( "objectfactory", this.getObjectFactory() );
267 }
268 if ( this.getTestClassesDirectory() != null )
269 {
270 getProperties().setProperty( "testng.test.classpath", getTestClassesDirectory().getAbsolutePath() );
271 }
272
273
274 }
275
276 private void convertGroupParameters()
277 {
278 if ( getProperties() == null )
279 {
280 setProperties( new Properties() );
281 }
282 if ( this.getExcludedGroups() != null )
283 {
284 getProperties().setProperty( "excludedgroups", this.getExcludedGroups() );
285 }
286 if ( this.getGroups() != null )
287 {
288 getProperties().setProperty( "groups", this.getGroups() );
289 }
290 }
291
292 protected boolean isAnyConcurrencySelected()
293 {
294 return this.getParallel() != null && this.getParallel().trim().length() > 0;
295 }
296
297 protected boolean isAnyGroupsSelected()
298 {
299 return this.getGroups() != null && this.getExcludedGroups() != null;
300 }
301
302
303
304
305
306 private void convertJunitCoreParameters()
307 {
308 if ( getProperties() == null )
309 {
310 setProperties( new Properties() );
311 }
312
313 if ( this.getParallel() != null )
314 {
315 getProperties().setProperty( "parallel", this.getParallel() );
316 }
317 if ( this.getThreadCount() > 0 )
318 {
319 getProperties().setProperty( "threadCount", Integer.toString( this.getThreadCount() ) );
320 }
321 getProperties().setProperty( "perCoreThreadCount", Boolean.toString( getPerCoreThreadCount() ) );
322 getProperties().setProperty( "useUnlimitedThreads", Boolean.toString( getUseUnlimitedThreads() ) );
323 }
324
325 private boolean isJunit47Compatible( Artifact artifact )
326 {
327 return dependencyResolver.isWithinVersionSpec( artifact, "[4.7,)" );
328 }
329
330 private boolean isAnyJunit4( Artifact artifact )
331 {
332 return dependencyResolver.isWithinVersionSpec( artifact, "[4.0,)" );
333 }
334
335 boolean isForkModeNever()
336 {
337 return ForkConfiguration.FORK_NEVER.equals( getForkMode() );
338 }
339
340 private java.util.List getRunOrders()
341 {
342 String runOrderString = getRunOrder();
343 RunOrder[] runOrder = runOrderString == null ? RunOrder.DEFAULT : RunOrder.valueOfMulti( runOrderString );
344 return Arrays.asList( runOrder );
345 }
346
347 private boolean requiresRunHistory()
348 {
349 final List runOrders = getRunOrders();
350 return runOrders.contains( RunOrder.BALANCED ) || runOrders.contains( RunOrder.FAILEDFIRST );
351 }
352
353 protected ProviderConfiguration createProviderConfiguration( String configurationHash )
354 throws MojoExecutionException, MojoFailureException
355 {
356 ReporterConfiguration reporterConfiguration =
357 new ReporterConfiguration( getReportsDirectory(), Boolean.valueOf( isTrimStackTrace() ) );
358
359 Artifact testNgArtifact;
360 try
361 {
362 testNgArtifact = getTestNgArtifact();
363 }
364 catch ( InvalidVersionSpecificationException e )
365 {
366 throw new MojoExecutionException( "Error determining the TestNG version requested: " + e.getMessage(), e );
367 }
368
369 DirectoryScannerParameters directoryScannerParameters = null;
370 final boolean isTestNg = testNgArtifact != null;
371 TestArtifactInfo testNg =
372 isTestNg ? new TestArtifactInfo( testNgArtifact.getVersion(), testNgArtifact.getClassifier() ) : null;
373 List testXml = getSuiteXmlFiles() != null ? Arrays.asList( getSuiteXmlFiles() ) : null;
374 TestRequest testSuiteDefinition =
375 new TestRequest( testXml, getTestSourceDirectory(), getTest(), getTestMethod() );
376 final boolean failIfNoTests;
377
378 if ( isValidSuiteXmlFileConfig() && getTest() == null )
379 {
380 failIfNoTests = getFailIfNoTests() != null && getFailIfNoTests().booleanValue();
381 if ( !isTestNg )
382 {
383 throw new MojoExecutionException( "suiteXmlFiles is configured, but there is no TestNG dependency" );
384 }
385 }
386 else
387 {
388 if ( isSpecificTestSpecified() && getFailIfNoTests() == null )
389 {
390 setFailIfNoTests( Boolean.TRUE );
391 }
392
393 failIfNoTests = getFailIfNoTests() != null && getFailIfNoTests().booleanValue();
394
395 List includes = getIncludeList();
396 List excludes = getExcludeList();
397 directoryScannerParameters = new DirectoryScannerParameters( getTestClassesDirectory(), includes, excludes,
398 Boolean.valueOf( failIfNoTests ),
399 getRunOrder() );
400 }
401
402 Properties providerProperties = getProperties();
403 if ( providerProperties == null )
404 {
405 providerProperties = new Properties();
406 }
407
408 RunOrderParameters runOrderParameters =
409 new RunOrderParameters( getRunOrder(), getStatisticsFileName( configurationHash ) );
410
411 return new ProviderConfiguration( directoryScannerParameters, runOrderParameters, failIfNoTests,
412 reporterConfiguration, testNg, testSuiteDefinition, providerProperties,
413 null );
414 }
415
416 public File getStatisticsFile( String configurationHash )
417 {
418 return new File( getStatisticsFileName( configurationHash ) );
419 }
420
421 public String getStatisticsFileName( String configurationHash )
422 {
423 return getReportsDirectory().getParentFile().getParentFile() + File.separator + ".surefire-"
424 + configurationHash;
425 }
426
427
428 StartupConfiguration createStartupConfiguration( ForkConfiguration forkConfiguration, ProviderInfo provider,
429 ClassLoaderConfiguration classLoaderConfiguration )
430 throws MojoExecutionException, MojoFailureException
431 {
432
433 try
434 {
435 provider.addProviderProperties();
436 String providerName = provider.getProviderName();
437 Classpath providerClasspath = provider.getProviderClasspath();
438 Classpath inprocClassPath = new Classpath( providerClasspath );
439 Artifact surefireArtifact = getCommonArtifact();
440 inprocClassPath.addClassPathElementUrl( surefireArtifact.getFile().getAbsolutePath() );
441
442 final Classpath testClasspath = generateTestClasspath();
443
444 logClasspath( testClasspath, "test classpath" );
445 logClasspath( providerClasspath, "provider classpath" );
446 final ClasspathConfiguration classpathConfiguration =
447 new ClasspathConfiguration( testClasspath, providerClasspath, inprocClassPath, isEnableAssertions(),
448 isChildDelegation() );
449
450 return new StartupConfiguration( providerName, classpathConfiguration, classLoaderConfiguration,
451 forkConfiguration.getForkMode(), false );
452 }
453 catch ( ArtifactResolutionException e )
454 {
455 throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
456 }
457 catch ( ArtifactNotFoundException e )
458 {
459 throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
460 }
461 catch ( InvalidVersionSpecificationException e )
462 {
463 throw new MojoExecutionException( "Unable to generate classpath: " + e, e );
464 }
465
466 }
467
468 private Artifact getCommonArtifact()
469 {
470 return (Artifact) getPluginArtifactMap().get( "org.apache.maven.surefire:maven-surefire-common" );
471 }
472
473 private StartupReportConfiguration getStartupReportConfiguration( String configChecksum )
474 {
475 return new StartupReportConfiguration( isUseFile(), isPrintSummary(), getReportFormat(),
476 isRedirectTestOutputToFile(), isDisableXmlReport(),
477 getReportsDirectory(), isTrimStackTrace(), getReportNameSuffix(),
478 configChecksum, requiresRunHistory() );
479 }
480
481 void logClasspath( Classpath classpath, String descriptor )
482 {
483 getLog().debug( descriptor + " classpath:" );
484 for ( Iterator i = classpath.getClassPath().iterator(); i.hasNext(); )
485 {
486 String classpathElement = (String) i.next();
487 if ( classpathElement == null )
488 {
489 getLog().warn( "The test classpath contains a null element." );
490 }
491 else
492 {
493 getLog().debug( " " + classpathElement );
494 }
495 }
496 }
497
498
499 private boolean isSpecificTestSpecified()
500 {
501 return getTest() != null;
502 }
503
504 private boolean isValidSuiteXmlFileConfig()
505 {
506 return getSuiteXmlFiles() != null && getSuiteXmlFiles().length > 0;
507 }
508
509 private List getExcludeList()
510 {
511 List excludes;
512 if ( isSpecificTestSpecified() )
513 {
514
515
516
517
518 excludes = new ArrayList();
519 }
520 else
521 {
522
523 excludes = this.getExcludes();
524
525
526
527 if ( excludes == null || excludes.size() == 0 )
528 {
529 excludes = new ArrayList( Arrays.asList( new String[]{ "**/*$*" } ) );
530 }
531 }
532 return excludes;
533 }
534
535 private List getIncludeList()
536 {
537 List includes;
538 if ( isSpecificTestSpecified() )
539 {
540
541
542
543
544
545 includes = new ArrayList();
546
547 String[] testRegexes = StringUtils.split( getTest(), "," );
548
549 for ( int i = 0; i < testRegexes.length; i++ )
550 {
551 String testRegex = testRegexes[i];
552 if ( testRegex.endsWith( ".java" ) )
553 {
554 testRegex = testRegex.substring( 0, testRegex.length() - 5 );
555 }
556
557 testRegex = testRegex.replace( '.', '/' );
558 includes.add( "**/" + testRegex + ".java" );
559 }
560 }
561 else
562 {
563 includes = this.getIncludes();
564
565
566
567 if ( includes == null || includes.size() == 0 )
568 {
569 includes = new ArrayList( Arrays.asList( getDefaultIncludes() ) );
570 }
571 }
572 return includes;
573 }
574
575 private Artifact getTestNgArtifact()
576 throws MojoFailureException, InvalidVersionSpecificationException
577 {
578
579 Artifact artifact = (Artifact) getProjectArtifactMap().get( getTestNGArtifactName() );
580
581 if ( artifact != null )
582 {
583 VersionRange range = VersionRange.createFromVersionSpec( "[4.7,)" );
584 if ( !range.containsVersion( new DefaultArtifactVersion( artifact.getVersion() ) ) )
585 {
586 throw new MojoFailureException(
587 "TestNG support requires version 4.7 or above. You have declared version "
588 + artifact.getVersion() );
589 }
590 }
591 return artifact;
592
593 }
594
595 private Artifact getJunitArtifact()
596 {
597 return (Artifact) getProjectArtifactMap().get( getJunitArtifactName() );
598 }
599
600 private Artifact getJunitDepArtifact()
601 {
602 return (Artifact) getProjectArtifactMap().get( "junit:junit-dep" );
603 }
604
605 protected ForkStarter createForkStarter( ProviderInfo provider, ForkConfiguration forkConfiguration,
606 ClassLoaderConfiguration classLoaderConfiguration )
607 throws MojoExecutionException, MojoFailureException
608 {
609 StartupConfiguration startupConfiguration =
610 createStartupConfiguration( forkConfiguration, provider, classLoaderConfiguration );
611 String configChecksum = getConfigChecksum();
612 StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum );
613 ProviderConfiguration providerConfiguration = createProviderConfiguration( configChecksum );
614 return new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
615 getForkedProcessTimeoutInSeconds(), startupReportConfiguration );
616 }
617
618 protected InPluginVMSurefireStarter createInprocessStarter( ProviderInfo provider,
619 ForkConfiguration forkConfiguration,
620 ClassLoaderConfiguration classLoaderConfiguration )
621 throws MojoExecutionException, MojoFailureException
622 {
623 StartupConfiguration startupConfiguration =
624 createStartupConfiguration( forkConfiguration, provider, classLoaderConfiguration );
625 String configChecksum = getConfigChecksum();
626 StartupReportConfiguration startupReportConfiguration = getStartupReportConfiguration( configChecksum );
627 ProviderConfiguration providerConfiguration = createProviderConfiguration( configChecksum );
628 return new InPluginVMSurefireStarter( startupConfiguration, providerConfiguration, startupReportConfiguration );
629
630 }
631
632 protected ForkConfiguration getForkConfiguration()
633 {
634 File tmpDir = getSurefireTempDir();
635
636 tmpDir.mkdirs();
637
638 Artifact shadeFire = (Artifact) getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-shadefire" );
639
640 surefireBooterArtifact = (Artifact) getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
641 if ( surefireBooterArtifact == null )
642 {
643 throw new RuntimeException( "Unable to locate surefire-booter in the list of plugin artifacts" );
644 }
645
646 surefireBooterArtifact.isSnapshot();
647
648 final Classpath bootClasspathConfiguration =
649 getArtifactClasspath( shadeFire != null ? shadeFire : surefireBooterArtifact );
650
651 ForkConfiguration fork = new ForkConfiguration( bootClasspathConfiguration, getForkMode(), tmpDir );
652
653 fork.setTempDirectory( tmpDir );
654
655 processSystemProperties( !fork.isForking() );
656
657 verifyLegalSystemProperties();
658
659 if ( getLog().isDebugEnabled() )
660 {
661 showMap( getInternalSystemProperties(), "system property" );
662 }
663
664 Toolchain tc = getToolchain();
665
666 if ( tc != null )
667 {
668 getLog().info( "Toolchain in " + getPluginName() + "-plugin: " + tc );
669 if ( isForkModeNever() )
670 {
671 setForkMode( ForkConfiguration.FORK_ONCE );
672 }
673 if ( getJvm() != null )
674 {
675 getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + getJvm() );
676 }
677 else
678 {
679 setJvm( tc.findTool( "java" ) );
680 }
681 }
682
683 if ( fork.isForking() )
684 {
685 setUseSystemClassLoader( isUseSystemClassLoader() );
686
687 fork.setSystemProperties( getInternalSystemProperties() );
688
689 if ( "true".equals( getDebugForkedProcess() ) )
690 {
691 setDebugForkedProcess(
692 "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005" );
693 }
694
695 fork.setDebugLine( getDebugForkedProcess() );
696
697 if ( ( getJvm() == null || "".equals( getJvm() ) ) )
698 {
699
700 setJvm( System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java" );
701 getLog().debug( "Using JVM: " + getJvm() );
702 }
703
704 fork.setJvmExecutable( getJvm() );
705
706 if ( getWorkingDirectory() != null )
707 {
708 fork.setWorkingDirectory( getWorkingDirectory() );
709 }
710 else
711 {
712 fork.setWorkingDirectory( getBasedir() );
713 }
714
715 fork.setArgLine( getArgLine() );
716
717 fork.setEnvironmentVariables( getEnvironmentVariables() );
718
719 if ( getLog().isDebugEnabled() )
720 {
721 showMap( getEnvironmentVariables(), "environment variable" );
722
723 fork.setDebug( true );
724 }
725
726 if ( getArgLine() != null )
727 {
728 List args = Arrays.asList( getArgLine().split( " " ) );
729 if ( args.contains( "-da" ) || args.contains( "-disableassertions" ) )
730 {
731 setEnableAssertions( false );
732 }
733 }
734 }
735 return fork;
736 }
737
738 private void verifyLegalSystemProperties()
739 {
740 final Properties properties = getInternalSystemProperties();
741 Iterator iter = properties.keySet().iterator();
742
743 while ( iter.hasNext() )
744 {
745 String key = (String) iter.next();
746
747 if ( "java.library.path".equals( key ) )
748 {
749 getLog().warn(
750 "java.library.path cannot be set as system property, use <argLine>-Djava.library.path=...<argLine> instead" );
751 }
752 }
753 }
754
755
756
757
758
759
760
761 private File getSurefireTempDir()
762 {
763 return new File( getReportsDirectory().getParentFile(), "surefire" );
764 }
765
766 private String getConfigChecksum()
767 {
768 ChecksumCalculator checksum = new ChecksumCalculator();
769 checksum.add( getPluginName() );
770 checksum.add( isSkipTests() );
771 checksum.add( isSkipExec() );
772 checksum.add( isSkip() );
773 checksum.add( getTestClassesDirectory() );
774 checksum.add( getClassesDirectory() );
775 checksum.add( getClasspathDependencyExcludes() );
776 checksum.add( getClasspathDependencyScopeExclude() );
777 checksum.add( getAdditionalClasspathElements() );
778 checksum.add( getReportsDirectory() );
779 checksum.add( getTestSourceDirectory() );
780 checksum.add( getTest() );
781 checksum.add( getIncludes() );
782 checksum.add( getExcludes() );
783 checksum.add( getLocalRepository() );
784 checksum.add( getSystemProperties() );
785 checksum.add( getSystemPropertyVariables() );
786 checksum.add( getSystemPropertiesFile() );
787 checksum.add( getProperties() );
788 checksum.add( isPrintSummary() );
789 checksum.add( getReportFormat() );
790 checksum.add( getReportNameSuffix() );
791 checksum.add( isUseFile() );
792 checksum.add( isRedirectTestOutputToFile() );
793 checksum.add( getForkMode() );
794 checksum.add( getJvm() );
795 checksum.add( getArgLine() );
796 checksum.add( getDebugForkedProcess() );
797 checksum.add( getForkedProcessTimeoutInSeconds() );
798 checksum.add( getEnvironmentVariables() );
799 checksum.add( getWorkingDirectory() );
800 checksum.add( isChildDelegation() );
801 checksum.add( getGroups() );
802 checksum.add( getExcludedGroups() );
803 checksum.add( getSuiteXmlFiles() );
804 checksum.add( getJunitArtifact() );
805 checksum.add( getTestNGArtifactName() );
806 checksum.add( getThreadCount() );
807 checksum.add( getPerCoreThreadCount() );
808 checksum.add( getUseUnlimitedThreads() );
809 checksum.add( getParallel() );
810 checksum.add( isTrimStackTrace() );
811 checksum.add( getRemoteRepositories() );
812 checksum.add( isDisableXmlReport() );
813 checksum.add( isUseSystemClassLoader() );
814 checksum.add( isUseManifestOnlyJar() );
815 checksum.add( isEnableAssertions() );
816 checksum.add( getObjectFactory() );
817 checksum.add( getFailIfNoTests() );
818 checksum.add( getRunOrder() );
819 addPluginSpecificChecksumItems( checksum );
820 return checksum.getSha1();
821
822 }
823
824 protected abstract void addPluginSpecificChecksumItems( ChecksumCalculator checksum );
825
826 protected boolean hasExecutedBefore()
827 {
828
829 String configChecksum = getConfigChecksum();
830 Map pluginContext = getPluginContext();
831 if ( pluginContext.containsKey( configChecksum ) )
832 {
833 getLog().info( "Skipping execution of surefire because it has already been run for this configuration" );
834 return true;
835 }
836 pluginContext.put( configChecksum, configChecksum );
837
838 return false;
839 }
840
841 protected ClassLoaderConfiguration getClassLoaderConfiguration( ForkConfiguration fork )
842 {
843 return fork.isForking()
844 ? new ClassLoaderConfiguration( isUseSystemClassLoader(), isUseManifestOnlyJar() )
845 : new ClassLoaderConfiguration( false, false );
846 }
847
848 protected abstract String[] getDefaultIncludes();
849
850
851
852
853
854
855
856
857
858
859
860 Classpath generateTestClasspath()
861 throws InvalidVersionSpecificationException, MojoFailureException, ArtifactResolutionException,
862 ArtifactNotFoundException
863 {
864 List classpath = new ArrayList( 2 + getProject().getArtifacts().size() );
865
866 classpath.add( getTestClassesDirectory().getAbsolutePath() );
867
868 classpath.add( getClassesDirectory().getAbsolutePath() );
869
870 Set classpathArtifacts = getProject().getArtifacts();
871
872 if ( getClasspathDependencyScopeExclude() != null && !getClasspathDependencyScopeExclude().equals( "" ) )
873 {
874 ArtifactFilter dependencyFilter = new ScopeArtifactFilter( getClasspathDependencyScopeExclude() );
875 classpathArtifacts = this.filterArtifacts( classpathArtifacts, dependencyFilter );
876 }
877
878 if ( getClasspathDependencyExcludes() != null )
879 {
880 ArtifactFilter dependencyFilter = new PatternIncludesArtifactFilter( getClasspathDependencyExcludes() );
881 classpathArtifacts = this.filterArtifacts( classpathArtifacts, dependencyFilter );
882 }
883
884 for ( Iterator iter = classpathArtifacts.iterator(); iter.hasNext(); )
885 {
886 Artifact artifact = (Artifact) iter.next();
887 if ( artifact.getArtifactHandler().isAddedToClasspath() )
888 {
889 File file = artifact.getFile();
890 if ( file != null )
891 {
892 classpath.add( file.getPath() );
893 }
894 }
895 }
896
897
898 if ( getAdditionalClasspathElements() != null )
899 {
900 for ( Iterator iter = getAdditionalClasspathElements().iterator(); iter.hasNext(); )
901 {
902 String classpathElement = (String) iter.next();
903 if ( classpathElement != null )
904 {
905 classpath.add( classpathElement );
906 }
907 }
908 }
909
910
911
912 if ( getTestNgArtifact() != null )
913 {
914 Artifact testNgUtils = getTestNgUtilsArtifact();
915 String path = testNgUtils.getFile().getPath();
916 classpath.add( path );
917
918 }
919
920 return new Classpath( classpath );
921 }
922
923 Artifact getTestNgUtilsArtifact()
924 throws ArtifactResolutionException, ArtifactNotFoundException
925 {
926 Artifact surefireArtifact =
927 (Artifact) getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
928 String surefireVersion = surefireArtifact.getBaseVersion();
929 Artifact testNgUtils =
930 getArtifactFactory().createArtifact( "org.apache.maven.surefire", "surefire-testng-utils", surefireVersion,
931 "runtime", "jar" );
932
933 getArtifactResolver().resolve( testNgUtils, getRemoteRepositories(), getLocalRepository() );
934 return testNgUtils;
935 }
936
937
938
939
940
941
942
943
944 private Set filterArtifacts( Set artifacts, ArtifactFilter filter )
945 {
946 Set filteredArtifacts = new LinkedHashSet();
947
948 for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
949 {
950 Artifact artifact = (Artifact) iter.next();
951 if ( !filter.include( artifact ) )
952 {
953 filteredArtifacts.add( artifact );
954 }
955 }
956
957 return filteredArtifacts;
958 }
959
960 private void showMap( Map map, String setting )
961 {
962 for ( Iterator i = map.keySet().iterator(); i.hasNext(); )
963 {
964 String key = (String) i.next();
965 String value = (String) map.get( key );
966 getLog().debug( "Setting " + setting + " [" + key + "]=[" + value + "]" );
967 }
968 }
969
970
971 private ArtifactResolutionResult resolveArtifact( Artifact filteredArtifact, Artifact providerArtifact )
972 {
973 ArtifactFilter filter = null;
974 if ( filteredArtifact != null )
975 {
976 filter = new ExcludesArtifactFilter(
977 Collections.singletonList( filteredArtifact.getGroupId() + ":" + filteredArtifact.getArtifactId() ) );
978 }
979
980 Artifact originatingArtifact = getArtifactFactory().createBuildArtifact( "dummy", "dummy", "1.0", "jar" );
981
982 try
983 {
984 return getArtifactResolver().resolveTransitively( Collections.singleton( providerArtifact ),
985 originatingArtifact, getLocalRepository(),
986 getRemoteRepositories(), getMetadataSource(), filter );
987 }
988 catch ( ArtifactResolutionException e )
989 {
990 throw new NestedRuntimeException( e );
991 }
992 catch ( ArtifactNotFoundException e )
993 {
994 throw new NestedRuntimeException( e );
995 }
996 }
997
998 private Classpath getArtifactClasspath( Artifact surefireArtifact )
999 {
1000 ArtifactResolutionResult result = resolveArtifact( null, surefireArtifact );
1001
1002 List items = new ArrayList();
1003 for ( Iterator i = result.getArtifacts().iterator(); i.hasNext(); )
1004 {
1005 Artifact artifact = (Artifact) i.next();
1006
1007 getLog().debug(
1008 "Adding to " + getPluginName() + " booter test classpath: " + artifact.getFile().getAbsolutePath() +
1009 " Scope: " + artifact.getScope() );
1010
1011 items.add( artifact.getFile().getAbsolutePath() );
1012 }
1013 return new Classpath( items );
1014 }
1015
1016 void processSystemProperties( boolean setInSystem )
1017 {
1018 copyPropertiesToInternalSystemProperties( getSystemProperties() );
1019
1020 if ( this.getSystemPropertiesFile() != null )
1021 {
1022 Properties props = new Properties();
1023 try
1024 {
1025 FileInputStream fis = new FileInputStream( getSystemPropertiesFile() );
1026 props.load( fis );
1027 fis.close();
1028 }
1029 catch ( IOException e )
1030 {
1031 String msg =
1032 "The system property file '" + getSystemPropertiesFile().getAbsolutePath() + "' can't be read.";
1033 if ( getLog().isDebugEnabled() )
1034 {
1035 getLog().warn( msg, e );
1036 }
1037 else
1038 {
1039 getLog().warn( msg );
1040 }
1041 }
1042
1043 Enumeration keys = props.propertyNames();
1044
1045 while ( keys.hasMoreElements() )
1046 {
1047 String key = (String) keys.nextElement();
1048 String value = props.getProperty( key );
1049 getInternalSystemProperties().setProperty( key, value );
1050 }
1051 }
1052
1053 if ( this.getSystemPropertyVariables() != null )
1054 {
1055 for ( Iterator i = getSystemPropertyVariables().keySet().iterator(); i.hasNext(); )
1056 {
1057 String key = (String) i.next();
1058 String value = (String) getSystemPropertyVariables().get( key );
1059
1060 if ( value != null )
1061 {
1062 getInternalSystemProperties().setProperty( key, value );
1063 }
1064 }
1065 }
1066
1067 setOriginalSystemProperties( (Properties) System.getProperties().clone() );
1068
1069
1070
1071
1072
1073
1074 copyPropertiesToInternalSystemProperties( getUserProperties() );
1075
1076 getInternalSystemProperties().setProperty( "basedir", getBasedir().getAbsolutePath() );
1077 getInternalSystemProperties().setProperty( "user.dir", getWorkingDirectory().getAbsolutePath() );
1078 getInternalSystemProperties().setProperty( "localRepository", getLocalRepository().getBasedir() );
1079
1080 if ( setInSystem )
1081 {
1082
1083 Iterator iter = getInternalSystemProperties().keySet().iterator();
1084
1085 while ( iter.hasNext() )
1086 {
1087 String key = (String) iter.next();
1088
1089 String value = getInternalSystemProperties().getProperty( key );
1090
1091 System.setProperty( key, value );
1092 }
1093 }
1094 }
1095
1096 private void copyPropertiesToInternalSystemProperties( Properties properties )
1097 {
1098 if ( properties != null )
1099 {
1100 for ( Iterator i = properties.keySet().iterator(); i.hasNext(); )
1101 {
1102 String key = (String) i.next();
1103 String value = properties.getProperty( key );
1104 getInternalSystemProperties().setProperty( key, value );
1105 }
1106 }
1107 }
1108
1109 private Properties getUserProperties()
1110 {
1111 Properties props = null;
1112 try
1113 {
1114
1115 Method getUserProperties = getSession().getClass().getMethod( "getUserProperties", null );
1116 props = (Properties) getUserProperties.invoke( getSession(), null );
1117 }
1118 catch ( Exception e )
1119 {
1120 String msg = "Build uses Maven 2.0.x, cannot propagate system properties"
1121 + " from command line to tests (cf. SUREFIRE-121)";
1122 if ( getLog().isDebugEnabled() )
1123 {
1124 getLog().warn( msg, e );
1125 }
1126 else
1127 {
1128 getLog().warn( msg );
1129 }
1130 }
1131 if ( props == null )
1132 {
1133 props = new Properties();
1134 }
1135 return props;
1136 }
1137
1138
1139 void ensureWorkingDirectoryExists()
1140 throws MojoFailureException
1141 {
1142 if ( getWorkingDirectory() == null )
1143 {
1144 throw new MojoFailureException( "workingDirectory cannot be null" );
1145 }
1146
1147 if ( !getWorkingDirectory().exists() )
1148 {
1149 if ( !getWorkingDirectory().mkdirs() )
1150 {
1151 throw new MojoFailureException( "Cannot create workingDirectory " + getWorkingDirectory() );
1152 }
1153 }
1154
1155 if ( !getWorkingDirectory().isDirectory() )
1156 {
1157 throw new MojoFailureException(
1158 "workingDirectory " + getWorkingDirectory() + " exists and is not a directory" );
1159 }
1160 }
1161
1162 void ensureParallelRunningCompatibility()
1163 throws MojoFailureException
1164 {
1165 if ( isMavenParallel() && isForkModeNever() )
1166 {
1167 throw new MojoFailureException( "parallel maven execution is not compatible with surefire forkmode NEVER" );
1168 }
1169 }
1170
1171 void warnIfUselessUseSystemClassLoaderParameter()
1172 {
1173 if ( isUseSystemClassLoader() && isForkModeNever() )
1174 {
1175 getLog().warn( "useSystemClassloader setting has no effect when not forking" );
1176 }
1177 }
1178
1179 class TestNgProviderInfo
1180 implements ProviderInfo
1181 {
1182 private final Artifact testNgArtifact;
1183
1184 TestNgProviderInfo( Artifact testNgArtifact )
1185 {
1186 this.testNgArtifact = testNgArtifact;
1187 }
1188
1189 public String getProviderName()
1190 {
1191 return "org.apache.maven.surefire.testng.TestNGProvider";
1192 }
1193
1194 public boolean isApplicable()
1195 {
1196 return testNgArtifact != null;
1197 }
1198
1199 public void addProviderProperties()
1200 {
1201 convertTestNGParameters();
1202 }
1203
1204 public Classpath getProviderClasspath()
1205 throws ArtifactResolutionException, ArtifactNotFoundException
1206 {
1207 Artifact surefireArtifact =
1208 (Artifact) getPluginArtifactMap().get( "org.apache.maven.surefire:surefire-booter" );
1209 return dependencyResolver.getProviderClasspath( "surefire-testng", surefireArtifact.getBaseVersion(),
1210 testNgArtifact );
1211 }
1212 }
1213
1214 class JUnit3ProviderInfo
1215 implements ProviderInfo
1216 {
1217 public String getProviderName()
1218 {
1219 return "org.apache.maven.surefire.junit.JUnit3Provider";
1220 }
1221
1222 public boolean isApplicable()
1223 {
1224 return true;
1225 }
1226
1227 public void addProviderProperties()
1228 {
1229 }
1230
1231 public Classpath getProviderClasspath()
1232 throws ArtifactResolutionException, ArtifactNotFoundException
1233 {
1234
1235
1236 return dependencyResolver.getProviderClasspath( "surefire-junit3", surefireBooterArtifact.getBaseVersion(),
1237 null );
1238
1239 }
1240
1241 }
1242
1243 class JUnit4ProviderInfo
1244 implements ProviderInfo
1245 {
1246 private final Artifact junitArtifact;
1247
1248 private final Artifact junitDepArtifact;
1249
1250 JUnit4ProviderInfo( Artifact junitArtifact, Artifact junitDepArtifact )
1251 {
1252 this.junitArtifact = junitArtifact;
1253 this.junitDepArtifact = junitDepArtifact;
1254 }
1255
1256 public String getProviderName()
1257 {
1258 return "org.apache.maven.surefire.junit4.JUnit4Provider";
1259 }
1260
1261 public boolean isApplicable()
1262 {
1263 return junitDepArtifact != null || isAnyJunit4( junitArtifact );
1264 }
1265
1266 public void addProviderProperties()
1267 {
1268 }
1269
1270 public Classpath getProviderClasspath()
1271 throws ArtifactResolutionException, ArtifactNotFoundException
1272 {
1273 return dependencyResolver.getProviderClasspath( "surefire-junit4", surefireBooterArtifact.getBaseVersion(),
1274 null );
1275
1276 }
1277
1278 }
1279
1280 class JUnitCoreProviderInfo
1281 implements ProviderInfo
1282 {
1283 private final Artifact junitArtifact;
1284
1285 private final Artifact junitDepArtifact;
1286
1287 JUnitCoreProviderInfo( Artifact junitArtifact, Artifact junitDepArtifact )
1288 {
1289 this.junitArtifact = junitArtifact;
1290 this.junitDepArtifact = junitDepArtifact;
1291 }
1292
1293 public String getProviderName()
1294 {
1295 return "org.apache.maven.surefire.junitcore.JUnitCoreProvider";
1296 }
1297
1298 private boolean is47CompatibleJunitDep()
1299 {
1300 return junitDepArtifact != null && isJunit47Compatible( junitDepArtifact );
1301 }
1302
1303 public boolean isApplicable()
1304 {
1305 final boolean isJunitArtifact47 = isAnyJunit4( junitArtifact ) && isJunit47Compatible( junitArtifact );
1306 final boolean isAny47ProvidersForcers = isAnyConcurrencySelected() || isAnyGroupsSelected();
1307 return isAny47ProvidersForcers && ( isJunitArtifact47 || is47CompatibleJunitDep() );
1308 }
1309
1310 public void addProviderProperties()
1311 {
1312 convertJunitCoreParameters();
1313 convertGroupParameters();
1314 }
1315
1316 public Classpath getProviderClasspath()
1317 throws ArtifactResolutionException, ArtifactNotFoundException
1318 {
1319 return dependencyResolver.getProviderClasspath( "surefire-junit47", surefireBooterArtifact.getBaseVersion(),
1320 null );
1321 }
1322
1323 }
1324
1325 public class DynamicProviderInfo
1326 implements ConfigurableProviderInfo
1327 {
1328 final String providerName;
1329
1330 DynamicProviderInfo( String providerName )
1331 {
1332 this.providerName = providerName;
1333 }
1334
1335 public ProviderInfo instantiate( String providerName )
1336 {
1337 return new DynamicProviderInfo( providerName );
1338 }
1339
1340 public String getProviderName()
1341 {
1342 return providerName;
1343 }
1344
1345 public boolean isApplicable()
1346 {
1347 return true;
1348 }
1349
1350 public void addProviderProperties()
1351 {
1352
1353 convertJunitCoreParameters();
1354 convertTestNGParameters();
1355 }
1356
1357
1358 public Classpath getProviderClasspath()
1359 throws ArtifactResolutionException, ArtifactNotFoundException
1360 {
1361 final Map pluginArtifactMap = getPluginArtifactMap();
1362 Artifact plugin = (Artifact) pluginArtifactMap.get( "org.apache.maven.plugins:maven-surefire-plugin" );
1363 return dependencyResolver.addProviderToClasspath( pluginArtifactMap, plugin );
1364 }
1365
1366 }
1367
1368 }