Repository: maven-surefire Updated Branches: refs/heads/master a1ecfc022 -> 648c96717
[SUREFIRE-1295] Attribute JVM crashes to tests Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/364b0c9e Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/364b0c9e Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/364b0c9e Branch: refs/heads/master Commit: 364b0c9e8ae56916f0b9aead2a26f07ed57befca Parents: 059bd02 Author: Tibor17 <tibo...@lycos.com> Authored: Mon Nov 28 23:16:20 2016 +0100 Committer: Tibor17 <tibo...@lycos.com> Committed: Mon Nov 28 23:16:20 2016 +0100 ---------------------------------------------------------------------- .../surefire/booterclient/ForkStarter.java | 39 +++++++++- .../booterclient/output/ForkClient.java | 81 ++++++++++++++------ 2 files changed, 94 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/364b0c9e/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java index d512f24..3981c79 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java @@ -114,6 +114,8 @@ import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull */ public class ForkStarter { + private static final String EXECUTION_EXCEPTION = "ExecutionException"; + private static final long PING_IN_SECONDS = 10; private static final int TIMEOUT_CHECK_PERIOD_MILLIS = 100; @@ -436,6 +438,7 @@ public class ForkStarter throws SurefireBooterForkException { RunResult globalResult = new RunResult( 0, 0, 0, 0 ); + SurefireBooterForkException exception = null; for ( Future<RunResult> result : results ) { try @@ -459,10 +462,31 @@ public class ForkStarter catch ( ExecutionException e ) { Throwable realException = e.getCause(); - String error = realException == null ? "" : realException.getLocalizedMessage(); - throw new SurefireBooterForkException( "ExecutionException " + error, realException ); + if ( realException == null ) + { + if ( exception == null ) + { + exception = new SurefireBooterForkException( EXECUTION_EXCEPTION ); + } + } + else + { + String previousError = ""; + if ( exception != null && !EXECUTION_EXCEPTION.equals( exception.getLocalizedMessage().trim() ) ) + { + previousError = exception.getLocalizedMessage() + "\n"; + } + String error = previousError + EXECUTION_EXCEPTION + " " + realException.getLocalizedMessage(); + exception = new SurefireBooterForkException( error, realException ); + } } } + + if ( exception != null ) + { + throw exception; + } + return globalResult; } @@ -566,6 +590,7 @@ public class ForkStarter log.debug( "Forking command line: " + cli ); + Integer result = null; RunResult runResult = null; SurefireBooterForkException booterForkException = null; try @@ -577,7 +602,7 @@ public class ForkStarter currentForkClients.add( forkClient ); - int result = future.call(); + result = future.call(); if ( forkClient.hadTimeout() ) { @@ -622,10 +647,16 @@ public class ForkStarter } 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 RuntimeException( "The forked VM terminated without properly saying goodbye. VM crash or System.exit called?" - + "\nCommand was " + cli.toString() + detail, cause ); + + "\nCommand was " + cli.toString() + detail + errorCode + testsInProgress, cause ); } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/364b0c9e/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java index e6e5a6e..46d1115 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java @@ -19,27 +19,31 @@ package org.apache.maven.plugin.surefire.booterclient.output; * under the License. */ +import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream; +import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; +import org.apache.maven.plugin.surefire.report.DefaultReporterFactory; +import org.apache.maven.shared.utils.cli.StreamConsumer; +import org.apache.maven.surefire.report.ConsoleOutputReceiver; +import org.apache.maven.surefire.report.ReportEntry; +import org.apache.maven.surefire.report.ReporterException; +import org.apache.maven.surefire.report.RunListener; +import org.apache.maven.surefire.report.StackTraceWriter; + import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.nio.ByteBuffer; import java.util.NoSuchElementException; import java.util.Properties; +import java.util.Queue; +import java.util.Set; import java.util.StringTokenizer; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; -import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.NotifiableTestStream; -import org.apache.maven.plugin.surefire.report.DefaultReporterFactory; -import org.apache.maven.shared.utils.cli.StreamConsumer; -import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; -import org.apache.maven.surefire.report.ConsoleOutputReceiver; -import org.apache.maven.surefire.report.ReportEntry; -import org.apache.maven.surefire.report.ReporterException; -import org.apache.maven.surefire.report.RunListener; -import org.apache.maven.surefire.report.StackTraceWriter; - import static java.lang.Integer.decode; import static java.lang.Integer.parseInt; import static java.lang.System.currentTimeMillis; @@ -52,14 +56,14 @@ import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STD import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STDOUT; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_STOP_ON_NEXT_TEST; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_SYSPROPS; +import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED; +import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_STARTING; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_ASSUMPTIONFAILURE; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_ERROR; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_FAILED; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_SKIPPED; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_STARTING; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TEST_SUCCEEDED; -import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_COMPLETED; -import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_TESTSET_STARTING; import static org.apache.maven.surefire.booter.ForkingRunListener.BOOTERCODE_WARNING; import static org.apache.maven.surefire.booter.Shutdown.KILL; import static org.apache.maven.surefire.report.CategorizedReportEntry.reportEntry; @@ -73,7 +77,7 @@ import static org.apache.maven.surefire.util.internal.StringUtils.unescapeString * @author Kristian Rosenvold */ public class ForkClient - implements StreamConsumer + implements StreamConsumer { private static final long START_TIME_ZERO = 0L; private static final long START_TIME_NEGATIVE_TIMEOUT = -1L; @@ -86,6 +90,8 @@ public class ForkClient private final NotifiableTestStream notifiableTestStream; + private final Queue<String> testsInProgress = new ConcurrentLinkedQueue<String>(); + /** * <t>testSetStartedAt</t> is set to non-zero after received * {@link org.apache.maven.surefire.booter.ForkingRunListener#BOOTERCODE_TESTSET_STARTING test-set}. @@ -185,35 +191,56 @@ public class ForkClient case BOOTERCODE_TESTSET_STARTING: getOrCreateReporter( channelNumber ) .testSetStarting( createReportEntry( remaining ) ); + setCurrentStartTime(); break; case BOOTERCODE_TESTSET_COMPLETED: + testsInProgress.clear(); + getOrCreateReporter( channelNumber ) .testSetCompleted( createReportEntry( remaining ) ); break; case BOOTERCODE_TEST_STARTING: + ReportEntry reportEntry = createReportEntry( remaining ); + testsInProgress.offer( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) .testStarting( createReportEntry( remaining ) ); break; case BOOTERCODE_TEST_SUCCEEDED: + reportEntry = createReportEntry( remaining ); + testsInProgress.remove( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) - .testSucceeded( createReportEntry( remaining ) ); + .testSucceeded( reportEntry ); break; case BOOTERCODE_TEST_FAILED: + reportEntry = createReportEntry( remaining ); + testsInProgress.remove( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) - .testFailed( createReportEntry( remaining ) ); + .testFailed( reportEntry ); break; case BOOTERCODE_TEST_SKIPPED: + reportEntry = createReportEntry( remaining ); + testsInProgress.remove( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) - .testSkipped( createReportEntry( remaining ) ); + .testSkipped( reportEntry ); break; case BOOTERCODE_TEST_ERROR: + reportEntry = createReportEntry( remaining ); + testsInProgress.remove( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) - .testError( createReportEntry( remaining ) ); + .testError( reportEntry ); break; case BOOTERCODE_TEST_ASSUMPTIONFAILURE: + reportEntry = createReportEntry( remaining ); + testsInProgress.remove( reportEntry.getSourceName() ); + getOrCreateReporter( channelNumber ) - .testAssumptionFailure( createReportEntry( remaining ) ); + .testAssumptionFailure( reportEntry ); break; case BOOTERCODE_SYSPROPS: int keyEnd = remaining.indexOf( "," ); @@ -287,19 +314,19 @@ public class ForkClient { byte[] convertedBytes = unescaped.array(); getOrCreateConsoleOutputReceiver( channelNumber ) - .writeTestOutput( convertedBytes, unescaped.position(), unescaped.remaining(), isStdout ); + .writeTestOutput( convertedBytes, unescaped.position(), unescaped.remaining(), isStdout ); } else { byte[] convertedBytes = new byte[unescaped.remaining()]; unescaped.get( convertedBytes, 0, unescaped.remaining() ); getOrCreateConsoleOutputReceiver( channelNumber ) - .writeTestOutput( convertedBytes, 0, convertedBytes.length, isStdout ); + .writeTestOutput( convertedBytes, 0, convertedBytes.length, isStdout ); } } public final void consumeMultiLineContent( String s ) - throws IOException + throws IOException { BufferedReader stringReader = new BufferedReader( new StringReader( s ) ); for ( String s1 = stringReader.readLine(); s1 != null; s1 = stringReader.readLine() ) @@ -325,7 +352,7 @@ public class ForkClient String elapsedStr = tokens.nextToken(); Integer elapsed = "null".equals( elapsedStr ) ? null : decode( elapsedStr ); final StackTraceWriter stackTraceWriter = - tokens.hasMoreTokens() ? deserializeStackTraceWriter( tokens ) : null; + tokens.hasMoreTokens() ? deserializeStackTraceWriter( tokens ) : null; return reportEntry( source, name, group, stackTraceWriter, elapsed, message ); } @@ -411,4 +438,14 @@ public class ForkClient { return errorInFork != null; } + + public Set<String> testsInProgress() + { + return new TreeSet<String>( testsInProgress ); + } + + public boolean hasTestsInProgress() + { + return !testsInProgress.isEmpty(); + } }