View Javadoc

1   package org.apache.maven.plugin.surefire.booterclient;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * Starts the fork or runs in-process.
51   * <p/>
52   * Lives only on the plugin-side (not present in remote vms)
53   * <p/>
54   * Knows how to fork new vms and also how to delegate non-forking invocation to SurefireStarter directly
55   *
56   * @author Jason van Zyl
57   * @author Emmanuel Venisse
58   * @author Brett Porter
59   * @author Dan Fabulich
60   * @author Carlos Sanchez
61   * @author Kristian Rosenvold
62   * @version $Id: ForkStarter.java 1101566 2011-05-10 17:56:02Z krosenvold $
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 }