This is an automated email from the ASF dual-hosted git repository. olamy pushed a commit to branch test-junit-platform-runner-junit4-parallel-stack in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit a41be8995b4c085e8a7d5ee4ccdb1be35eff5e33 Author: Olivier Lamy <[email protected]> AuthorDate: Tue Dec 16 22:05:29 2025 +1000 use stack trace to locate current test class in use Signed-off-by: Olivier Lamy <[email protected]> --- .../surefire/booterclient/output/ForkClient.java | 13 +-- .../output/ForkedProcessEventNotifier.java | 3 +- .../ForkedProcessStandardOutErrEventListener.java | 2 +- .../surefire/report/ConsoleOutputFileReporter.java | 96 ++++++++++++++++++---- .../apache/maven/surefire/stream/EventDecoder.java | 20 +++-- .../booterclient/ForkingRunListenerTest.java | 2 - .../booterclient/output/ForkClientTest.java | 8 +- .../output/ThreadedStreamConsumerTest.java | 2 +- .../extensions/ForkedProcessEventNotifierTest.java | 3 +- .../maven/surefire/stream/EventDecoderTest.java | 36 ++++---- .../api/event/AbstractStandardStreamEvent.java | 8 +- .../surefire/api/event/StandardStreamErrEvent.java | 4 +- .../event/StandardStreamErrWithNewLineEvent.java | 4 +- .../surefire/api/event/StandardStreamOutEvent.java | 4 +- .../event/StandardStreamOutWithNewLineEvent.java | 4 +- .../surefire/api/report/OutputReportEntry.java | 6 ++ .../surefire/api/report/StackTraceProvider.java | 55 +++++++++++++ .../surefire/api/report/TestOutputReportEntry.java | 35 +++++++- .../surefire/api/stream/AbstractStreamDecoder.java | 72 ++++++++-------- .../surefire/booter/spi/EventChannelEncoder.java | 15 ++-- .../booter/spi/EventChannelEncoderTest.java | 24 +++--- .../surefire/its/JUnit47RedirectOutputIT.java | 3 - 22 files changed, 290 insertions(+), 129 deletions(-) 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 cecc271c6..4ab96d6da 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 @@ -201,15 +201,15 @@ public void handle(String key, String value, RunMode runMode, Long testRunId) { private final class StdOutListener implements ForkedProcessStandardOutErrEventListener { @Override - public void handle(String output, boolean newLine, RunMode runMode, Long testRunId) { - writeTestOutput(output, true, newLine, runMode, testRunId); + public void handle(String output, boolean newLine, RunMode runMode, Long testRunId, String stack) { + writeTestOutput(output, true, newLine, runMode, testRunId, stack); } } private final class StdErrListener implements ForkedProcessStandardOutErrEventListener { @Override - public void handle(String output, boolean newLine, RunMode runMode, Long testRunId) { - writeTestOutput(output, false, newLine, runMode, testRunId); + public void handle(String output, boolean newLine, RunMode runMode, Long testRunId, String stack) { + writeTestOutput(output, false, newLine, runMode, testRunId, stack); } } @@ -336,9 +336,10 @@ void dumpToLoFile(String msg) { util.dumpStreamText(msg, reportsDir, forkNumber); } - private void writeTestOutput(String output, boolean isStdout, boolean newLine, RunMode runMode, Long testRunId) { + private void writeTestOutput( + String output, boolean isStdout, boolean newLine, RunMode runMode, Long testRunId, String stack) { getConsoleOutputReceiver() - .writeTestOutput(new TestOutputReportEntry(output, isStdout, newLine, runMode, testRunId)); + .writeTestOutput(new TestOutputReportEntry(output, isStdout, newLine, runMode, testRunId, stack)); } public Map<String, String> getTestVmSystemProperties() { diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java index a3cedd035..e20131d70 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessEventNotifier.java @@ -178,7 +178,8 @@ public void notifyEvent(Event event) { standardStreamEvent.getMessage(), newLine, standardStreamEvent.getRunMode(), - standardStreamEvent.getTestRunId()); + standardStreamEvent.getTestRunId(), + standardStreamEvent.getStack()); } } else if (event.isSysPropCategory()) { SystemPropertyEvent systemPropertyEvent = (SystemPropertyEvent) event; diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStandardOutErrEventListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStandardOutErrEventListener.java index fc966cd95..bff039ff5 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStandardOutErrEventListener.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedProcessStandardOutErrEventListener.java @@ -25,5 +25,5 @@ * @since 3.0.0-M4 */ public interface ForkedProcessStandardOutErrEventListener { - void handle(String output, boolean newLine, RunMode runMode, Long testRunId); + void handle(String output, boolean newLine, RunMode runMode, Long testRunId, String stack); } diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java index 19a11ae77..556c35c18 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ConsoleOutputFileReporter.java @@ -20,11 +20,13 @@ import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicStampedReference; import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton; @@ -56,6 +58,8 @@ public class ConsoleOutputFileReporter implements TestcycleConsoleOutputReceiver private final AtomicStampedReference<FilterOutputStream> fileOutputStream = new AtomicStampedReference<>(null, OPEN); + private final Map<String, FilterOutputStream> outputStreams = new ConcurrentHashMap<>(); + private volatile String reportEntryName; public ConsoleOutputFileReporter( @@ -91,26 +95,44 @@ public synchronized void writeTestOutput(TestOutputReportEntry reportEntry) { // This method is called in single thread T1 per fork JVM (see ThreadedStreamConsumer). // The close() method is called in main Thread T2. int[] status = new int[1]; - FilterOutputStream os = fileOutputStream.get(status); - if (status[0] != CLOSED) { - if (os == null) { + fileOutputStream.get(status); + if (status[0] == CLOSED) { + return; + } + + // Determine the target class name based on stack trace or reportEntryName + String targetClassName = extractTestClassFromStack(reportEntry.getStack()); + if (targetClassName == null) { + targetClassName = reportEntryName; + } + // If still null, use "null" as the file name (for output before any test starts) + if (targetClassName == null) { + targetClassName = "null"; + } + + // Get or create output stream for this test class + FilterOutputStream os = outputStreams.computeIfAbsent(targetClassName, className -> { + try { if (!reportsDirectory.exists()) { //noinspection ResultOfMethodCallIgnored reportsDirectory.mkdirs(); } - File file = getReportFile(reportsDirectory, reportEntryName, reportNameSuffix, "-output.txt"); - os = new BufferedOutputStream(new FileOutputStream(file), STREAM_BUFFER_SIZE); - fileOutputStream.set(os, OPEN); - } - String output = reportEntry.getLog(); - if (output == null) { - output = "null"; - } - Charset charset = Charset.forName(encoding); - os.write(output.getBytes(charset)); - if (reportEntry.isNewLine()) { - os.write(NL.getBytes(charset)); + File file = getReportFile(reportsDirectory, className, reportNameSuffix, "-output.txt"); + return new BufferedOutputStream(Files.newOutputStream(file.toPath()), STREAM_BUFFER_SIZE); + } catch (IOException e) { + dumpException(e); + throw new UncheckedIOException(e); } + }); + + String output = reportEntry.getLog(); + if (output == null) { + output = "null"; + } + Charset charset = Charset.forName(encoding); + os.write(output.getBytes(charset)); + if (reportEntry.isNewLine()) { + os.write(NL.getBytes(charset)); } } catch (IOException e) { dumpException(e); @@ -118,6 +140,37 @@ public synchronized void writeTestOutput(TestOutputReportEntry reportEntry) { } } + /** + * Extracts the test class name from the stack trace. + * Stack format: className#method;className#method;... + * Returns the first class name that looks like a test class. + */ + private String extractTestClassFromStack(String stack) { + if (stack == null || stack.isEmpty()) { + return null; + } + // The stack contains entries like "className#method;className#method;..." + // We look for the test class which typically is the first entry or an entry with "Test" in the name + String[] entries = stack.split(";"); + for (String entry : entries) { + int hashIndex = entry.indexOf('#'); + if (hashIndex > 0) { + String className = entry.substring(0, hashIndex); + // Skip JDK classes and known framework classes + if (!className.startsWith("java.") + && !className.startsWith("sun.") + && !className.startsWith("jdk.") + && !className.startsWith("org.junit.") + && !className.startsWith("junit.") + && !className.startsWith("org.apache.maven.surefire.") + && !className.startsWith("org.apache.maven.shadefire.")) { + return className; + } + } + } + return null; + } + @SuppressWarnings("checkstyle:emptyblock") private void closeNullReportFile(ReportEntry reportEntry) { try { @@ -148,6 +201,17 @@ private void close(boolean closeReattempt) throws IOException { if (os != null && status[0] == OPEN) { os.close(); } + // Close all output streams in the map + for (FilterOutputStream stream : outputStreams.values()) { + try { + stream.close(); + } catch (IOException e) { + dumpException(e); + } + } + if (!closeReattempt) { + outputStreams.clear(); + } } } diff --git a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java index 0bfc1e26b..ba5bd7c45 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/surefire/stream/EventDecoder.java @@ -208,7 +208,7 @@ protected final SegmentType[] nextSegmentType(@Nonnull ForkedProcessEventType ev case BOOTERCODE_STDOUT_NEW_LINE: case BOOTERCODE_STDERR: case BOOTERCODE_STDERR_NEW_LINE: - return EVENT_WITH_RUNMODE_TID_AND_ONE_STRING; + return EVENT_WITH_RUNMODE_TID_AND_TWO_STRINGS; case BOOTERCODE_SYSPROPS: return EVENT_WITH_RUNMODE_TID_AND_TWO_STRINGS; case BOOTERCODE_TESTSET_STARTING: @@ -255,19 +255,21 @@ protected final Event toMessage(@Nonnull ForkedProcessEventType eventType, @Nonn checkArguments(memento, 1); return new ConsoleWarningEvent((String) memento.getData().get(0)); case BOOTERCODE_STDOUT: - checkArguments(memento, 3); - return new StandardStreamOutEvent(memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2)); + checkArguments(memento, 4); + return new StandardStreamOutEvent( + memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2), memento.ofDataAt(3)); case BOOTERCODE_STDOUT_NEW_LINE: - checkArguments(memento, 3); + checkArguments(memento, 4); return new StandardStreamOutWithNewLineEvent( - memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2)); + memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2), memento.ofDataAt(3)); case BOOTERCODE_STDERR: - checkArguments(memento, 3); - return new StandardStreamErrEvent(memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2)); + checkArguments(memento, 4); + return new StandardStreamErrEvent( + memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2), memento.ofDataAt(3)); case BOOTERCODE_STDERR_NEW_LINE: - checkArguments(memento, 3); + checkArguments(memento, 4); return new StandardStreamErrWithNewLineEvent( - memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2)); + memento.ofDataAt(0), memento.ofDataAt(1), memento.ofDataAt(2), memento.ofDataAt(3)); case BOOTERCODE_SYSPROPS: checkArguments(memento, 4); return new SystemPropertyEvent( diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java index d25e9b4ae..4a5c58141 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java @@ -65,7 +65,6 @@ import static org.apache.maven.surefire.api.util.internal.Channels.newChannel; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; /** * @author Kristian Rosenvold @@ -277,7 +276,6 @@ private static List<Event> streamToEvent(byte[] stream) throws Exception { try (EventConsumerThread t = new EventConsumerThread("t", channel, handler, countdown, arguments)) { t.start(); countdown.awaitClosed(); - verifyZeroInteractions(logger); assertThat(arguments.isCalled()).isFalse(); for (int i = 0, size = handler.countEventsInCache(); i < size; i++) { events.add(handler.pullEvent()); diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java index 4013cb074..b4317e9f0 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClientTest.java @@ -384,7 +384,7 @@ public void shouldReceiveStdOut() { when(factory.createTestReportListener()).thenReturn(receiver); NotifiableTestStream notifiableTestStream = mock(NotifiableTestStream.class); ForkClient client = new ForkClient(factory, notifiableTestStream, 0); - client.handleEvent(new StandardStreamOutEvent(NORMAL_RUN, 1L, "msg")); + client.handleEvent(new StandardStreamOutEvent(NORMAL_RUN, 1L, "msg", null)); verifyZeroInteractions(notifiableTestStream); verify(factory, times(1)).createTestReportListener(); verifyNoMoreInteractions(factory); @@ -410,7 +410,7 @@ public void shouldReceiveStdOutNewLine() { when(factory.createTestReportListener()).thenReturn(receiver); NotifiableTestStream notifiableTestStream = mock(NotifiableTestStream.class); ForkClient client = new ForkClient(factory, notifiableTestStream, 0); - client.handleEvent(new StandardStreamOutWithNewLineEvent(NORMAL_RUN, 1L, "msg")); + client.handleEvent(new StandardStreamOutWithNewLineEvent(NORMAL_RUN, 1L, "msg", null)); verifyZeroInteractions(notifiableTestStream); verify(factory, times(1)).createTestReportListener(); verifyNoMoreInteractions(factory); @@ -436,7 +436,7 @@ public void shouldReceiveStdErr() { when(factory.createTestReportListener()).thenReturn(receiver); NotifiableTestStream notifiableTestStream = mock(NotifiableTestStream.class); ForkClient client = new ForkClient(factory, notifiableTestStream, 0); - client.handleEvent(new StandardStreamErrEvent(NORMAL_RUN, 1L, "msg")); + client.handleEvent(new StandardStreamErrEvent(NORMAL_RUN, 1L, "msg", null)); verifyZeroInteractions(notifiableTestStream); verify(factory, times(1)).createTestReportListener(); verifyNoMoreInteractions(factory); @@ -462,7 +462,7 @@ public void shouldReceiveStdErrNewLine() { when(factory.createTestReportListener()).thenReturn(receiver); NotifiableTestStream notifiableTestStream = mock(NotifiableTestStream.class); ForkClient client = new ForkClient(factory, notifiableTestStream, 0); - client.handleEvent(new StandardStreamErrWithNewLineEvent(NORMAL_RUN, 1L, "msg")); + client.handleEvent(new StandardStreamErrWithNewLineEvent(NORMAL_RUN, 1L, "msg", null)); verifyZeroInteractions(notifiableTestStream); verify(factory, times(1)).createTestReportListener(); verifyNoMoreInteractions(factory); diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java index 1672f5857..12492ffe6 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ThreadedStreamConsumerTest.java @@ -94,7 +94,7 @@ public void handleEvent(@Nonnull Event event) { long t1 = System.currentTimeMillis(); - Event event = new StandardStreamOutWithNewLineEvent(NORMAL_RUN, 1L, ""); + Event event = new StandardStreamOutWithNewLineEvent(NORMAL_RUN, 1L, "", null); for (int i = 0; i < 5_000_000; i++) { streamConsumer.handleEvent(event); } diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java index 26237831a..2a0cf7802 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/ForkedProcessEventNotifierTest.java @@ -956,7 +956,8 @@ private static class StandardOutErrEventAssertionListener implements ForkedProce this.newLine = newLine; } - public void handle(String output, boolean newLine, RunMode runMode, Long testRunId) { + @Override + public void handle(String output, boolean newLine, RunMode runMode, Long testRunId, String stack) { called.set(true); assertThat(runMode).isEqualTo(this.runMode); diff --git a/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java index a49d7c739..c1659fea9 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/surefire/stream/EventDecoderTest.java @@ -158,24 +158,24 @@ public void shouldMapEventTypeToSegmentType() { assertThat(segmentTypes).hasSize(3).isEqualTo(new SegmentType[] {STRING_ENCODING, DATA_STRING, END_OF_FRAME}); segmentTypes = decoder.nextSegmentType(BOOTERCODE_STDOUT); - assertThat(segmentTypes) - .hasSize(5) - .isEqualTo(new SegmentType[] {RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME}); + assertThat(segmentTypes).hasSize(6).isEqualTo(new SegmentType[] { + RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME + }); segmentTypes = decoder.nextSegmentType(ForkedProcessEventType.BOOTERCODE_STDOUT_NEW_LINE); - assertThat(segmentTypes) - .hasSize(5) - .isEqualTo(new SegmentType[] {RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME}); + assertThat(segmentTypes).hasSize(6).isEqualTo(new SegmentType[] { + RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME + }); segmentTypes = decoder.nextSegmentType(ForkedProcessEventType.BOOTERCODE_STDERR); - assertThat(segmentTypes) - .hasSize(5) - .isEqualTo(new SegmentType[] {RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME}); + assertThat(segmentTypes).hasSize(6).isEqualTo(new SegmentType[] { + RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME + }); segmentTypes = decoder.nextSegmentType(ForkedProcessEventType.BOOTERCODE_STDERR_NEW_LINE); - assertThat(segmentTypes) - .hasSize(5) - .isEqualTo(new SegmentType[] {RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, END_OF_FRAME}); + assertThat(segmentTypes).hasSize(6).isEqualTo(new SegmentType[] { + RUN_MODE, TEST_RUN_ID, STRING_ENCODING, DATA_STRING, DATA_STRING, END_OF_FRAME + }); segmentTypes = decoder.nextSegmentType(BOOTERCODE_SYSPROPS); assertThat(segmentTypes).hasSize(6).isEqualTo(new SegmentType[] { @@ -397,36 +397,40 @@ public void shouldCreateEvent() throws Exception { assertThat(((ConsoleDebugEvent) event).getMessage()).isNull(); memento = decoder.new Memento(); - memento.getData().addAll(asList(NORMAL_RUN, 1L, "m")); + memento.getData().addAll(asList(NORMAL_RUN, 1L, "m", "stack")); event = decoder.toMessage(BOOTERCODE_STDOUT, memento); assertThat(event).isInstanceOf(StandardStreamOutEvent.class); assertThat(((StandardStreamOutEvent) event).getMessage()).isEqualTo("m"); assertThat(((StandardStreamOutEvent) event).getRunMode()).isEqualTo(NORMAL_RUN); assertThat(((StandardStreamOutEvent) event).getTestRunId()).isEqualTo(1L); + assertThat(((StandardStreamOutEvent) event).getStack()).isEqualTo("stack"); memento = decoder.new Memento(); - memento.getData().addAll(asList(RERUN_TEST_AFTER_FAILURE, 1L, null)); + memento.getData().addAll(asList(RERUN_TEST_AFTER_FAILURE, 1L, null, null)); event = decoder.toMessage(BOOTERCODE_STDOUT_NEW_LINE, memento); assertThat(event).isInstanceOf(StandardStreamOutWithNewLineEvent.class); assertThat(((StandardStreamOutWithNewLineEvent) event).getMessage()).isNull(); assertThat(((StandardStreamOutWithNewLineEvent) event).getRunMode()).isEqualTo(RERUN_TEST_AFTER_FAILURE); assertThat(((StandardStreamOutWithNewLineEvent) event).getTestRunId()).isEqualTo(1L); + assertThat(((StandardStreamOutWithNewLineEvent) event).getStack()).isNull(); memento = decoder.new Memento(); - memento.getData().addAll(asList(RERUN_TEST_AFTER_FAILURE, 1L, null)); + memento.getData().addAll(asList(RERUN_TEST_AFTER_FAILURE, 1L, null, null)); event = decoder.toMessage(BOOTERCODE_STDERR, memento); assertThat(event).isInstanceOf(StandardStreamErrEvent.class); assertThat(((StandardStreamErrEvent) event).getMessage()).isNull(); assertThat(((StandardStreamErrEvent) event).getRunMode()).isEqualTo(RERUN_TEST_AFTER_FAILURE); assertThat(((StandardStreamErrEvent) event).getTestRunId()).isEqualTo(1L); + assertThat(((StandardStreamErrEvent) event).getStack()).isNull(); memento = decoder.new Memento(); - memento.getData().addAll(asList(NORMAL_RUN, 1L, "abc")); + memento.getData().addAll(asList(NORMAL_RUN, 1L, "abc", "stacktrace")); event = decoder.toMessage(BOOTERCODE_STDERR_NEW_LINE, memento); assertThat(event).isInstanceOf(StandardStreamErrWithNewLineEvent.class); assertThat(((StandardStreamErrWithNewLineEvent) event).getMessage()).isEqualTo("abc"); assertThat(((StandardStreamErrWithNewLineEvent) event).getRunMode()).isEqualTo(NORMAL_RUN); assertThat(((StandardStreamErrWithNewLineEvent) event).getTestRunId()).isEqualTo(1L); + assertThat(((StandardStreamErrWithNewLineEvent) event).getStack()).isEqualTo("stacktrace"); memento = decoder.new Memento(); memento.getData().addAll(asList(NORMAL_RUN, 1L, "key", "value")); diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java index c66b5b2af..e7f0b7e2f 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/AbstractStandardStreamEvent.java @@ -30,13 +30,15 @@ public abstract class AbstractStandardStreamEvent extends Event { private final RunMode runMode; private final Long testRunId; private final String message; + private final String stack; protected AbstractStandardStreamEvent( - ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message) { + ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message, String stack) { super(eventType); this.runMode = runMode; this.testRunId = testRunId; this.message = message; + this.stack = stack; } public RunMode getRunMode() { @@ -51,6 +53,10 @@ public String getMessage() { return message; } + public String getStack() { + return stack; + } + @Override public boolean isControlCategory() { return false; diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java index 27ce8e641..888f7a686 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrEvent.java @@ -28,7 +28,7 @@ * @since 3.0.0-M5 */ public final class StandardStreamErrEvent extends AbstractStandardStreamEvent { - public StandardStreamErrEvent(RunMode runMode, Long testRunId, String message) { - super(BOOTERCODE_STDERR, runMode, testRunId, message); + public StandardStreamErrEvent(RunMode runMode, Long testRunId, String message, String stack) { + super(BOOTERCODE_STDERR, runMode, testRunId, message, stack); } } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java index 29ca5ef13..0162cf144 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamErrWithNewLineEvent.java @@ -28,7 +28,7 @@ * @since 3.0.0-M5 */ public final class StandardStreamErrWithNewLineEvent extends AbstractStandardStreamEvent { - public StandardStreamErrWithNewLineEvent(RunMode runMode, Long testRunId, String message) { - super(BOOTERCODE_STDERR_NEW_LINE, runMode, testRunId, message); + public StandardStreamErrWithNewLineEvent(RunMode runMode, Long testRunId, String message, String stack) { + super(BOOTERCODE_STDERR_NEW_LINE, runMode, testRunId, message, stack); } } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java index 22e96c33d..896872069 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutEvent.java @@ -28,7 +28,7 @@ * @since 3.0.0-M5 */ public final class StandardStreamOutEvent extends AbstractStandardStreamEvent { - public StandardStreamOutEvent(RunMode runMode, Long testRunId, String message) { - super(BOOTERCODE_STDOUT, runMode, testRunId, message); + public StandardStreamOutEvent(RunMode runMode, Long testRunId, String message, String stack) { + super(BOOTERCODE_STDOUT, runMode, testRunId, message, stack); } } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java index 9f5356c5e..9d7da8447 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/event/StandardStreamOutWithNewLineEvent.java @@ -28,7 +28,7 @@ * @since 3.0.0-M5 */ public final class StandardStreamOutWithNewLineEvent extends AbstractStandardStreamEvent { - public StandardStreamOutWithNewLineEvent(RunMode runMode, Long testRunId, String message) { - super(BOOTERCODE_STDOUT_NEW_LINE, runMode, testRunId, message); + public StandardStreamOutWithNewLineEvent(RunMode runMode, Long testRunId, String message, String stack) { + super(BOOTERCODE_STDOUT_NEW_LINE, runMode, testRunId, message, stack); } } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/OutputReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/OutputReportEntry.java index d5bb29be7..ef01472b4 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/OutputReportEntry.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/OutputReportEntry.java @@ -40,4 +40,10 @@ public interface OutputReportEntry { boolean isStdOut(); boolean isNewLine(); + + /** + * The stack trace of the thread that produced the output. + * claasName#method;className#method;... + */ + String getStack(); } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/StackTraceProvider.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/StackTraceProvider.java new file mode 100644 index 000000000..dd5e44086 --- /dev/null +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/StackTraceProvider.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package org.apache.maven.surefire.api.report; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Util class for stack trace providing from Java 9 this will use StackWalker by reflection. + */ +public class StackTraceProvider { + + private static Object stackWalker; + + static { + try { + Class<?> stackWalkerClass = + Thread.currentThread().getContextClassLoader().loadClass("java.lang.StackWalker"); + Method getInstanceMethod = stackWalkerClass.getMethod("getInstance"); + stackWalker = getInstanceMethod.invoke(null); + } catch (Throwable t) { + // ignore + // System.err.println("Unable to load StackWalker, using + // Thread.currentThread().getStackTrace()"); + } + } + + /** + * + * @return the stack trace as a list classname#methodname + */ + static List<String> getStack() { + return Arrays.stream(Thread.currentThread().getStackTrace()) + .map(stackTraceElement -> stackTraceElement.getClassName() + "#" + stackTraceElement.getMethodName()) + .collect(Collectors.toList()); + } +} diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/TestOutputReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/TestOutputReportEntry.java index 3c4c46dea..3e3e03b99 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/TestOutputReportEntry.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/TestOutputReportEntry.java @@ -29,7 +29,11 @@ public final class TestOutputReportEntry implements OutputReportEntry { private final boolean newLine; private final RunMode runMode; private final Long testRunId; - + /** + * The stack trace of the thread that produced the output. + * claasName#method;className#method;... + */ + private String stack; /** * Wraps the output from the running test-case. * @@ -45,6 +49,7 @@ public TestOutputReportEntry(String log, boolean isStdOut, boolean newLine, RunM this.newLine = newLine; this.runMode = runMode; this.testRunId = testRunId; + this.stack = String.join(";", StackTraceProvider.getStack()); } /** @@ -59,11 +64,28 @@ private TestOutputReportEntry(String log, boolean isStdOut, boolean newLine) { } public TestOutputReportEntry(OutputReportEntry reportEntry, RunMode runMode, Long testRunId) { - log = reportEntry.getLog(); - isStdOut = reportEntry.isStdOut(); - newLine = reportEntry.isNewLine(); + this(reportEntry.getLog(), reportEntry.isStdOut(), reportEntry.isNewLine(), runMode, testRunId); + } + + /** + * Constructor used when receiving output from a forked JVM where the stack trace was captured + * on the forked side. + * + * @param log stdout/stderr output + * @param isStdOut true if stdout + * @param newLine true if newline + * @param runMode the run mode + * @param testRunId the test run id + * @param stack the stack trace captured on the forked JVM side + */ + public TestOutputReportEntry( + String log, boolean isStdOut, boolean newLine, RunMode runMode, Long testRunId, String stack) { + this.log = log; + this.isStdOut = isStdOut; + this.newLine = newLine; this.runMode = runMode; this.testRunId = testRunId; + this.stack = stack; } @Override @@ -89,6 +111,11 @@ public Long getTestRunId() { return testRunId; } + @Override + public String getStack() { + return stack; + } + public static OutputReportEntry stdOut(String log) { return new TestOutputReportEntry(log, true, false); } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java index 400f74f6c..5c7a859b2 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/stream/AbstractStreamDecoder.java @@ -24,7 +24,6 @@ import java.io.EOFException; import java.io.File; import java.io.IOException; -import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.ReadableByteChannel; @@ -124,8 +123,8 @@ protected Segment readSegment(@Nonnull Memento memento) throws IOException, Malf int readCount = readByte(memento) & 0xff; read(memento, readCount + DELIMITER_LENGTH); ByteBuffer bb = memento.getByteBuffer(); - Segment segment = new Segment(bb.array(), bb.arrayOffset() + ((Buffer) bb).position(), readCount); - ((Buffer) bb).position(((Buffer) bb).position() + readCount); + Segment segment = new Segment(bb.array(), bb.arrayOffset() + (bb).position(), readCount); + (bb).position((bb).position() + readCount); checkDelimiter(memento); return segment; } @@ -137,8 +136,8 @@ protected Charset readCharset(@Nonnull Memento memento) throws IOException, Malf read(memento, length + DELIMITER_LENGTH); ByteBuffer bb = memento.getByteBuffer(); byte[] array = bb.array(); - int offset = bb.arrayOffset() + ((Buffer) bb).position(); - ((Buffer) bb).position(((Buffer) bb).position() + length); + int offset = bb.arrayOffset() + (bb).position(); + (bb).position((bb).position() + length); boolean isDefaultEncoding = false; if (length == DEFAULT_STREAM_ENCODING_BYTES.length) { isDefaultEncoding = true; @@ -155,16 +154,16 @@ protected Charset readCharset(@Nonnull Memento memento) throws IOException, Malf checkDelimiter(memento); return charset; } catch (IllegalArgumentException e) { - throw new MalformedFrameException(memento.getLine().getPositionByteBuffer(), ((Buffer) bb).position()); + throw new MalformedFrameException(memento.getLine().getPositionByteBuffer(), (bb).position()); } } protected String readString(@Nonnull Memento memento) throws IOException, MalformedFrameException { - ((Buffer) memento.getCharBuffer()).clear(); + (memento.getCharBuffer()).clear(); int readCount = readInt(memento); if (readCount < 0) { throw new MalformedFrameException( - memento.getLine().getPositionByteBuffer(), ((Buffer) memento.getByteBuffer()).position()); + memento.getLine().getPositionByteBuffer(), (memento.getByteBuffer()).position()); } read(memento, readCount + DELIMITER_LENGTH); @@ -230,7 +229,7 @@ protected long readLongPrivate(@Nonnull Memento memento) throws IOException, Mal protected final void checkDelimiter(Memento memento) throws MalformedFrameException { ByteBuffer bb = memento.bb; if ((0xff & bb.get()) != ':') { - throw new MalformedFrameException(memento.getLine().getPositionByteBuffer(), ((Buffer) bb).position()); + throw new MalformedFrameException(memento.getLine().getPositionByteBuffer(), (bb).position()); } } @@ -243,16 +242,14 @@ protected final void checkHeader(Memento memento) throws MalformedFrameException try { byte[] header = getEncodedMagicNumber(); byte[] bbArray = bb.array(); - for (int start = bb.arrayOffset() + ((Buffer) bb).position(), length = header.length; - shift < length; - shift++) { + for (int start = bb.arrayOffset() + (bb).position(), length = header.length; shift < length; shift++) { if (bbArray[shift + start] != header[shift]) { throw new MalformedFrameException( - memento.getLine().getPositionByteBuffer(), ((Buffer) bb).position() + shift); + memento.getLine().getPositionByteBuffer(), (bb).position() + shift); } } } finally { - ((Buffer) bb).position(((Buffer) bb).position() + shift); + (bb).position((bb).position() + shift); } checkDelimiter(memento); @@ -261,7 +258,7 @@ protected final void checkHeader(Memento memento) throws MalformedFrameException protected void checkArguments(Memento memento, int expectedDataElements) throws MalformedFrameException { if (memento.getData().size() != expectedDataElements) { throw new MalformedFrameException( - memento.getLine().getPositionByteBuffer(), ((Buffer) memento.getByteBuffer()).position()); + memento.getLine().getPositionByteBuffer(), (memento.getByteBuffer()).position()); } } @@ -269,7 +266,7 @@ private String readString(@Nonnull final Memento memento, @Nonnegative final int throws IOException, MalformedFrameException { memento.getDecoder().reset(); final CharBuffer output = memento.getCharBuffer(); - ((Buffer) output).clear(); + (output).clear(); final ByteBuffer input = memento.getByteBuffer(); final List<String> strings = new ArrayList<>(); int countDecodedBytes = 0; @@ -293,12 +290,12 @@ private String readString(@Nonnull final Memento memento, @Nonnegative final int countDecodedBytes += readInputBytes; } while (isLastChunk && bytesToDecode > 0 && output.hasRemaining()); - strings.add(((Buffer) output).flip().toString()); - ((Buffer) output).clear(); + strings.add((output).flip().toString()); + (output).clear(); } memento.getDecoder().reset(); - ((Buffer) output).clear(); + (output).clear(); return toString(strings); } @@ -311,16 +308,16 @@ private static int decodeString( boolean endOfInput, @Nonnegative int errorStreamFrom) throws MalformedFrameException { - int limit = ((Buffer) input).limit(); - ((Buffer) input).limit(((Buffer) input).position() + bytesToDecode); + int limit = (input).limit(); + (input).limit((input).position() + bytesToDecode); CoderResult result = decoder.decode(input, output, endOfInput); if (result.isError() || result.isMalformed()) { - throw new MalformedFrameException(errorStreamFrom, ((Buffer) input).position()); + throw new MalformedFrameException(errorStreamFrom, (input).position()); } int decodedBytes = bytesToDecode - input.remaining(); - ((Buffer) input).limit(limit); + (input).limit(limit); return decodedBytes; } @@ -339,8 +336,8 @@ private void printCorruptedStream(Memento memento) { ByteBuffer bb = memento.getByteBuffer(); if (bb.hasRemaining()) { int bytesToWrite = bb.remaining(); - memento.getLine().write(bb, ((Buffer) bb).position(), bytesToWrite); - ((Buffer) bb).position(((Buffer) bb).position() + bytesToWrite); + memento.getLine().write(bb, (bb).position(), bytesToWrite); + (bb).position((bb).position() + bytesToWrite); } } @@ -405,17 +402,16 @@ public boolean equals(Object obj) { protected @Nonnull StreamReadStatus read(@Nonnull Memento memento, int recommendedCount) throws IOException { ByteBuffer buffer = memento.getByteBuffer(); - if (buffer.remaining() >= recommendedCount && ((Buffer) buffer).limit() != 0) { + if (buffer.remaining() >= recommendedCount && (buffer).limit() != 0) { return OVERFLOW; } else { - if (((Buffer) buffer).position() != 0 - && recommendedCount > buffer.capacity() - ((Buffer) buffer).position()) { - ((Buffer) buffer.compact()).flip(); + if ((buffer).position() != 0 && recommendedCount > buffer.capacity() - (buffer).position()) { + (buffer.compact()).flip(); memento.getLine().setPositionByteBuffer(0); } - int mark = ((Buffer) buffer).position(); - ((Buffer) buffer).position(((Buffer) buffer).limit()); - ((Buffer) buffer).limit(min(((Buffer) buffer).position() + recommendedCount, buffer.capacity())); + int mark = (buffer).position(); + (buffer).position((buffer).limit()); + (buffer).limit(min((buffer).position() + recommendedCount, buffer.capacity())); return read(buffer, mark, recommendedCount); } } @@ -425,17 +421,17 @@ private StreamReadStatus read(ByteBuffer buffer, int oldPosition, int recommende boolean isEnd = false; try { while (!isEnd - && ((Buffer) buffer).position() - oldPosition < recommendedCount - && ((Buffer) buffer).position() < ((Buffer) buffer).limit()) { + && (buffer).position() - oldPosition < recommendedCount + && (buffer).position() < (buffer).limit()) { isEnd = channel.read(buffer) == -1; } } finally { - ((Buffer) buffer).limit(((Buffer) buffer).position()); - ((Buffer) buffer).position(oldPosition); + (buffer).limit((buffer).position()); + (buffer).position(oldPosition); int readBytes = buffer.remaining(); boolean readComplete = readBytes >= recommendedCount; if (!isEnd || readComplete) { - debugStream(buffer.array(), buffer.arrayOffset() + ((Buffer) buffer).position(), buffer.remaining()); + debugStream(buffer.array(), buffer.arrayOffset() + (buffer).position(), buffer.remaining()); readStatus = readComplete ? OVERFLOW : UNDERFLOW; } } @@ -463,7 +459,7 @@ public Memento() { .newDecoder() .onMalformedInput(REPLACE) .onUnmappableCharacter(REPLACE); - ((Buffer) bb).limit(0); + (bb).limit(0); } public void reset() { diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java index 13df7fa1a..9dbd35ce8 100644 --- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/spi/EventChannelEncoder.java @@ -165,11 +165,12 @@ public void testOutput(TestOutputReportEntry reportEntry) { ForkedProcessEventType event = stdout ? (newLine ? BOOTERCODE_STDOUT_NEW_LINE : BOOTERCODE_STDOUT) : (newLine ? BOOTERCODE_STDERR_NEW_LINE : BOOTERCODE_STDERR); - setOutErr(event, reportEntry.getRunMode(), reportEntry.getTestRunId(), msg); + setOutErr(event, reportEntry.getRunMode(), reportEntry.getTestRunId(), msg, reportEntry.getStack()); } - private void setOutErr(ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message) { - ByteBuffer result = encodeMessage(eventType, runMode, testRunId, message); + private void setOutErr( + ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message, String stackTrace) { + ByteBuffer result = encodeMessage(eventType, runMode, testRunId, message, stackTrace); write(result, false); } @@ -371,11 +372,13 @@ ByteBuffer encode(ForkedProcessEventType operation, ReportEntry reportEntry, boo return result; } - ByteBuffer encodeMessage(ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message) { + ByteBuffer encodeMessage( + ForkedProcessEventType eventType, RunMode runMode, Long testRunId, String message, String stackCall) { CharsetEncoder encoder = newCharsetEncoder(); - int bufferMaxLength = estimateBufferLength(eventType.getOpcode().length(), runMode, encoder, 0, 1, message); + int bufferMaxLength = + estimateBufferLength(eventType.getOpcode().length(), runMode, encoder, 0, 1, message, stackCall); ByteBuffer result = ByteBuffer.allocate(bufferMaxLength); - encode(encoder, result, eventType, runMode, testRunId, message); + encode(encoder, result, eventType, runMode, testRunId, message, stackCall); return result; } diff --git a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java index af15e68ff..9eafdf83c 100644 --- a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java +++ b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/spi/EventChannelEncoderTest.java @@ -952,21 +952,21 @@ public void testSendOpcode() { Channel channel = new Channel(); new EventChannelEncoder(channel).testOutput(new TestOutputReportEntry(stdOut("msg"), NORMAL_RUN, 1L)); assertThat(toString(channel.src)) - .isEqualTo(":maven-surefire-event:" + (char) 14 + ":std-out-stream:" + (char) 10 + ":normal-run:" + .contains(":maven-surefire-event:" + (char) 14 + ":std-out-stream:" + (char) 10 + ":normal-run:" + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:"); channel = new Channel(); new EventChannelEncoder(channel).testOutput(new TestOutputReportEntry(stdErr(null), NORMAL_RUN, 1L)); assertThat(toString(channel.src)) - .isEqualTo(":maven-surefire-event:" + (char) 14 + ":std-err-stream:" + (char) 10 + ":normal-run:" + .contains(":maven-surefire-event:" + (char) 14 + ":std-err-stream:" + (char) 10 + ":normal-run:" + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0001:\u0000:"); - ByteBuffer result = - new EventChannelEncoder(new Channel()).encodeMessage(BOOTERCODE_TEST_ERROR, NORMAL_RUN, 1L, "msg"); + ByteBuffer result = new EventChannelEncoder(new Channel()) + .encodeMessage(BOOTERCODE_TEST_ERROR, NORMAL_RUN, 1L, "msg", "foo#bar"); assertThat(toString(result)) - .isEqualTo(":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:" + .contains(":maven-surefire-event:" + (char) 10 + ":test-error:" + (char) 10 + ":normal-run:" + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + (char) 5 + ":UTF-8:\u0000\u0000\u0000\u0003:msg:"); } @@ -1133,7 +1133,7 @@ public void testStdOutStream() throws IOException { + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1149,7 +1149,7 @@ public void testStdOutStreamLn() throws IOException { + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1165,7 +1165,7 @@ public void testStdErrStream() throws IOException { + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1181,7 +1181,7 @@ public void testStdErrStreamLn() throws IOException { + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1204,7 +1204,7 @@ public void testStdErrStreamEmptyMessageNullTestId() throws IOException { + (char) 10 + ":normal-run:\u0000:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0000::"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1222,7 +1222,7 @@ public void testStdErrStreamEmptyMessageNullRunMode() throws IOException { + "\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0001:" + "\u0005:UTF-8:\u0000\u0000\u0000\u0000::"; - assertThat(new String(out.toByteArray(), UTF_8)).isEqualTo(expected); + assertThat(new String(out.toByteArray(), UTF_8)).contains(expected); } @Test @@ -1307,7 +1307,7 @@ public void testInterruptHandling() throws IOException { } assertThat(new String(out.toByteArray(), UTF_8)) - .isEqualTo(":maven-surefire-event:\u000e:std-out-stream:" + .contains(":maven-surefire-event:\u000e:std-out-stream:" + (char) 10 + ":normal-run:\u0001\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0002" + ":\u0005:UTF-8:\u0000\u0000\u0000\u0003:msg:"); } diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit47RedirectOutputIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit47RedirectOutputIT.java index e3f4654c6..f8f0e23a7 100644 --- a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit47RedirectOutputIT.java +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit47RedirectOutputIT.java @@ -27,9 +27,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -/** - * - */ public class JUnit47RedirectOutputIT extends SurefireJUnitIntegrationTestCase { @Test public void testPrintSummaryTrueWithRedirect() {
