in maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java [480:654]
private RunResult fork(
Object testSet,
PropertiesWrapper providerProperties,
ForkClient forkClient,
SurefireProperties effectiveSystemProperties,
int forkNumber,
AbstractCommandReader commandReader,
ForkNodeFactory forkNodeFactory,
boolean readTestsFromInStream)
throws SurefireBooterForkException {
CloseableCloser closer = new CloseableCloser(forkNumber, commandReader);
final String tempDir;
final File surefireProperties;
final File systPropsFile;
final ForkChannel forkChannel;
File dumpLogDir = replaceForkThreadsInPath(startupReportConfiguration.getReportsDirectory(), forkNumber);
try {
ForkNodeArguments forkNodeArguments = new ForkedNodeArg(
forkConfiguration.isDebug(),
forkNumber,
dumpLogDir,
randomUUID().toString());
forkChannel = forkNodeFactory.createForkChannel(forkNodeArguments);
closer.addCloseable(forkChannel);
tempDir = forkConfiguration.getTempDirectory().getCanonicalPath();
BooterSerializer booterSerializer = new BooterSerializer(forkConfiguration);
Long pluginPid = forkConfiguration.getPluginPlatform().getPluginPid();
log.debug("Determined Maven Process ID " + pluginPid);
String connectionString = forkChannel.getForkNodeConnectionString();
log.debug("Fork Channel [" + forkNumber + "] connection string '" + connectionString
+ "' for the implementation " + forkChannel.getClass());
surefireProperties = booterSerializer.serialize(
providerProperties,
providerConfiguration,
startupConfiguration,
testSet,
readTestsFromInStream,
pluginPid,
forkNumber,
connectionString);
if (effectiveSystemProperties != null) {
SurefireProperties filteredProperties =
createCopyAndReplaceForkNumPlaceholder(effectiveSystemProperties, forkNumber);
systPropsFile = writePropertiesFile(
filteredProperties,
forkConfiguration.getTempDirectory(),
"surefire_" + SYSTEM_PROPERTIES_FILE_COUNTER.getAndIncrement(),
forkConfiguration.isDebug());
} else {
systPropsFile = null;
}
} catch (IOException e) {
throw new SurefireBooterForkException("Error creating properties files for forking", e);
}
Commandline cli = forkConfiguration.createCommandLine(startupConfiguration, forkNumber, dumpLogDir);
cli.createArg().setValue(tempDir);
cli.createArg().setValue(DUMP_FILE_PREFIX + forkNumber);
cli.createArg().setValue(surefireProperties.getName());
if (systPropsFile != null) {
cli.createArg().setValue(systPropsFile.getName());
}
ThreadedStreamConsumer eventConsumer = new ThreadedStreamConsumer(forkClient);
closer.addCloseable(eventConsumer);
log.debug("Forking command line: " + cli);
Integer result = null;
RunResult runResult = null;
SurefireBooterForkException booterForkException = null;
Stoppable err = null;
DefaultReporterFactory reporter = forkClient.getDefaultReporterFactory();
currentForkClients.add(forkClient);
CountdownCloseable countdownCloseable =
new CountdownCloseable(eventConsumer, forkChannel.getCountdownCloseablePermits());
try (CommandlineExecutor exec = new CommandlineExecutor(cli, countdownCloseable)) {
forkChannel.tryConnectToClient();
CommandlineStreams streams = exec.execute();
closer.addCloseable(streams);
err = bindErrorStream(forkNumber, countdownCloseable, streams, forkClient.getConsoleOutputReceiver());
forkChannel.bindCommandReader(commandReader, streams.getStdInChannel());
forkChannel.bindEventHandler(eventConsumer, countdownCloseable, streams.getStdOutChannel());
log.debug("Fork Channel [" + forkNumber + "] connected to the client.");
result = exec.awaitExit();
if (forkClient.hadTimeout()) {
runResult = timeout(reporter.getGlobalRunStatistics().getRunResult());
} else if (result != SUCCESS) {
booterForkException =
new SurefireBooterForkException("Error occurred in starting fork, check output in log");
}
} catch (InterruptedException e) {
log.error("Closing the streams after (InterruptedException) '" + e.getLocalizedMessage() + "'");
// maybe implement it in the Future.cancel() of the extension or similar
forkChannel.disable();
if (err != null) {
err.disable();
}
} catch (Exception e) {
// CommandLineException from pipes and IOException from sockets
runResult = failure(reporter.getGlobalRunStatistics().getRunResult(), e);
String cliErr = e.getLocalizedMessage();
Throwable cause = e.getCause();
booterForkException =
new SurefireBooterForkException("Error while executing forked tests.", cliErr, cause, runResult);
} finally {
log.debug("Closing the fork " + forkNumber + " after "
+ (forkClient.isSaidGoodBye() ? "saying GoodBye." : "not saying Good Bye."));
currentForkClients.remove(forkClient);
closer.close();
if (runResult == null) {
runResult = reporter.getGlobalRunStatistics().getRunResult();
}
forkClient.close(runResult.isTimeout());
if (!runResult.isTimeout()) {
Throwable cause = booterForkException == null ? null : booterForkException.getCause();
String detail = booterForkException == null ? "" : "\n" + booterForkException.getMessage();
if (forkClient.isErrorInFork()) {
StackTraceWriter errorInFork = forkClient.getErrorInFork();
String errorInForkMessage = errorInFork == null
? null
: errorInFork.getThrowable().getLocalizedMessage();
boolean showStackTrace =
providerConfiguration.getMainCliOptions().contains(SHOW_ERRORS);
String stackTrace = errorInForkMessage;
if (showStackTrace) {
if (errorInFork != null) {
if (stackTrace == null) {
stackTrace = "";
} else {
stackTrace += NL;
}
stackTrace += errorInFork.writeTrimmedTraceToString();
}
}
//noinspection ThrowFromFinallyBlock
throw new SurefireBooterForkException(
"There was an error in the forked process"
+ detail
+ (stackTrace == null ? "" : "\n" + stackTrace),
cause);
}
if (!forkClient.isSaidGoodBye()) {
String errorCode = result == null ? "" : "\nProcess Exit Code: " + result;
String testsInProgress = forkClient.hasTestsInProgress() ? "\nCrashed tests:" : "";
for (String test : forkClient.testsInProgress()) {
testsInProgress += "\n" + test;
}
// noinspection ThrowFromFinallyBlock
throw new SurefireBooterForkException(
"The forked VM terminated without properly saying goodbye. VM crash or System.exit called?"
+ "\nCommand was " + cli.toString() + detail + errorCode + testsInProgress,
cause);
}
}
if (booterForkException != null) {
throw booterForkException;
}
}
return runResult;
}