blob: b1e1c9186632af3fd7fbe6e6d151695c6a2b0757 [file] [log] [blame]
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.StartupReportConfiguration;
import org.apache.maven.plugin.surefire.SurefireProperties;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.AbstractCommandReader;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStream.TestLessInputStreamBuilder;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStream;
import org.apache.maven.plugin.surefire.booterclient.output.ForkClient;
import org.apache.maven.plugin.surefire.extensions.LegacyForkNodeFactory;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactory;
import org.apache.maven.surefire.booter.AbstractPathConfiguration;
import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
import org.apache.maven.surefire.booter.Classpath;
import org.apache.maven.surefire.booter.PropertiesWrapper;
import org.apache.maven.surefire.booter.ProviderConfiguration;
import org.apache.maven.surefire.api.booter.Shutdown;
import org.apache.maven.surefire.booter.StartupConfiguration;
import org.apache.maven.surefire.booter.SurefireBooterForkException;
import org.apache.maven.surefire.extensions.ForkNodeFactory;
import org.apache.maven.surefire.api.report.ReporterConfiguration;
import org.apache.maven.surefire.shared.compress.archivers.zip.Zip64Mode;
import org.apache.maven.surefire.shared.compress.archivers.zip.ZipArchiveEntry;
import org.apache.maven.surefire.shared.compress.archivers.zip.ZipArchiveOutputStream;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.jar.Manifest;
import java.util.zip.Deflater;
import static org.fest.util.Files.delete;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.powermock.reflect.Whitebox.invokeMethod;
/**
*
*/
public class ForkStarterTest
{
private static String baseDir = System.getProperty( "user.dir" );
private static File tmp;
@Rule
public final ExpectedException e = ExpectedException.none();
@BeforeClass
public static void prepareFiles() throws IOException
{
File target = new File( baseDir, "target" );
tmp = new File( target, "tmp" );
tmp.mkdirs();
File booter = new File( tmp, "surefirebooter.jar" );
booter.createNewFile();
try ( ZipArchiveOutputStream zos = new ZipArchiveOutputStream( new FileOutputStream( booter ) ) )
{
zos.setUseZip64( Zip64Mode.Never );
zos.setLevel( Deflater.NO_COMPRESSION );
ZipArchiveEntry ze = new ZipArchiveEntry( "META-INF/MANIFEST.MF" );
zos.putArchiveEntry( ze );
Manifest man = new Manifest();
man.getMainAttributes().putValue( "Manifest-Version", "1.0" );
man.getMainAttributes().putValue( "Main-Class", MainClass.class.getName() );
man.write( zos );
zos.closeArchiveEntry();
ze = new ZipArchiveEntry( "org/apache/maven/plugin/surefire/booterclient/MainClass.class" );
zos.putArchiveEntry( ze );
String classesDir = Paths.get( target.getPath(), "test-classes" ).toString();
Path cls = Paths.get( classesDir, "org", "apache", "maven", "plugin", "surefire", "booterclient",
"MainClass.class" );
zos.write( Files.readAllBytes( cls ) );
zos.closeArchiveEntry();
}
}
@AfterClass
public static void deleteTmp()
{
delete( tmp );
}
@Test
public void processShouldExitWithoutSayingGoodBye() throws Exception
{
ReporterConfiguration reporterConfiguration = new ReporterConfiguration( tmp, true );
ProviderConfiguration providerConfiguration = mock( ProviderConfiguration.class );
when( providerConfiguration.getReporterConfiguration() )
.thenReturn( reporterConfiguration );
when( providerConfiguration.getShutdown() )
.thenReturn( Shutdown.EXIT );
StartupConfiguration startupConfiguration = mock( StartupConfiguration.class );
when( startupConfiguration.getClasspathConfiguration() )
.thenReturn( new ClasspathConfig() );
when( startupConfiguration.getClassLoaderConfiguration() )
.thenReturn( new ClassLoaderConfiguration( false, false ) );
when( startupConfiguration.getProviderClassName() )
.thenReturn( MainClass.class.getName() );
ForkConfiguration forkConfiguration = mock( ForkConfiguration.class );
when( forkConfiguration.getWorkingDirectory() )
.thenReturn( tmp );
when( forkConfiguration.getTempDirectory() )
.thenReturn( tmp );
when( forkConfiguration.getPluginPlatform() )
.thenReturn( new Platform() );
OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
cli.setWorkingDirectory( tmp );
cli.setExecutable( System.getProperty( "java.home" ) + "/bin/java" );
cli.createArg().setLine( "-jar" );
cli.createArg().setLine( "surefirebooter.jar" );
cli.createArg().setLine( "fail" );
when( forkConfiguration.createCommandLine( eq( startupConfiguration ), eq( 1 ), eq( tmp ) ) )
.thenReturn( cli );
StartupReportConfiguration startupReportConfiguration = new StartupReportConfiguration( true, true, null,
false, tmp, true, "", null, false, 0, null, null, true, null, null, null );
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkStarter forkStarter = new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
0, startupReportConfiguration, logger );
DefaultReporterFactory reporterFactory = new DefaultReporterFactory( startupReportConfiguration, logger, 1 );
e.expect( SurefireBooterForkException.class );
e.expectMessage( containsString( "Process Exit Code: 1" ) );
e.expectMessage( containsString( "The forked VM terminated without properly saying goodbye." ) );
e.expectMessage( containsString( "VM crash or System.exit called?" ) );
Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
int.class, AbstractCommandReader.class, ForkNodeFactory.class, boolean.class};
TestProvidingInputStream testProvidingInputStream = new TestProvidingInputStream( new ArrayDeque<String>() );
invokeMethod( forkStarter, "fork", types, null,
new PropertiesWrapper( Collections.<String, String>emptyMap() ),
new ForkClient( reporterFactory, null, 1 ),
new SurefireProperties(), 1, testProvidingInputStream, new LegacyForkNodeFactory(), true );
testProvidingInputStream.close();
}
@Test
public void processShouldWaitForAck() throws Exception
{
ReporterConfiguration reporterConfiguration = new ReporterConfiguration( tmp, true );
ProviderConfiguration providerConfiguration = mock( ProviderConfiguration.class );
when( providerConfiguration.getReporterConfiguration() )
.thenReturn( reporterConfiguration );
when( providerConfiguration.getShutdown() )
.thenReturn( Shutdown.EXIT );
StartupConfiguration startupConfiguration = mock( StartupConfiguration.class );
when( startupConfiguration.getClasspathConfiguration() )
.thenReturn( new ClasspathConfig() );
when( startupConfiguration.getClassLoaderConfiguration() )
.thenReturn( new ClassLoaderConfiguration( false, false ) );
when( startupConfiguration.getProviderClassName() )
.thenReturn( MainClass.class.getName() );
ForkConfiguration forkConfiguration = mock( ForkConfiguration.class );
when( forkConfiguration.getWorkingDirectory() )
.thenReturn( tmp );
when( forkConfiguration.getTempDirectory() )
.thenReturn( tmp );
when( forkConfiguration.getPluginPlatform() )
.thenReturn( new Platform() );
OutputStreamFlushableCommandline cli = new OutputStreamFlushableCommandline();
cli.setWorkingDirectory( tmp );
cli.setExecutable( System.getProperty( "java.home" ) + "/bin/java" );
cli.createArg().setLine( "-jar" );
cli.createArg().setLine( "surefirebooter.jar" );
when( forkConfiguration.createCommandLine( eq( startupConfiguration ), eq( 1 ), eq( tmp ) ) )
.thenReturn( cli );
StartupReportConfiguration startupReportConfiguration = new StartupReportConfiguration( true, true, null,
false, tmp, true, "", null, false, 0, null, null, true, null, null, null );
ConsoleLogger logger = mock( ConsoleLogger.class );
ForkStarter forkStarter = new ForkStarter( providerConfiguration, startupConfiguration, forkConfiguration,
0, startupReportConfiguration, logger );
DefaultReporterFactory reporterFactory = new DefaultReporterFactory( startupReportConfiguration, logger, 1 );
Class<?>[] types = {Object.class, PropertiesWrapper.class, ForkClient.class, SurefireProperties.class,
int.class, AbstractCommandReader.class, ForkNodeFactory.class, boolean.class};
TestLessInputStream testLessInputStream = new TestLessInputStreamBuilder().build();
invokeMethod( forkStarter, "fork", types, null,
new PropertiesWrapper( Collections.<String, String>emptyMap() ),
new ForkClient( reporterFactory, testLessInputStream, 1 ),
new SurefireProperties(), 1, testLessInputStream, new LegacyForkNodeFactory(), true );
testLessInputStream.close();
}
private static class ClasspathConfig extends AbstractPathConfiguration
{
ClasspathConfig()
{
this( Classpath.emptyClasspath(), false, false );
}
private ClasspathConfig( Classpath surefireClasspathUrls, boolean enableAssertions, boolean childDelegation )
{
super( surefireClasspathUrls, enableAssertions, childDelegation );
}
@Override
public Classpath getTestClasspath()
{
return Classpath.emptyClasspath();
}
@Override
public boolean isModularPathConfig()
{
return false;
}
@Override
public boolean isClassPathConfig()
{
return true;
}
@Override
protected Classpath getInprocClasspath()
{
return Classpath.emptyClasspath();
}
}
}