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 org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
23 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
24 import org.apache.maven.plugin.surefire.util.Relocator;
25 import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
26 import org.apache.maven.surefire.booter.Classpath;
27 import org.apache.maven.surefire.booter.ClasspathConfiguration;
28 import org.apache.maven.surefire.booter.ForkedBooter;
29 import org.apache.maven.surefire.booter.StartupConfiguration;
30 import org.apache.maven.surefire.booter.SurefireBooterForkException;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.powermock.core.classloader.annotations.PrepareForTest;
35 import org.powermock.modules.junit4.PowerMockRunner;
36
37 import javax.annotation.Nonnull;
38 import java.io.File;
39 import java.util.HashMap;
40 import java.util.Map;
41 import java.util.Properties;
42
43 import static java.util.Collections.singleton;
44 import static org.fest.assertions.Assertions.assertThat;
45 import static org.mockito.ArgumentMatchers.anyString;
46 import static org.mockito.ArgumentMatchers.eq;
47 import static org.mockito.Mockito.never;
48 import static org.mockito.Mockito.times;
49 import static org.mockito.Mockito.verify;
50 import static org.powermock.api.mockito.PowerMockito.*;
51 import static org.powermock.reflect.Whitebox.invokeMethod;
52
53
54
55
56
57
58
59 @RunWith( PowerMockRunner.class )
60 @PrepareForTest( { DefaultForkConfiguration.class, Relocator.class } )
61 public class DefaultForkConfigurationTest
62 {
63 private Classpath booterClasspath;
64 private File tempDirectory;
65 private String debugLine;
66 private File workingDirectory;
67 private Properties modelProperties;
68 private String argLine;
69 private Map<String, String> environmentVariables;
70 private boolean debug;
71 private int forkCount;
72 private boolean reuseForks;
73 private Platform pluginPlatform;
74 private ConsoleLogger log;
75
76 @Before
77 public void setup()
78 {
79 booterClasspath = new Classpath( singleton( "provider.jar" ) );
80 tempDirectory = new File( "target/surefire" );
81 debugLine = "";
82 workingDirectory = new File( "." );
83 modelProperties = new Properties();
84 argLine = null;
85 environmentVariables = new HashMap<>();
86 debug = true;
87 forkCount = 2;
88 reuseForks = true;
89 pluginPlatform = new Platform();
90 log = mock( ConsoleLogger.class );
91 }
92
93 @Test
94 public void shouldBeNullArgLine() throws Exception
95 {
96 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
97 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
98 pluginPlatform, log )
99 {
100
101 @Override
102 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
103 @Nonnull String booterThatHasMainMethod,
104 @Nonnull StartupConfiguration config,
105 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
106 {
107
108 }
109 };
110
111 DefaultForkConfiguration mockedConfig = spy( config );
112 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
113 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
114 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) );
115 assertThat( newArgLine ).isEmpty();
116 }
117
118 @Test
119 public void shouldBeEmptyArgLine() throws Exception
120 {
121 argLine = "";
122 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
123 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
124 pluginPlatform, log )
125 {
126
127 @Override
128 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
129 @Nonnull String booterThatHasMainMethod,
130 @Nonnull StartupConfiguration config,
131 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
132 {
133
134 }
135 };
136
137 DefaultForkConfiguration mockedConfig = spy( config );
138 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
139 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
140 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) );
141 assertThat( newArgLine ).isEmpty();
142 }
143
144 @Test
145 public void shouldBeEmptyArgLineInsteadOfNewLines() throws Exception
146 {
147 argLine = "\n\r";
148 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
149 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
150 pluginPlatform, log )
151 {
152
153 @Override
154 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
155 @Nonnull String booterThatHasMainMethod,
156 @Nonnull StartupConfiguration config,
157 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
158 {
159
160 }
161 };
162
163 DefaultForkConfiguration mockedConfig = spy( config );
164 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
165 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
166 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) );
167 assertThat( newArgLine ).isEmpty();
168 }
169
170 @Test
171 public void shouldBeWithoutEscaping() throws Exception
172 {
173 argLine = "-Dfile.encoding=UTF-8";
174 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
175 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
176 pluginPlatform, log )
177 {
178
179 @Override
180 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
181 @Nonnull String booterThatHasMainMethod,
182 @Nonnull StartupConfiguration config,
183 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
184 {
185
186 }
187 };
188
189 DefaultForkConfiguration mockedConfig = spy( config );
190 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
191 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
192 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dfile.encoding=UTF-8" ) );
193 assertThat( newArgLine ).isEqualTo( "-Dfile.encoding=UTF-8" );
194 }
195
196 @Test
197 public void shouldBeWithEscaping() throws Exception
198 {
199 modelProperties.put( "encoding", "UTF-8" );
200 argLine = "-Dfile.encoding=@{encoding}";
201 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
202 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
203 pluginPlatform, log )
204 {
205
206 @Override
207 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
208 @Nonnull String booterThatHasMainMethod,
209 @Nonnull StartupConfiguration config,
210 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
211 {
212
213 }
214 };
215
216 DefaultForkConfiguration mockedConfig = spy( config );
217 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
218 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
219 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dfile.encoding=UTF-8" ) );
220 assertThat( newArgLine ).isEqualTo( "-Dfile.encoding=UTF-8" );
221 }
222
223 @Test
224 public void shouldBeWhitespaceInsteadOfNewLines() throws Exception
225 {
226 argLine = "a\n\rb";
227 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
228 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
229 pluginPlatform, log )
230 {
231
232 @Override
233 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
234 @Nonnull String booterThatHasMainMethod,
235 @Nonnull StartupConfiguration config,
236 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
237 {
238
239 }
240 };
241
242 DefaultForkConfiguration mockedConfig = spy( config );
243 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
244 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
245 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "a b" ) );
246 assertThat( newArgLine ).isEqualTo( "a b" );
247 }
248
249 @Test
250 public void shouldEscapeThreadNumber() throws Exception
251 {
252 argLine = "-Dthread=${surefire.threadNumber}";
253 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
254 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
255 pluginPlatform, log )
256 {
257
258 @Override
259 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
260 @Nonnull String booterThatHasMainMethod,
261 @Nonnull StartupConfiguration config,
262 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
263 {
264
265 }
266 };
267
268 DefaultForkConfiguration mockedConfig = spy( config );
269 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
270 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
271 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dthread=" + forkCount ) );
272 assertThat( newArgLine ).isEqualTo( "-Dthread=" + forkCount );
273 }
274
275 @Test
276 public void shouldEscapeForkNumber() throws Exception
277 {
278 argLine = "-Dthread=${surefire.forkNumber}";
279 DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine,
280 workingDirectory, modelProperties, argLine, environmentVariables, debug, forkCount, reuseForks,
281 pluginPlatform, log )
282 {
283
284 @Override
285 protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli,
286 @Nonnull String booterThatHasMainMethod,
287 @Nonnull StartupConfiguration config,
288 @Nonnull File dumpLogDirectory ) throws SurefireBooterForkException
289 {
290
291 }
292 };
293
294 DefaultForkConfiguration mockedConfig = spy( config );
295 String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 );
296 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" );
297 verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dthread=" + forkCount ) );
298 assertThat( newArgLine ).isEqualTo( "-Dthread=" + forkCount );
299 }
300
301 @Test
302 public void shouldRelocateBooterClassWhenShadefire() throws Exception
303 {
304 ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
305 ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
306 StartupConfiguration conf =
307 new StartupConfiguration( "org.apache.maven.shadefire.surefire.MyProvider", cc, clc, false, false );
308 StartupConfiguration confMock = spy( conf );
309 mockStatic( Relocator.class );
310 when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
311
312 String cls = invokeMethod( DefaultForkConfiguration.class, "findStartClass", confMock );
313
314 verify( confMock, times( 1 ) ).isShadefire();
315 verifyStatic( Relocator.class, times( 1 ) );
316 Relocator.relocate( eq( ForkedBooter.class.getName() ) );
317
318 assertThat( cls ).isEqualTo( "org.apache.maven.shadefire.surefire.booter.ForkedBooter" );
319 assertThat( confMock.isShadefire() ).isTrue();
320 }
321
322 @Test
323 public void shouldNotRelocateBooterClass() throws Exception
324 {
325 ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true );
326 ClasspathConfiguration cc = new ClasspathConfiguration( true, true );
327 StartupConfiguration conf =
328 new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, false, false );
329 StartupConfiguration confMock = spy( conf );
330 mockStatic( Relocator.class );
331 when( Relocator.relocate( anyString() ) ).thenCallRealMethod();
332
333 String cls = invokeMethod( DefaultForkConfiguration.class, "findStartClass", confMock );
334
335 verify( confMock, times( 1 ) ).isShadefire();
336 verifyStatic( Relocator.class, never() );
337 Relocator.relocate( eq( ForkedBooter.class.getName() ) );
338
339 assertThat( cls ).isEqualTo( "org.apache.maven.surefire.booter.ForkedBooter" );
340 assertThat( confMock.isShadefire() ).isFalse();
341 }
342 }