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 org.apache.commons.io.FileUtils;
23  import org.apache.commons.lang3.SystemUtils;
24  import org.apache.maven.plugin.surefire.JdkAttributes;
25  import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
26  import org.apache.maven.shared.utils.StringUtils;
27  import org.apache.maven.shared.utils.cli.Commandline;
28  import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
29  import org.apache.maven.surefire.booter.Classpath;
30  import org.apache.maven.surefire.booter.ClasspathConfiguration;
31  import org.apache.maven.surefire.booter.StartupConfiguration;
32  import org.apache.maven.surefire.booter.SurefireBooterForkException;
33  import org.junit.After;
34  import org.junit.Before;
35  import org.junit.Test;
36  
37  import java.io.File;
38  import java.io.IOException;
39  import java.util.Collections;
40  import java.util.List;
41  import java.util.Properties;
42  
43  import static java.util.Collections.singletonList;
44  import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
45  import static org.apache.maven.surefire.booter.ProcessCheckerType.ALL;
46  import static org.fest.util.Files.temporaryFolder;
47  import static org.junit.Assert.assertEquals;
48  import static org.junit.Assert.assertTrue;
49  import static org.junit.Assert.fail;
50  
51  /**
52   *
53   */
54  public class ForkConfigurationTest
55  {
56      private static final StartupConfiguration STARTUP_CONFIG = new StartupConfiguration( "",
57              new ClasspathConfiguration( true, true ),
58              new ClassLoaderConfiguration( true, true ),
59              false,
60              false,
61              ALL );
62  
63      private static int idx = 0;
64  
65      private File basedir;
66  
67      @Before
68      public void setupDirectories() throws IOException
69      {
70          File target = new File( System.getProperty( "user.dir" ), "target" );
71          basedir = new File( target, "SUREFIRE-1136-" + ++idx );
72          FileUtils.deleteDirectory( basedir );
73          assertTrue( basedir.mkdirs() );
74      }
75  
76      @After
77      public void deleteDirectories() throws IOException
78      {
79          FileUtils.deleteDirectory( basedir );
80      }
81  
82      @Test
83      @SuppressWarnings( { "checkstyle:methodname", "checkstyle:magicnumber" } )
84      public void testCreateCommandLine_UseSystemClassLoaderForkOnce_ShouldConstructManifestOnlyJar()
85          throws IOException, SurefireBooterForkException
86      {
87          ForkConfiguration config = getForkConfiguration( basedir, null );
88          File cpElement = getTempClasspathFile();
89  
90          List<String> cp = singletonList( cpElement.getAbsolutePath() );
91          ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
92                  emptyClasspath(), true, true );
93          ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
94          StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
95  
96          Commandline cli = config.createCommandLine( startup, 1, temporaryFolder() );
97  
98          String line = StringUtils.join( cli.getCommandline(), " " );
99          assertTrue( line.contains( "-jar" ) );
100     }
101 
102     @Test
103     public void testArglineWithNewline()
104         throws IOException, SurefireBooterForkException
105     {
106         // SUREFIRE-657
107         ForkConfiguration config = getForkConfiguration( basedir, "abc\ndef" );
108         File cpElement = getTempClasspathFile();
109 
110         List<String> cp = singletonList( cpElement.getAbsolutePath() );
111         ClasspathConfiguration cpConfig = new ClasspathConfiguration( new Classpath( cp ), emptyClasspath(),
112                 emptyClasspath(), true, true );
113         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
114         StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
115 
116         Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
117         assertTrue( commandLine.toString().contains( "abc def" ) );
118     }
119 
120     @Test
121     public void testCurrentWorkingDirectoryPropagationIncludingForkNumberExpansion()
122         throws IOException, SurefireBooterForkException
123     {
124         File cwd = new File( basedir, "fork_${surefire.forkNumber}" );
125 
126         ClasspathConfiguration cpConfig = new ClasspathConfiguration( emptyClasspath(), emptyClasspath(),
127                 emptyClasspath(), true, true );
128         ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
129         StartupConfiguration startup = new StartupConfiguration( "", cpConfig, clc, false, false, ALL );
130         ForkConfiguration config = getForkConfiguration( cwd.getCanonicalFile() );
131         Commandline commandLine = config.createCommandLine( startup, 1, temporaryFolder() );
132 
133         File forkDirectory = new File( basedir, "fork_1" );
134 
135         String shellWorkDir = commandLine.getShell().getWorkingDirectory().getCanonicalPath();
136         assertEquals( shellWorkDir,  forkDirectory.getCanonicalPath() );
137     }
138 
139     @Test
140     public void testExceptionWhenCurrentDirectoryIsNotRealDirectory()
141         throws IOException
142     {
143         File cwd = new File( basedir, "cwd.txt" );
144         FileUtils.touch( cwd );
145 
146         try
147         {
148             ForkConfiguration config = getForkConfiguration( cwd.getCanonicalFile() );
149             config.createCommandLine( STARTUP_CONFIG, 1, temporaryFolder() );
150         }
151         catch ( SurefireBooterForkException e )
152         {
153             // To handle issue with ~ expansion on Windows
154             String absolutePath = cwd.getCanonicalPath();
155             assertEquals( "WorkingDirectory " + absolutePath + " exists and is not a directory", e.getMessage() );
156             return;
157         }
158         finally
159         {
160             assertTrue( cwd.delete() );
161         }
162 
163         fail();
164     }
165 
166     @Test
167     public void testExceptionWhenCurrentDirectoryCannotBeCreated()
168         throws IOException
169     {
170         // NULL is invalid for JDK starting from 1.7.60
171         // - https://github.com/openjdk-mirror/jdk/commit/e5389115f3634d25d101e2dcc71f120d4fd9f72f
172         // ? character is invalid on Windows, seems to be imposable to create invalid directory using Java on Linux
173         File cwd = new File( basedir, "?\u0000InvalidDirectoryName" );
174 
175         try
176         {
177             ForkConfiguration config = getForkConfiguration( cwd.getAbsoluteFile() );
178             config.createCommandLine( STARTUP_CONFIG, 1, temporaryFolder() );
179         }
180         catch ( SurefireBooterForkException sbfe )
181         {
182             assertEquals( "Cannot create workingDirectory " + cwd.getAbsolutePath(), sbfe.getMessage() );
183             return;
184         }
185         finally
186         {
187             FileUtils.deleteDirectory( cwd );
188         }
189 
190         if ( SystemUtils.IS_OS_WINDOWS || isJavaVersionAtLeast7u60() )
191         {
192             fail();
193         }
194     }
195 
196     private File getTempClasspathFile()
197         throws IOException
198     {
199         File cpElement = new File( basedir, "ForkConfigurationTest." + idx + ".file" );
200         FileUtils.deleteDirectory( cpElement );
201         return cpElement;
202     }
203 
204     static ForkConfiguration getForkConfiguration( File basedir, String argLine )
205         throws IOException
206     {
207         File jvm = new File( new File( System.getProperty( "java.home" ), "bin" ), "java" );
208         return getForkConfiguration( basedir, argLine, jvm.getAbsolutePath(), new File( "." ).getCanonicalFile() );
209     }
210 
211     private ForkConfiguration getForkConfiguration( File cwd )
212             throws IOException
213     {
214         File jvm = new File( new File( System.getProperty( "java.home" ), "bin" ), "java" );
215         return getForkConfiguration( basedir, null, jvm.getAbsolutePath(), cwd );
216     }
217 
218     private static ForkConfiguration getForkConfiguration( File basedir, String argLine, String jvm, File cwd )
219         throws IOException
220     {
221         Platform platform = new Platform().withJdkExecAttributesForTests( new JdkAttributes( jvm, false ) );
222         File tmpDir = new File( new File( basedir, "target" ), "surefire" );
223         FileUtils.deleteDirectory( tmpDir );
224         assertTrue( tmpDir.mkdirs() );
225         return new JarManifestForkConfiguration( emptyClasspath(), tmpDir, null,
226                 cwd, new Properties(), argLine,
227                 Collections.<String, String>emptyMap(), new String[0], false, 1, false,
228                 platform, new NullConsoleLogger() );
229     }
230 
231     // based on http://stackoverflow.com/questions/2591083/getting-version-of-java-in-runtime
232     @SuppressWarnings( "checkstyle:magicnumber" )
233     private static boolean isJavaVersionAtLeast7u60()
234     {
235         String[] javaVersionElements = System.getProperty( "java.runtime.version" ).split( "\\.|_|-b" );
236         return Integer.valueOf( javaVersionElements[1] ) >= 7 && Integer.valueOf( javaVersionElements[3] ) >= 60;
237     }
238 }