Coverage Report - org.apache.maven.plugin.surefire.booterclient.ForkConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
ForkConfiguration
74%
53/71
32%
11/34
2,769
 
 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.FileOutputStream;
 24  
 import java.io.IOException;
 25  
 import java.util.List;
 26  
 import java.util.Map;
 27  
 import java.util.jar.JarEntry;
 28  
 import java.util.jar.JarOutputStream;
 29  
 import java.util.jar.Manifest;
 30  
 
 31  
 import org.apache.maven.plugin.surefire.AbstractSurefireMojo;
 32  
 import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
 33  
 import org.apache.maven.plugin.surefire.util.Relocator;
 34  
 import org.apache.maven.shared.utils.StringUtils;
 35  
 import org.apache.maven.surefire.booter.Classpath;
 36  
 import org.apache.maven.surefire.booter.ForkedBooter;
 37  
 import org.apache.maven.surefire.booter.StartupConfiguration;
 38  
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
 39  
 import org.apache.maven.surefire.util.UrlUtils;
 40  
 
 41  
 /**
 42  
  * Configuration for forking tests.
 43  
  *
 44  
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 45  
  * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
 46  
  * @author <a href="mailto:krosenvold@apache.org">Kristian Rosenvold</a>
 47  
  */
 48  
 public class ForkConfiguration
 49  
 {
 50  
     public static final String FORK_ONCE = "once";
 51  
 
 52  
     public static final String FORK_ALWAYS = "always";
 53  
 
 54  
     public static final String FORK_NEVER = "never";
 55  
 
 56  
     public static final String FORK_PERTHREAD = "perthread";
 57  
 
 58  
     private final int forkCount;
 59  
 
 60  
     private final boolean reuseForks;
 61  
 
 62  
     private final Classpath bootClasspathConfiguration;
 63  
 
 64  
     private final String jvmExecutable;
 65  
 
 66  
     private final String argLine;
 67  
 
 68  
     private final Map<String, String> environmentVariables;
 69  
 
 70  
     private final File workingDirectory;
 71  
 
 72  
     private final File tempDirectory;
 73  
 
 74  
     private final boolean debug;
 75  
 
 76  
     private final String debugLine;
 77  
 
 78  
     public ForkConfiguration( Classpath bootClasspathConfiguration, File tmpDir, String debugLine, String jvmExecutable,
 79  
                               File workingDirectory, String argLine, Map<String, String> environmentVariables,
 80  
                               boolean debugEnabled, int forkCount, boolean reuseForks )
 81  14
     {
 82  14
         this.bootClasspathConfiguration = bootClasspathConfiguration;
 83  14
         this.tempDirectory = tmpDir;
 84  14
         this.debugLine = debugLine;
 85  14
         this.jvmExecutable = jvmExecutable;
 86  14
         this.workingDirectory = workingDirectory;
 87  14
         this.argLine = argLine;
 88  14
         this.environmentVariables = environmentVariables;
 89  14
         this.debug = debugEnabled;
 90  14
         this.forkCount = forkCount;
 91  14
         this.reuseForks = reuseForks;
 92  14
     }
 93  
 
 94  
     public Classpath getBootClasspath()
 95  
     {
 96  0
         return bootClasspathConfiguration;
 97  
     }
 98  
 
 99  
     public static String getEffectiveForkMode( String forkMode )
 100  
     {
 101  0
         if ( "pertest".equalsIgnoreCase( forkMode ) )
 102  
         {
 103  0
             return FORK_ALWAYS;
 104  
         }
 105  0
         else if ( "none".equalsIgnoreCase( forkMode ) )
 106  
         {
 107  0
             return FORK_NEVER;
 108  
         }
 109  0
         else if ( forkMode.equals( FORK_NEVER ) || forkMode.equals( FORK_ONCE ) ||
 110  
             forkMode.equals( FORK_ALWAYS ) || forkMode.equals( FORK_PERTHREAD ) )
 111  
         {
 112  0
             return forkMode;
 113  
         }
 114  
         else
 115  
         {
 116  0
             throw new IllegalArgumentException( "Fork mode " + forkMode + " is not a legal value" );
 117  
         }
 118  
     }
 119  
 
 120  
     /**
 121  
      * @param classPath            cla the classpath arguments
 122  
      * @param startupConfiguration The startup configuration
 123  
      * @param threadNumber         the thread number, to be the replacement in the argLine   @return A commandline
 124  
      * @throws org.apache.maven.surefire.booter.SurefireBooterForkException
 125  
      *          when unable to perform the fork
 126  
      */
 127  
     public OutputStreamFlushableCommandline createCommandLine( List<String> classPath,
 128  
                                                                StartupConfiguration startupConfiguration,
 129  
                                                                int threadNumber )
 130  
         throws SurefireBooterForkException
 131  
     {
 132  0
         return createCommandLine( classPath,
 133  
                                   startupConfiguration.getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable(),
 134  
                                   startupConfiguration.isShadefire(), startupConfiguration.isProviderMainClass()
 135  
             ? startupConfiguration.getActualClassName()
 136  
             : ForkedBooter.class.getName(), threadNumber );
 137  
     }
 138  
 
 139  
     OutputStreamFlushableCommandline createCommandLine( List<String> classPath, boolean useJar, boolean shadefire,
 140  
                                                         String providerThatHasMainMethod, int threadNumber )
 141  
         throws SurefireBooterForkException
 142  
     {
 143  2
         OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
 144  
 
 145  2
         cli.setExecutable( jvmExecutable );
 146  
 
 147  2
         if ( argLine != null )
 148  
         {
 149  1
             cli.createArg().setLine( replaceThreadNumberPlaceholder( stripNewLines( argLine ), threadNumber ) );
 150  
         }
 151  
 
 152  2
         if ( environmentVariables != null )
 153  
         {
 154  
 
 155  0
             for ( String key : environmentVariables.keySet() )
 156  
             {
 157  0
                 String value = environmentVariables.get( key );
 158  
 
 159  0
                 cli.addEnvironment( key, value );
 160  0
             }
 161  
         }
 162  
 
 163  2
         if ( getDebugLine() != null && !"".equals( getDebugLine() ) )
 164  
         {
 165  0
             cli.createArg().setLine( getDebugLine() );
 166  
         }
 167  
 
 168  2
         if ( useJar )
 169  
         {
 170  
             File jarFile;
 171  
             try
 172  
             {
 173  1
                 jarFile = createJar( classPath, providerThatHasMainMethod );
 174  
             }
 175  0
             catch ( IOException e )
 176  
             {
 177  0
                 throw new SurefireBooterForkException( "Error creating archive file", e );
 178  1
             }
 179  
 
 180  1
             cli.createArg().setValue( "-jar" );
 181  
 
 182  1
             cli.createArg().setValue( jarFile.getAbsolutePath() );
 183  1
         }
 184  
         else
 185  
         {
 186  1
             cli.addEnvironment( "CLASSPATH", StringUtils.join( classPath.iterator(), File.pathSeparator ) );
 187  
 
 188  1
             final String forkedBooter =
 189  
                 providerThatHasMainMethod != null ? providerThatHasMainMethod : ForkedBooter.class.getName();
 190  
 
 191  1
             cli.createArg().setValue( shadefire ? new Relocator().relocate( forkedBooter ) : forkedBooter );
 192  
         }
 193  
 
 194  2
         cli.setWorkingDirectory( workingDirectory.getAbsolutePath() );
 195  
 
 196  2
         return cli;
 197  
     }
 198  
 
 199  
     private String replaceThreadNumberPlaceholder( String argLine, int threadNumber )
 200  
     {
 201  1
         return argLine.replace( AbstractSurefireMojo.THREAD_NUMBER_PLACEHOLDER,
 202  
                                 String.valueOf( threadNumber ) ).replace( AbstractSurefireMojo.FORK_NUMBER_PLACEHOLDER,
 203  
                                                                           String.valueOf( threadNumber ) );
 204  
     }
 205  
 
 206  
     /**
 207  
      * Create a jar with just a manifest containing a Main-Class entry for BooterConfiguration and a Class-Path entry
 208  
      * for all classpath elements.
 209  
      *
 210  
      * @param classPath      List&lt;String> of all classpath elements.
 211  
      * @param startClassName  The classname to start (main-class)
 212  
      * @return The file pointint to the jar
 213  
      * @throws java.io.IOException When a file operation fails.
 214  
      */
 215  
     private File createJar( List<String> classPath, String startClassName )
 216  
         throws IOException
 217  
     {
 218  1
         File file = File.createTempFile( "surefirebooter", ".jar", tempDirectory );
 219  1
         if ( !debug )
 220  
         {
 221  1
             file.deleteOnExit();
 222  
         }
 223  1
         FileOutputStream fos = new FileOutputStream( file );
 224  1
         JarOutputStream jos = new JarOutputStream( fos );
 225  1
         jos.setLevel( JarOutputStream.STORED );
 226  1
         JarEntry je = new JarEntry( "META-INF/MANIFEST.MF" );
 227  1
         jos.putNextEntry( je );
 228  
 
 229  1
         Manifest man = new Manifest();
 230  
 
 231  
         // we can't use StringUtils.join here since we need to add a '/' to
 232  
         // the end of directory entries - otherwise the jvm will ignore them.
 233  1
         String cp = "";
 234  1
         for ( String el : classPath )
 235  
         {
 236  
             // NOTE: if File points to a directory, this entry MUST end in '/'.
 237  1
             cp += UrlUtils.getURL( new File( el ) ).toExternalForm() + " ";
 238  1
         }
 239  
 
 240  1
         man.getMainAttributes().putValue( "Manifest-Version", "1.0" );
 241  1
         man.getMainAttributes().putValue( "Class-Path", cp.trim() );
 242  1
         man.getMainAttributes().putValue( "Main-Class", startClassName );
 243  
 
 244  1
         man.write( jos );
 245  1
         jos.close();
 246  
 
 247  1
         return file;
 248  
     }
 249  
 
 250  
     public boolean isDebug()
 251  
     {
 252  12
         return debug;
 253  
     }
 254  
 
 255  
     public String stripNewLines( String argline )
 256  
     {
 257  1
         return argline.replace( "\n", " " ).replace( "\r", " " );
 258  
     }
 259  
 
 260  
     public String getDebugLine()
 261  
     {
 262  2
         return debugLine;
 263  
     }
 264  
 
 265  
     public File getTempDirectory()
 266  
     {
 267  12
         return tempDirectory;
 268  
     }
 269  
 
 270  
     public int getForkCount()
 271  
     {
 272  0
         return forkCount;
 273  
     }
 274  
 
 275  
 
 276  
     public boolean isReuseForks()
 277  
     {
 278  0
         return reuseForks;
 279  
     }
 280  
 }