1 package org.apache.maven.plugin.surefire.booterclient;
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.IOException;
24 import java.util.Iterator;
25 import java.util.Properties;
26 import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
27 import org.apache.maven.plugin.surefire.booterclient.output.ThreadedStreamConsumer;
28 import org.apache.maven.plugin.surefire.report.FileReporterFactory;
29 import org.apache.maven.surefire.booter.Classpath;
30 import org.apache.maven.surefire.booter.ClasspathConfiguration;
31 import org.apache.maven.surefire.booter.ProviderConfiguration;
32 import org.apache.maven.surefire.booter.ProviderFactory;
33 import org.apache.maven.surefire.booter.StartupConfiguration;
34 import org.apache.maven.surefire.booter.StartupReportConfiguration;
35 import org.apache.maven.surefire.booter.SurefireBooterForkException;
36 import org.apache.maven.surefire.booter.SurefireExecutionException;
37 import org.apache.maven.surefire.booter.SurefireReflector;
38 import org.apache.maven.surefire.booter.SystemPropertyManager;
39 import org.apache.maven.surefire.providerapi.SurefireProvider;
40 import org.apache.maven.surefire.report.ReporterFactory;
41 import org.apache.maven.surefire.report.RunStatistics;
42 import org.apache.maven.surefire.suite.RunResult;
43 import org.codehaus.plexus.util.cli.CommandLineException;
44 import org.codehaus.plexus.util.cli.CommandLineTimeOutException;
45 import org.codehaus.plexus.util.cli.CommandLineUtils;
46 import org.codehaus.plexus.util.cli.Commandline;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public class ForkStarter
65 {
66 private final int forkedProcessTimeoutInSeconds;
67
68 private final ProviderConfiguration providerConfiguration;
69
70 private final StartupConfiguration startupConfiguration;
71
72 private final ForkConfiguration forkConfiguration;
73
74 private final StartupReportConfiguration startupReportConfiguration;
75
76 public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
77 ForkConfiguration forkConfiguration, int forkedProcessTimeoutInSeconds,
78 StartupReportConfiguration startupReportConfiguration )
79 {
80 this.forkConfiguration = forkConfiguration;
81 this.providerConfiguration = providerConfiguration;
82 this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
83 this.startupConfiguration = startupConfiguration;
84 this.startupReportConfiguration = startupReportConfiguration;
85 }
86
87 public RunResult run()
88 throws SurefireBooterForkException, SurefireExecutionException
89 {
90 final RunResult result;
91
92 final String requestedForkMode = forkConfiguration.getForkMode();
93 final FileReporterFactory fileReporterFactory = new FileReporterFactory( startupReportConfiguration );
94 try
95 {
96 if ( ForkConfiguration.FORK_ONCE.equals( requestedForkMode ) )
97 {
98 result = fork( null, providerConfiguration.getProviderProperties(), fileReporterFactory );
99 }
100 else if ( ForkConfiguration.FORK_ALWAYS.equals( requestedForkMode ) )
101 {
102 result = runSuitesForkPerTestSet( fileReporterFactory );
103 }
104 else
105 {
106 throw new SurefireExecutionException( "Unknown forkmode: " + requestedForkMode, null );
107 }
108 }
109 finally
110 {
111 fileReporterFactory.close();
112 }
113 return result;
114 }
115
116 private RunResult runSuitesForkPerTestSet( FileReporterFactory fileReporterFactory )
117 throws SurefireBooterForkException
118 {
119 RunResult globalResult = new RunResult( 0, 0, 0, 0 );
120
121 final Iterator suites = getSuitesIterator();
122
123 Properties properties = new Properties();
124
125 while ( suites.hasNext() )
126 {
127 Object testSet = suites.next();
128 RunResult runResult = fork( testSet, properties, fileReporterFactory );
129 globalResult = globalResult.aggregate( runResult );
130 }
131
132 return globalResult;
133 }
134
135 private RunResult fork( Object testSet, Properties properties, ReporterFactory testSetReporterFactory )
136 throws SurefireBooterForkException
137 {
138 File surefireProperties;
139 File systemProperties = null;
140 try
141 {
142 BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration, properties );
143
144 surefireProperties = booterSerializer.serialize( providerConfiguration, startupConfiguration, testSet,
145 forkConfiguration.getForkMode() );
146
147 if ( forkConfiguration.getSystemProperties() != null )
148 {
149 systemProperties = SystemPropertyManager.writePropertiesFile( forkConfiguration.getSystemProperties(),
150 forkConfiguration.getTempDirectory(),
151 "surefire", forkConfiguration.isDebug() );
152 }
153 }
154 catch ( IOException e )
155 {
156 throw new SurefireBooterForkException( "Error creating properties files for forking", e );
157 }
158
159 final Classpath bootClasspathConfiguration = forkConfiguration.getBootClasspath();
160 final Classpath additionlClassPathUrls = startupConfiguration.useSystemClassLoader()
161 ? startupConfiguration.getClasspathConfiguration().getTestClasspath()
162 : null;
163
164 Classpath bootClasspath = Classpath.join( bootClasspathConfiguration, additionlClassPathUrls );
165
166 Commandline cli = forkConfiguration.createCommandLine( bootClasspath.getClassPath(),
167 startupConfiguration.getClassLoaderConfiguration(),
168 startupConfiguration.isShadefire() );
169
170 cli.createArg().setFile( surefireProperties );
171
172 if ( systemProperties != null )
173 {
174 cli.createArg().setFile( systemProperties );
175 }
176
177 ForkClient out =
178 new ForkClient( testSetReporterFactory, startupReportConfiguration.getTestVmSystemProperties() );
179 ThreadedStreamConsumer threadedStreamConsumer2 = new ThreadedStreamConsumer( out );
180
181 if ( forkConfiguration.isDebug() )
182 {
183 System.out.println( "Forking command line: " + cli );
184 }
185
186 RunResult runResult;
187
188 try
189 {
190 final int timeout = forkedProcessTimeoutInSeconds > 0 ? forkedProcessTimeoutInSeconds : 0;
191 CommandLineUtils.executeCommandLine( cli, threadedStreamConsumer2, threadedStreamConsumer2, timeout );
192
193 threadedStreamConsumer2.close();
194 out.close();
195
196 final RunStatistics globalRunStatistics = testSetReporterFactory.getGlobalRunStatistics();
197
198 runResult = globalRunStatistics.getRunResult();
199 }
200 catch ( CommandLineTimeOutException e )
201 {
202 runResult = RunResult.Timeout;
203 }
204 catch ( CommandLineException e )
205 {
206 throw new SurefireBooterForkException( "Error while executing forked tests.", e.getCause() );
207 }
208
209 return runResult;
210 }
211
212 private Iterator getSuitesIterator()
213 throws SurefireBooterForkException
214 {
215 try
216 {
217 final ClasspathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();
218 ClassLoader testsClassLoader = classpathConfiguration.createTestClassLoader( false );
219 ClassLoader surefireClassLoader = classpathConfiguration.createSurefireClassLoader( testsClassLoader );
220
221 SurefireReflector surefireReflector = new SurefireReflector( surefireClassLoader );
222 Object reporterFactory = surefireReflector.createReportingReporterFactory( startupReportConfiguration );
223
224 final ProviderFactory providerFactory =
225 new ProviderFactory( startupConfiguration, providerConfiguration, surefireClassLoader, testsClassLoader,
226 reporterFactory );
227 SurefireProvider surefireProvider = providerFactory.createProvider();
228 return surefireProvider.getSuites();
229 }
230 catch ( SurefireExecutionException e )
231 {
232 throw new SurefireBooterForkException( "Unable to create classloader to find test suites", e );
233 }
234 }
235
236 }