Coverage Report - org.apache.maven.plugin.surefire.booterclient.ForkStarter
 
Classes in this File Line Coverage Branch Coverage Complexity
ForkStarter
0%
0/91
0%
0/40
5.5
 
 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 org.apache.maven.plugin.surefire.booterclient.output.FileOutputConsumerProxy;
 23  
 import org.apache.maven.plugin.surefire.booterclient.output.NullOutputConsumer;
 24  
 import org.apache.maven.plugin.surefire.booterclient.output.OutputConsumer;
 25  
 import org.apache.maven.plugin.surefire.booterclient.output.StandardOutputConsumer;
 26  
 import org.apache.maven.plugin.surefire.booterclient.output.SupressFooterOutputConsumerProxy;
 27  
 import org.apache.maven.plugin.surefire.booterclient.output.SupressHeaderOutputConsumerProxy;
 28  
 import org.apache.maven.plugin.surefire.booterclient.output.SynchronizedOutputConsumer;
 29  
 import org.apache.maven.surefire.booter.Classpath;
 30  
 import org.apache.maven.surefire.booter.ProviderConfiguration;
 31  
 import org.apache.maven.surefire.booter.ProviderFactory;
 32  
 import org.apache.maven.surefire.booter.StartupConfiguration;
 33  
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
 34  
 import org.apache.maven.surefire.booter.SurefireExecutionException;
 35  
 import org.apache.maven.surefire.booter.SurefireStarter;
 36  
 import org.apache.maven.surefire.booter.SystemPropertyManager;
 37  
 import org.apache.maven.surefire.providerapi.SurefireProvider;
 38  
 import org.apache.maven.surefire.suite.RunResult;
 39  
 import org.codehaus.plexus.util.IOUtil;
 40  
 import org.codehaus.plexus.util.cli.CommandLineException;
 41  
 import org.codehaus.plexus.util.cli.CommandLineTimeOutException;
 42  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 43  
 import org.codehaus.plexus.util.cli.Commandline;
 44  
 import org.codehaus.plexus.util.cli.StreamConsumer;
 45  
 
 46  
 import java.io.File;
 47  
 import java.io.FileInputStream;
 48  
 import java.io.FileNotFoundException;
 49  
 import java.io.IOException;
 50  
 import java.util.Iterator;
 51  
 import java.util.Properties;
 52  
 
 53  
 
 54  
 /**
 55  
  * Starts the fork or runs in-process.
 56  
  * <p/>
 57  
  * Lives only on the plugin-side (not present in remote vms)
 58  
  * <p/>
 59  
  * Knows how to fork new vms and also how to delegate non-forking invocation to SurefireStarter directly
 60  
  *
 61  
  * @author Jason van Zyl
 62  
  * @author Emmanuel Venisse
 63  
  * @author Brett Porter
 64  
  * @author Dan Fabulich
 65  
  * @author Carlos Sanchez
 66  
  * @author Kristian Rosenvold
 67  
  * @version $Id: ForkStarter.java 1076367 2011-03-02 20:30:49Z krosenvold $
 68  
  */
 69  
 public class ForkStarter
 70  
 {
 71  
     private final int forkedProcessTimeoutInSeconds;
 72  
 
 73  
     private final ProviderConfiguration providerConfiguration;
 74  
 
 75  
     private final StartupConfiguration startupConfiguration;
 76  
 
 77  
     private final ForkConfiguration forkConfiguration;
 78  
 
 79  
     private final File reportsDirectory;
 80  
 
 81  
     private final boolean printSummary;
 82  
 
 83  
     public ForkStarter( ProviderConfiguration providerConfiguration, StartupConfiguration startupConfiguration,
 84  
                         File reportsDirectory, ForkConfiguration forkConfiguration, int forkedProcessTimeoutInSeconds,
 85  
                         boolean printSummary )
 86  0
     {
 87  0
         this.forkConfiguration = forkConfiguration;
 88  0
         this.providerConfiguration = providerConfiguration;
 89  0
         this.reportsDirectory = reportsDirectory;
 90  0
         this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
 91  0
         this.startupConfiguration = startupConfiguration;
 92  0
         this.printSummary = printSummary;
 93  0
     }
 94  
 
 95  
     public int run()
 96  
         throws SurefireBooterForkException, SurefireExecutionException
 97  
     {
 98  
         final int result;
 99  
 
 100  0
         final String requestedForkMode = forkConfiguration.getForkMode();
 101  0
         if ( ForkConfiguration.FORK_NEVER.equals( requestedForkMode ) )
 102  
         {
 103  0
             SurefireStarter surefireStarter = new SurefireStarter( startupConfiguration, providerConfiguration );
 104  0
             result = surefireStarter.runSuitesInProcess();
 105  0
         }
 106  0
         else if ( ForkConfiguration.FORK_ONCE.equals( requestedForkMode ) )
 107  
         {
 108  0
             result = runSuitesForkOnce();
 109  
         }
 110  0
         else if ( ForkConfiguration.FORK_ALWAYS.equals( requestedForkMode ) )
 111  
         {
 112  0
             result = runSuitesForkPerTestSet();
 113  
         }
 114  
         else
 115  
         {
 116  0
             throw new SurefireExecutionException( "Unknown forkmode: " + requestedForkMode, null );
 117  
         }
 118  0
         return result;
 119  
     }
 120  
 
 121  
     private int runSuitesForkOnce()
 122  
         throws SurefireBooterForkException
 123  
     {
 124  0
         return fork( null, providerConfiguration.getProviderProperties(), true, true );
 125  
     }
 126  
 
 127  
     private int runSuitesForkPerTestSet()
 128  
         throws SurefireBooterForkException
 129  
     {
 130  0
         int globalResult = 0;
 131  
 
 132  
         ClassLoader testsClassLoader;
 133  
         ClassLoader surefireClassLoader;
 134  
         try
 135  
         {
 136  0
             testsClassLoader = startupConfiguration.getClasspathConfiguration().createTestClassLoader( false );
 137  
             // TODO: assertions = true shouldn't be required if we had proper separation (see TestNG)
 138  0
             surefireClassLoader =
 139  
                 startupConfiguration.getClasspathConfiguration().createSurefireClassLoader( testsClassLoader );
 140  
         }
 141  0
         catch ( SurefireExecutionException e )
 142  
         {
 143  0
             throw new SurefireBooterForkException( "Unable to create classloader to find test suites", e );
 144  0
         }
 145  
 
 146  0
         boolean showHeading = true;
 147  0
         final ProviderFactory providerFactory =
 148  
             new ProviderFactory( startupConfiguration, providerConfiguration, surefireClassLoader, testsClassLoader );
 149  0
         SurefireProvider surefireProvider = providerFactory.createProvider();
 150  
 
 151  0
         Properties properties = new Properties();
 152  
 
 153  0
         final Iterator suites = surefireProvider.getSuites();
 154  0
         while ( suites.hasNext() )
 155  
         {
 156  0
             Object testSet = suites.next();
 157  0
             boolean showFooter = !suites.hasNext();
 158  0
             int result = fork( testSet, properties, showHeading, showFooter );
 159  
 
 160  0
             if ( result > globalResult )
 161  
             {
 162  0
                 globalResult = result;
 163  
             }
 164  0
             showHeading = false;
 165  0
         }
 166  
         // At this place, show aggregated results ?
 167  0
         return globalResult;
 168  
     }
 169  
 
 170  
     private int fork( Object testSet, Properties properties, boolean showHeading, boolean showFooter )
 171  
         throws SurefireBooterForkException
 172  
     {
 173  
         File surefireProperties;
 174  0
         File systemProperties = null;
 175  
         try
 176  
         {
 177  0
             BooterSerializer booterSerializer = new BooterSerializer( forkConfiguration, properties );
 178  
 
 179  0
             surefireProperties = booterSerializer.serialize( providerConfiguration, startupConfiguration, testSet );
 180  
 
 181  0
             if ( forkConfiguration.getSystemProperties() != null )
 182  
             {
 183  0
                 systemProperties = SystemPropertyManager.writePropertiesFile( forkConfiguration.getSystemProperties(),
 184  
                                                                               forkConfiguration.getTempDirectory(),
 185  
                                                                               "surefire", forkConfiguration.isDebug() );
 186  
             }
 187  
         }
 188  0
         catch ( IOException e )
 189  
         {
 190  0
             throw new SurefireBooterForkException( "Error creating properties files for forking", e );
 191  0
         }
 192  
 
 193  0
         final Classpath bootClasspathConfiguration = forkConfiguration.getBootClasspath();
 194  0
         final Classpath additionlClassPathUrls = startupConfiguration.useSystemClassLoader()
 195  
             ? startupConfiguration.getClasspathConfiguration().getTestClasspath()
 196  
             : null;
 197  
 
 198  0
         Classpath bootClasspath = Classpath.join( bootClasspathConfiguration, additionlClassPathUrls );
 199  
 
 200  0
         Commandline cli = forkConfiguration.createCommandLine( bootClasspath.getClassPath(),
 201  
                                                                startupConfiguration.getClassLoaderConfiguration(),
 202  
                                                                startupConfiguration.isShadefire() );
 203  
 
 204  0
         cli.createArg().setFile( surefireProperties );
 205  
 
 206  0
         if ( systemProperties != null )
 207  
         {
 208  0
             cli.createArg().setFile( systemProperties );
 209  
         }
 210  
 
 211  0
         final boolean willBeSharingConsumer = startupConfiguration.isRedirectTestOutputToFile();
 212  
 
 213  0
         ForkingStreamConsumer out =
 214  
             getForkingStreamConsumer( showHeading, showFooter, startupConfiguration.isRedirectTestOutputToFile(),
 215  
                                       willBeSharingConsumer, printSummary );
 216  
 
 217  0
         StreamConsumer err = willBeSharingConsumer
 218  
             ? out
 219  
             : getForkingStreamConsumer( showHeading, showFooter, startupConfiguration.isRedirectTestOutputToFile(),
 220  
                                         false, printSummary );
 221  
 
 222  0
         if ( forkConfiguration.isDebug() )
 223  
         {
 224  0
             System.out.println( "Forking command line: " + cli );
 225  
         }
 226  
 
 227  
         int returnCode;
 228  
 
 229  
         try
 230  
         {
 231  0
             returnCode = CommandLineUtils.executeCommandLine( cli, out, err, forkedProcessTimeoutInSeconds > 0 ?
 232  
                 forkedProcessTimeoutInSeconds: 0 );
 233  
         }
 234  0
         catch ( CommandLineTimeOutException e )
 235  
         {
 236  0
             returnCode = RunResult.FAILURE;
 237  
         }
 238  0
         catch ( CommandLineException e )
 239  
         {
 240  0
             throw new SurefireBooterForkException( "Error while executing forked tests.", e.getCause() );
 241  0
         }
 242  
 
 243  
        /*if ( !providerConfiguration.isSurefireForkReturnCode( returnCode ) )
 244  
         {
 245  
             throw new SurefireBooterForkException( "Uncontrolled error while forking surefire."
 246  
                                                        + "You need to inspect log files (with reportFormat=plain and redirectTestOutputToFile=true )"
 247  
                                                        + " to see stacktrace" );
 248  
         }  */
 249  
 
 250  0
         if ( startupConfiguration.isRedirectTestOutputToFile() )
 251  
         {
 252  
             // ensure the FileOutputConsumerProxy flushes/closes the output file
 253  
             try
 254  
             {
 255  0
                 out.getOutputConsumer().testSetCompleted();
 256  
             }
 257  0
             catch ( Exception e )
 258  
             {
 259  
                 // the FileOutputConsumerProxy might throw an IllegalStateException but that's not of interest now
 260  0
             }
 261  
         }
 262  
 
 263  0
         if ( surefireProperties != null && surefireProperties.exists() )
 264  
         {
 265  0
             FileInputStream inStream = null;
 266  
             try
 267  
             {
 268  0
                 inStream = new FileInputStream( surefireProperties );
 269  
 
 270  0
                 properties.load( inStream );
 271  
             }
 272  0
             catch ( FileNotFoundException e )
 273  
             {
 274  0
                 throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
 275  
             }
 276  0
             catch ( IOException e )
 277  
             {
 278  0
                 throw new SurefireBooterForkException( "Unable to reload properties file from forked process", e );
 279  
             }
 280  
             finally
 281  
             {
 282  0
                 IOUtil.close( inStream );
 283  0
             }
 284  
         }
 285  
 
 286  0
         return returnCode;
 287  
     }
 288  
 
 289  
 
 290  
     private ForkingStreamConsumer getForkingStreamConsumer( boolean showHeading, boolean showFooter,
 291  
                                                             boolean redirectTestOutputToFile, boolean mustBeThreadSafe,
 292  
                                                             boolean printSummary )
 293  
     {
 294  0
         OutputConsumer outputConsumer =
 295  
             printSummary ? new StandardOutputConsumer() : (OutputConsumer) new NullOutputConsumer();
 296  
 
 297  0
         if ( redirectTestOutputToFile )
 298  
         {
 299  0
             outputConsumer = new FileOutputConsumerProxy( outputConsumer, reportsDirectory );
 300  
         }
 301  
 
 302  0
         if ( !showHeading )
 303  
         {
 304  0
             outputConsumer = new SupressHeaderOutputConsumerProxy( outputConsumer );
 305  
         }
 306  
 
 307  0
         if ( !showFooter )
 308  
         {
 309  0
             outputConsumer = new SupressFooterOutputConsumerProxy( outputConsumer );
 310  
         }
 311  
 
 312  0
         if ( mustBeThreadSafe )
 313  
         {
 314  0
             outputConsumer = new SynchronizedOutputConsumer( outputConsumer );
 315  
         }
 316  
 
 317  0
         return new ForkingStreamConsumer( outputConsumer );
 318  
     }
 319  
 }