| package org.apache.maven.plugin.surefire.booterclient; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline; |
| import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; |
| import org.apache.maven.plugin.surefire.util.Relocator; |
| import org.apache.maven.surefire.booter.ClassLoaderConfiguration; |
| import org.apache.maven.surefire.booter.Classpath; |
| import org.apache.maven.surefire.booter.ClasspathConfiguration; |
| import org.apache.maven.surefire.booter.ForkedBooter; |
| import org.apache.maven.surefire.booter.StartupConfiguration; |
| import org.apache.maven.surefire.extensions.ForkNodeFactory; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.powermock.core.classloader.annotations.PowerMockIgnore; |
| import org.powermock.core.classloader.annotations.PrepareForTest; |
| import org.powermock.modules.junit4.PowerMockRunner; |
| |
| import javax.annotation.Nonnull; |
| import java.io.File; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import static java.util.Collections.singleton; |
| import static org.fest.assertions.Assertions.assertThat; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.powermock.api.mockito.PowerMockito.mock; |
| import static org.powermock.api.mockito.PowerMockito.mockStatic; |
| import static org.powermock.api.mockito.PowerMockito.spy; |
| import static org.powermock.api.mockito.PowerMockito.verifyPrivate; |
| import static org.powermock.api.mockito.PowerMockito.verifyStatic; |
| import static org.powermock.api.mockito.PowerMockito.when; |
| import static org.powermock.reflect.Whitebox.invokeMethod; |
| |
| /** |
| * Unit tests for {@link DefaultForkConfiguration}. |
| * |
| * @author Tibor Digana (tibor17) |
| * @since 2.21 |
| */ |
| @RunWith( PowerMockRunner.class ) |
| @PrepareForTest( { DefaultForkConfiguration.class, Relocator.class } ) |
| @PowerMockIgnore( { "org.jacoco.agent.rt.*", "com.vladium.emma.rt.*" } ) |
| public class DefaultForkConfigurationTest |
| { |
| private Classpath booterClasspath; |
| private File tempDirectory; |
| private String debugLine; |
| private File workingDirectory; |
| private Properties modelProperties; |
| private String argLine; |
| private Map<String, String> environmentVariables; |
| private String[] excludedEnvironmentVariables; |
| private boolean debug; |
| private int forkCount; |
| private boolean reuseForks; |
| private Platform pluginPlatform; |
| private ConsoleLogger log; |
| private ForkNodeFactory forkNodeFactory; |
| |
| @Before |
| public void setup() |
| { |
| booterClasspath = new Classpath( singleton( "provider.jar" ) ); |
| tempDirectory = new File( "target/surefire" ); |
| debugLine = ""; |
| workingDirectory = new File( "." ); |
| modelProperties = new Properties(); |
| argLine = null; |
| environmentVariables = new HashMap<>(); |
| excludedEnvironmentVariables = new String[0]; |
| debug = true; |
| forkCount = 2; |
| reuseForks = true; |
| pluginPlatform = new Platform(); |
| log = mock( ConsoleLogger.class ); |
| forkNodeFactory = mock( ForkNodeFactory.class ); |
| } |
| |
| @Test |
| public void shouldBeNullArgLine() throws Exception |
| { |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) ); |
| assertThat( newArgLine ).isEmpty(); |
| } |
| |
| @Test |
| public void shouldBeEmptyArgLine() throws Exception |
| { |
| argLine = ""; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) ); |
| assertThat( newArgLine ).isEmpty(); |
| } |
| |
| @Test |
| public void shouldBeEmptyArgLineInsteadOfNewLines() throws Exception |
| { |
| argLine = "\n\r"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "" ) ); |
| assertThat( newArgLine ).isEmpty(); |
| } |
| |
| @Test |
| public void shouldBeWithoutEscaping() throws Exception |
| { |
| argLine = "-Dfile.encoding=UTF-8"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dfile.encoding=UTF-8" ) ); |
| assertThat( newArgLine ).isEqualTo( "-Dfile.encoding=UTF-8" ); |
| } |
| |
| @Test |
| public void shouldBeWithEscaping() throws Exception |
| { |
| modelProperties.put( "encoding", "UTF-8" ); |
| argLine = "-Dfile.encoding=@{encoding}"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dfile.encoding=UTF-8" ) ); |
| assertThat( newArgLine ).isEqualTo( "-Dfile.encoding=UTF-8" ); |
| } |
| |
| @Test |
| public void shouldBeWhitespaceInsteadOfNewLines() throws Exception |
| { |
| argLine = "a\n\rb"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "a b" ) ); |
| assertThat( newArgLine ).isEqualTo( "a b" ); |
| } |
| |
| @Test |
| public void shouldEscapeThreadNumber() throws Exception |
| { |
| argLine = "-Dthread=${surefire.threadNumber}"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dthread=" + forkCount ) ); |
| assertThat( newArgLine ).isEqualTo( "-Dthread=" + forkCount ); |
| } |
| |
| @Test |
| public void shouldEscapeForkNumber() throws Exception |
| { |
| argLine = "-Dthread=${surefire.forkNumber}"; |
| DefaultForkConfiguration config = new DefaultForkConfiguration( booterClasspath, tempDirectory, debugLine, |
| workingDirectory, modelProperties, argLine, environmentVariables, excludedEnvironmentVariables, |
| debug, forkCount, reuseForks, pluginPlatform, log, forkNodeFactory ) |
| { |
| |
| @Override |
| protected void resolveClasspath( @Nonnull OutputStreamFlushableCommandline cli, |
| @Nonnull String booterThatHasMainMethod, |
| @Nonnull StartupConfiguration config, |
| @Nonnull File dumpLogDirectory ) |
| { |
| } |
| }; |
| |
| DefaultForkConfiguration mockedConfig = spy( config ); |
| String newArgLine = invokeMethod( mockedConfig, "newJvmArgLine", new Class[] { int.class }, 2 ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "interpolateArgLineWithPropertyExpressions" ); |
| verifyPrivate( mockedConfig, times( 1 ) ).invoke( "extendJvmArgLine", eq( "-Dthread=" + forkCount ) ); |
| assertThat( newArgLine ).isEqualTo( "-Dthread=" + forkCount ); |
| } |
| |
| @Test |
| public void shouldRelocateBooterClassWhenShadefire() throws Exception |
| { |
| ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true ); |
| ClasspathConfiguration cc = new ClasspathConfiguration( true, true ); |
| StartupConfiguration conf = new StartupConfiguration( "org.apache.maven.shadefire.surefire.MyProvider", |
| cc, clc, null ); |
| StartupConfiguration confMock = spy( conf ); |
| mockStatic( Relocator.class ); |
| when( Relocator.relocate( anyString() ) ).thenCallRealMethod(); |
| |
| String cls = invokeMethod( DefaultForkConfiguration.class, "findStartClass", confMock ); |
| |
| verify( confMock, times( 1 ) ).isShadefire(); |
| verifyStatic( Relocator.class, times( 1 ) ); |
| Relocator.relocate( eq( ForkedBooter.class.getName() ) ); |
| |
| assertThat( cls ).isEqualTo( "org.apache.maven.shadefire.surefire.booter.ForkedBooter" ); |
| assertThat( confMock.isShadefire() ).isTrue(); |
| } |
| |
| @Test |
| public void shouldNotRelocateBooterClass() throws Exception |
| { |
| ClassLoaderConfiguration clc = new ClassLoaderConfiguration( true, true ); |
| ClasspathConfiguration cc = new ClasspathConfiguration( true, true ); |
| StartupConfiguration conf = |
| new StartupConfiguration( "org.apache.maven.surefire.MyProvider", cc, clc, null ); |
| StartupConfiguration confMock = spy( conf ); |
| mockStatic( Relocator.class ); |
| when( Relocator.relocate( anyString() ) ).thenCallRealMethod(); |
| |
| String cls = invokeMethod( DefaultForkConfiguration.class, "findStartClass", confMock ); |
| |
| verify( confMock, times( 1 ) ).isShadefire(); |
| verifyStatic( Relocator.class, never() ); |
| Relocator.relocate( eq( ForkedBooter.class.getName() ) ); |
| |
| assertThat( cls ).isEqualTo( "org.apache.maven.surefire.booter.ForkedBooter" ); |
| assertThat( confMock.isShadefire() ).isFalse(); |
| } |
| } |