
org.apache.maven.surefire.booter.ForkedBooter Maven / Gradle / Ivy
package org.apache.maven.surefire.booter;
/*
* 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.surefire.providerapi.ProviderParameters;
import org.apache.maven.surefire.providerapi.SurefireProvider;
import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.suite.RunResult;
import org.apache.maven.surefire.testset.TestSetFailedException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.lang.Math.max;
import static java.lang.System.err;
import static java.lang.System.out;
import static java.lang.System.setErr;
import static java.lang.System.setOut;
import static java.lang.Thread.currentThread;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.maven.surefire.booter.CommandReader.getReader;
import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_BYE;
import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_ERROR;
import static org.apache.maven.surefire.booter.ForkingRunListener.encode;
import static org.apache.maven.surefire.booter.SystemPropertyManager.setSystemProperties;
import static org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg;
import static org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDaemonThreadFactory;
import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
/**
* The part of the booter that is unique to a forked vm.
*
* Deals with deserialization of the booter wire-level protocol
*
*
* @author Jason van Zyl
* @author Emmanuel Venisse
* @author Kristian Rosenvold
*/
public final class ForkedBooter
{
private static final long DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS = 30;
private static final long PING_TIMEOUT_IN_SECONDS = 20;
private static final long ONE_SECOND_IN_MILLIS = 1000;
private static volatile ScheduledThreadPoolExecutor jvmTerminator;
private static volatile long systemExitTimeoutInSeconds = DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS;
/**
* This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and
* then calls the Surefire class' run method. The system exit code will be 1 if an exception is thrown.
*
* @param args Commandline arguments
*/
public static void main( String... args )
{
final CommandReader reader = startupMasterProcessReader();
final ExecutorService pingScheduler = isDebugging() ? null : listenToShutdownCommands( reader );
final PrintStream originalOut = out;
try
{
final String tmpDir = args[0];
final String dumpFileName = args[1];
final String surefirePropsFileName = args[2];
BooterDeserializer booterDeserializer =
new BooterDeserializer( createSurefirePropertiesIfFileExists( tmpDir, surefirePropsFileName ) );
if ( args.length > 3 )
{
final String effectiveSystemPropertiesFileName = args[3];
setSystemProperties( new File( tmpDir, effectiveSystemPropertiesFileName ) );
}
final ProviderConfiguration providerConfiguration = booterDeserializer.deserialize();
DumpErrorSingleton.getSingleton().init( dumpFileName, providerConfiguration.getReporterConfiguration() );
final StartupConfiguration startupConfiguration = booterDeserializer.getProviderConfiguration();
systemExitTimeoutInSeconds =
providerConfiguration.systemExitTimeout( DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
final TypeEncodedValue forkedTestSet = providerConfiguration.getTestForFork();
final boolean readTestsFromInputStream = providerConfiguration.isReadTestsFromInStream();
final ClasspathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();
if ( startupConfiguration.isManifestOnlyJarRequestedAndUsable() )
{
classpathConfiguration.trickClassPathWhenManifestOnlyClasspath();
}
final ClassLoader classLoader = currentThread().getContextClassLoader();
classLoader.setDefaultAssertionStatus( classpathConfiguration.isEnableAssertions() );
startupConfiguration.writeSurefireTestClasspathProperty();
final Object testSet;
if ( forkedTestSet != null )
{
testSet = forkedTestSet.getDecodedValue( classLoader );
}
else if ( readTestsFromInputStream )
{
testSet = new LazyTestsToRun( originalOut );
}
else
{
testSet = null;
}
try
{
runSuitesInProcess( testSet, startupConfiguration, providerConfiguration, originalOut );
}
catch ( InvocationTargetException t )
{
DumpErrorSingleton.getSingleton().dumpException( t );
StackTraceWriter stackTraceWriter =
new LegacyPojoStackTraceWriter( "test subsystem", "no method", t.getTargetException() );
StringBuilder stringBuilder = new StringBuilder();
encode( stringBuilder, stackTraceWriter, false );
encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n" , originalOut );
}
catch ( Throwable t )
{
DumpErrorSingleton.getSingleton().dumpException( t );
StackTraceWriter stackTraceWriter = new LegacyPojoStackTraceWriter( "test subsystem", "no method", t );
StringBuilder stringBuilder = new StringBuilder();
encode( stringBuilder, stackTraceWriter, false );
encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n", originalOut );
}
acknowledgedExit( reader, originalOut, pingScheduler );
}
catch ( Throwable t )
{
DumpErrorSingleton.getSingleton().dumpException( t );
// Just throwing does getMessage() and a local trace - we want to call printStackTrace for a full trace
// noinspection UseOfSystemOutOrSystemErr
t.printStackTrace( err );
cancelPingScheduler( pingScheduler );
// noinspection ProhibitedExceptionThrown,CallToSystemExit
exit( 1 );
}
}
private static void cancelPingScheduler( final ExecutorService pingScheduler )
{
if ( pingScheduler != null )
{
try
{
AccessController.doPrivileged( new PrivilegedAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy