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