private RunResult fork()

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;
    }