From 8b7d32d4f872e48aaa6f32db2245debfc016ff95 Mon Sep 17 00:00:00 2001 From: tibordigana Date: Sun, 26 Feb 2023 17:59:29 +0100 Subject: [PATCH] Test Indexes and Reporters --- .../report/DefaultReporterFactory.java | 2 + .../surefire/report/ReportEntryType.java | 20 ++- .../surefire/report/ReportersAggregator.java | 135 ++++++++++++++++++ .../surefire/report/StatelessXmlReporter.java | 61 ++++---- .../surefire/report/TestMethodCalls.java | 40 ++++++ .../surefire/report/TestSetRunListener.java | 70 +++++---- .../surefire/report/TestStatsProcessor.java | 5 + .../surefire/report/WrappedReportEntry.java | 6 + .../surefire/api/report/ReportEntry.java | 21 +++ .../api/report/TestOutputReportEntry.java | 13 ++ .../maven/surefire/api/report/UniqueID.java | 70 +++++++++ .../api/util/internal/ReportEntryUtils.java | 79 ++++++++++ .../maven/surefire/extensions/ReportData.java | 96 +++++++++++++ .../StatelessReportEventListener.java | 12 +- .../StatelessTestSetSummaryListener.java | 6 + .../TestAssumptionFailureOperation.java | 22 +++ .../testoperations/TestErrorOperation.java | 22 +++ .../TestExecutionSkippedByUserOperation.java | 22 +++ .../testoperations/TestFailedOperation.java | 22 +++ .../testoperations/TestOperation.java | 15 ++ .../TestSetCompletedOperation.java | 22 +++ .../TestSetStartingOperation.java | 22 +++ .../testoperations/TestSkippedOperation.java | 22 +++ .../testoperations/TestStartingOperation.java | 22 +++ .../TestSucceededOperation.java | 22 +++ .../surefire/report/ClassMethodIndexer.java | 11 +- .../junitplatform/JUnitPlatformProvider.java | 9 +- .../junitplatform/RunListenerAdapter.java | 8 +- 28 files changed, 804 insertions(+), 73 deletions(-) create mode 100644 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportersAggregator.java create mode 100644 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestMethodCalls.java create mode 100644 maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestStatsProcessor.java create mode 100644 surefire-api/src/main/java/org/apache/maven/surefire/api/report/UniqueID.java create mode 100644 surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/ReportEntryUtils.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ReportData.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessTestSetSummaryListener.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestAssumptionFailureOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestErrorOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestExecutionSkippedByUserOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestFailedOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetCompletedOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetStartingOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSkippedOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestStartingOperation.java create mode 100644 surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSucceededOperation.java diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java index d45ae83cf3..7a8a475fbd 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DefaultReporterFactory.java @@ -291,6 +291,8 @@ private void mergeTestHistoryResult() // Merge all the stats for tests from listeners for ( TestSetRunListener listener : listeners ) { + // this method should not be here + // it should be centralized in one place in the state machine - processor for ( TestMethodStats methodStats : listener.getTestMethodStats() ) { List currentMethodStats = diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportEntryType.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportEntryType.java index ffdb706532..b785523efc 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportEntryType.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportEntryType.java @@ -19,13 +19,18 @@ * under the License. */ +import static java.util.Objects.requireNonNull; + /** - * Type of an entry in the report + * Type of entry in the report. * */ public enum ReportEntryType { - + TEST_SET_STARTING(), + TEST_SET_COMPLETED(), + TEST_STARTING(), + TEST_ASSUMPTION_FAILURE(), ERROR( "error", "flakyError", "rerunError" ), FAILURE( "failure", "flakyFailure", "rerunFailure" ), SKIPPED( "skipped", "", "" ), @@ -37,6 +42,11 @@ public enum ReportEntryType private final String rerunXmlTag; + ReportEntryType() + { + this( null, null, null ); + } + ReportEntryType( String xmlTag, String flakyXmlTag, String rerunXmlTag ) { this.xmlTag = xmlTag; @@ -46,16 +56,16 @@ public enum ReportEntryType public String getXmlTag() { - return xmlTag; + return requireNonNull( xmlTag ); } public String getFlakyXmlTag() { - return flakyXmlTag; + return requireNonNull( flakyXmlTag ); } public String getRerunXmlTag() { - return rerunXmlTag; + return requireNonNull( rerunXmlTag ); } } diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportersAggregator.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportersAggregator.java new file mode 100644 index 0000000000..90eabe8582 --- /dev/null +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/ReportersAggregator.java @@ -0,0 +1,135 @@ +package org.apache.maven.plugin.surefire.report; + +/* + * 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.plugin.surefire.runorder.StatisticsReporter; +import org.apache.maven.surefire.extensions.ConsoleOutputReportEventListener; +import org.apache.maven.surefire.extensions.StatelessReportEventListener; +import org.apache.maven.surefire.extensions.StatelessTestSetSummaryListener; +import org.apache.maven.surefire.extensions.StatelessTestsetInfoConsoleReportEventListener; +import org.apache.maven.surefire.extensions.StatelessTestsetInfoFileReportEventListener; + +/** + * + */ +public final class ReportersAggregator +{ + private StatelessTestsetInfoConsoleReportEventListener consoleReporter; + private StatelessTestsetInfoFileReportEventListener fileReporter; + private StatelessReportEventListener simpleXMLReporter; + private ConsoleOutputReportEventListener testOutputReceiver; + private StatisticsReporter statisticsReporter; + private StatelessTestSetSummaryListener testSetSummaryReporter; + private boolean trimStackTrace; + private boolean isPlainFormat; + private boolean briefOrPlainFormat; + + public StatelessTestsetInfoConsoleReportEventListener getConsoleReporter() + { + return consoleReporter; + } + + public void setConsoleReporter( + StatelessTestsetInfoConsoleReportEventListener consoleReporter ) + { + this.consoleReporter = consoleReporter; + } + + public StatelessTestsetInfoFileReportEventListener getFileReporter() + { + return fileReporter; + } + + public void setFileReporter( + StatelessTestsetInfoFileReportEventListener fileReporter ) + { + this.fileReporter = fileReporter; + } + + public StatelessReportEventListener getSimpleXMLReporter() + { + return simpleXMLReporter; + } + + public void setSimpleXMLReporter( StatelessReportEventListener simpleXMLReporter ) + { + this.simpleXMLReporter = simpleXMLReporter; + } + + public ConsoleOutputReportEventListener getTestOutputReceiver() + { + return testOutputReceiver; + } + + public void setTestOutputReceiver( ConsoleOutputReportEventListener testOutputReceiver ) + { + this.testOutputReceiver = testOutputReceiver; + } + + public StatisticsReporter getStatisticsReporter() + { + return statisticsReporter; + } + + public void setStatisticsReporter( StatisticsReporter statisticsReporter ) + { + this.statisticsReporter = statisticsReporter; + } + + public StatelessTestSetSummaryListener getTestSetSummaryReporter() + { + return testSetSummaryReporter; + } + + public void setTestSetSummaryReporter( StatelessTestSetSummaryListener testSetSummaryReporter ) + { + this.testSetSummaryReporter = testSetSummaryReporter; + } + + public boolean isTrimStackTrace() + { + return trimStackTrace; + } + + public void setTrimStackTrace( boolean trimStackTrace ) + { + this.trimStackTrace = trimStackTrace; + } + + public boolean isPlainFormat() + { + return isPlainFormat; + } + + public void setPlainFormat( boolean plainFormat ) + { + isPlainFormat = plainFormat; + } + + public boolean isBriefOrPlainFormat() + { + return briefOrPlainFormat; + } + + public void setBriefOrPlainFormat( boolean briefOrPlainFormat ) + { + this.briefOrPlainFormat = briefOrPlainFormat; + } +} diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java index 45f1c5003c..007a43be59 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporter.java @@ -20,6 +20,8 @@ */ import org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton; +import org.apache.maven.surefire.extensions.ReportData; +import org.apache.maven.surefire.api.report.UniqueID; import org.apache.maven.surefire.shared.utils.xml.PrettyPrintXMLWriter; import org.apache.maven.surefire.shared.utils.xml.XMLWriter; import org.apache.maven.surefire.extensions.StatelessReportEventListener; @@ -27,7 +29,6 @@ import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -43,6 +44,7 @@ import java.util.concurrent.ConcurrentLinkedDeque; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.Files.newOutputStream; import static org.apache.maven.plugin.surefire.report.DefaultReporterFactory.TestResultType; import static org.apache.maven.plugin.surefire.report.FileReporterUtils.stripIllegalFilenameChars; import static org.apache.maven.plugin.surefire.report.ReportEntryType.SKIPPED; @@ -134,10 +136,22 @@ public StatelessXmlReporter( File reportsDirectory, String reportNameSuffix, boo this.phrasedMethodName = phrasedMethodName; } + @Override + public void testSetCompleted( UniqueID sourceId, ReportData testSetStats ) + { + TestMethodCalls methodCalls = new TestMethodCalls(); + + testSetStats.filterOperations( sourceId ) + .forEach( methodCalls::addOperation ); + + testSetStats.filterRerunOperations( sourceId ) + .forEach( methodCalls::addRerunOperation ); + } + @Override public void testSetCompleted( WrappedReportEntry testSetReportEntry, TestSetStats testSetStats ) { - Map>> classMethodStatistics = + Map>> classMethodStatistics = arrangeMethodStatistics( testSetReportEntry, testSetStats ); // The Java Language Spec: @@ -151,9 +165,9 @@ public void testSetCompleted( WrappedReportEntry testSetReportEntry, TestSetStat showProperties( ppw, testSetReportEntry.getSystemProperties() ); - for ( Entry>> statistics : classMethodStatistics.entrySet() ) + for ( Entry>> statistics : classMethodStatistics.entrySet() ) { - for ( Entry> thisMethodRuns : statistics.getValue().entrySet() ) + for ( Entry> thisMethodRuns : statistics.getValue().entrySet() ) { serializeTestClass( outputStream, fw, ppw, thisMethodRuns.getValue() ); } @@ -171,38 +185,33 @@ public void testSetCompleted( WrappedReportEntry testSetReportEntry, TestSetStat } } - private Map>> arrangeMethodStatistics( - WrappedReportEntry testSetReportEntry, TestSetStats testSetStats ) + private Map>> arrangeMethodStatistics( + UniqueID sourceId, TestMethodCalls methodCalls ) { - Map>> classMethodStatistics = new LinkedHashMap<>(); - for ( WrappedReportEntry methodEntry : aggregateCacheFromMultipleReruns( testSetReportEntry, testSetStats ) ) + Map methodStatistics = new LinkedHashMap<>(); + + for ( WrappedReportEntry methodEntry : methodCalls ) { - String testClassName = methodEntry.getSourceName(); - Map> stats = classMethodStatistics.get( testClassName ); - if ( stats == null ) - { - stats = new LinkedHashMap<>(); - classMethodStatistics.put( testClassName, stats ); - } - String methodName = methodEntry.getName(); - List methodRuns = stats.get( methodName ); - if ( methodRuns == null ) - { - methodRuns = new ArrayList<>(); - stats.put( methodName, methodRuns ); - } + UniqueID methodId = methodEntry.getTestRunUniqueId(); + + Map> stats = + classMethodStatistics.computeIfAbsent( methodId.toSourceUniqueId(), k -> new LinkedHashMap<>() ); + + List methodRuns = + stats.computeIfAbsent( methodId, k -> new ArrayList<>() ); + methodRuns.add( methodEntry ); } return classMethodStatistics; } private Deque aggregateCacheFromMultipleReruns( WrappedReportEntry testSetReportEntry, - TestSetStats testSetStats ) + TestSetStats testSetStats ) { - String suiteClassName = testSetReportEntry.getSourceName(); + /*String suiteClassName = testSetReportEntry.getSourceName(); Deque methodRunHistory = getAddMethodRunHistoryMap( suiteClassName ); methodRunHistory.addAll( testSetStats.getReportEntries() ); - return methodRunHistory; + return methodRunHistory;*/ } private void serializeTestClass( OutputStream outputStream, OutputStreamWriter fw, XMLWriter ppw, @@ -364,7 +373,7 @@ private OutputStream getOutputStream( WrappedReportEntry testSetReportEntry ) reportFile.delete(); //noinspection ResultOfMethodCallIgnored reportDir.mkdirs(); - return new BufferedOutputStream( new FileOutputStream( reportFile ), 64 * 1024 ); + return new BufferedOutputStream( newOutputStream( reportFile.toPath() ), 64 * 1024 ); } private static OutputStreamWriter getWriter( OutputStream fos ) diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestMethodCalls.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestMethodCalls.java new file mode 100644 index 0000000000..4a1c5dcc50 --- /dev/null +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestMethodCalls.java @@ -0,0 +1,40 @@ +package org.apache.maven.plugin.surefire.report; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.maven.surefire.api.report.UniqueID; +import org.apache.maven.surefire.extensions.ReportData; +import org.apache.maven.surefire.extensions.testoperations.TestOperation; + +import static java.util.stream.Collectors.toMap; + +final class TestMethodCalls +{ + private final ReportData reportData = new ReportData(); + + void addOperation( TestOperation op ) + { + reportData.addOperation( op ); + } + + void addRerunOperation( TestOperation op ) + { + reportData.addRetryOperation( op ); + } + + Map mapTestStats() + { + return reportData.getIds() + .stream() + .collect( toMap( + id -> id, + id -> + { + ReportData rep = new ReportData(); + reportData.filterOperations( id ).forEach( rep::addOperation ); + reportData.filterRerunOperations( id ).forEach( rep::addRetryOperation ); + return rep; + }, (u, v) -> { throw new IllegalStateException(); }, LinkedHashMap::new ) ); + } +} diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java index 2884f68a55..8463d85333 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestSetRunListener.java @@ -20,25 +20,36 @@ */ import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.maven.plugin.surefire.runorder.StatisticsReporter; import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.RunMode; import org.apache.maven.surefire.api.report.TestOutputReportEntry; import org.apache.maven.surefire.api.report.TestReportListener; import org.apache.maven.surefire.api.report.TestSetReportEntry; +import org.apache.maven.surefire.extensions.StatelessTestSetSummaryListener; +import org.apache.maven.surefire.extensions.TestOutputReportOperation; +import org.apache.maven.surefire.extensions.TestSetReportOperation; import org.apache.maven.surefire.extensions.ConsoleOutputReportEventListener; +import org.apache.maven.surefire.extensions.TestReportOperation; import org.apache.maven.surefire.extensions.StatelessReportEventListener; import org.apache.maven.surefire.extensions.StatelessTestsetInfoConsoleReportEventListener; import org.apache.maven.surefire.extensions.StatelessTestsetInfoFileReportEventListener; +import org.apache.maven.surefire.extensions.testoperations.TestOperation; import static org.apache.maven.plugin.surefire.report.ReportEntryType.ERROR; import static org.apache.maven.plugin.surefire.report.ReportEntryType.FAILURE; import static org.apache.maven.plugin.surefire.report.ReportEntryType.SKIPPED; import static org.apache.maven.plugin.surefire.report.ReportEntryType.SUCCESS; +import static org.apache.maven.surefire.api.report.RunMode.RERUN_TEST_AFTER_FAILURE; /** * Reports data for a single test set. @@ -49,9 +60,8 @@ public class TestSetRunListener implements TestReportListener { - private final Queue testMethodStats = new ConcurrentLinkedQueue<>(); - - private final TestSetStats detailsForThis; + private final Map>> operationsPerSource = new HashMap<>(); + private final Map>> rerunOperationsPerSource = new HashMap<>(); private final ConsoleOutputReportEventListener testOutputReceiver; @@ -65,29 +75,20 @@ public class TestSetRunListener private final StatisticsReporter statisticsReporter; - private final Object lock; - - private Utf8RecodingDeferredFileOutputStream testStdOut = initDeferred( "stdout" ); + private final StatelessTestSetSummaryListener testSetSummaryReport; - private Utf8RecodingDeferredFileOutputStream testStdErr = initDeferred( "stderr" ); + private final Object lock; - @SuppressWarnings( "checkstyle:parameternumber" ) - public TestSetRunListener( StatelessTestsetInfoConsoleReportEventListener - consoleReporter, - StatelessTestsetInfoFileReportEventListener - fileReporter, - StatelessReportEventListener simpleXMLReporter, - ConsoleOutputReportEventListener testOutputReceiver, - StatisticsReporter statisticsReporter, boolean trimStackTrace, - boolean isPlainFormat, boolean briefOrPlainFormat, Object lock ) + public TestSetRunListener( ReportersAggregator reporters, Object lock ) { - this.consoleReporter = consoleReporter; - this.fileReporter = fileReporter; - this.statisticsReporter = statisticsReporter; - this.simpleXMLReporter = simpleXMLReporter; - this.testOutputReceiver = testOutputReceiver; - this.briefOrPlainFormat = briefOrPlainFormat; - detailsForThis = new TestSetStats( trimStackTrace, isPlainFormat ); + consoleReporter = reporters.getConsoleReporter(); + fileReporter = reporters.getFileReporter(); + statisticsReporter = reporters.getStatisticsReporter(); + simpleXMLReporter = reporters.getSimpleXMLReporter(); + testOutputReceiver = reporters.getTestOutputReceiver(); + briefOrPlainFormat = reporters.isBriefOrPlainFormat(); + testSetSummaryReport = reporters.getTestSetSummaryReporter(); + detailsForThis = new TestSetStats( reporters.isTrimStackTrace(), reporters.isPlainFormat() ); this.lock = lock; } @@ -176,6 +177,7 @@ public void writeTestOutput( TestOutputReportEntry reportEntry ) { synchronized ( lock ) { + addEntry( reportEntry.getSourceId(), reportEntry.getRunMode(), new TestOutputReportOperation( reportEntry ) ); Utf8RecodingDeferredFileOutputStream stream = reportEntry.isStdOut() ? testStdOut : testStdErr; stream.write( reportEntry.getLog(), reportEntry.isNewLine() ); testOutputReceiver.writeTestOutput( reportEntry ); @@ -183,13 +185,14 @@ public void writeTestOutput( TestOutputReportEntry reportEntry ) } catch ( IOException e ) { - throw new RuntimeException( e ); + throw new UncheckedIOException( e ); } } @Override public void testSetStarting( TestSetReportEntry report ) { + addEntry( report.getSourceId(), report.getRunMode(), new TestSetReportOperation( report ) ); detailsForThis.testSetStart(); consoleReporter.testSetStarting( report ); testOutputReceiver.testSetStarting( report ); @@ -204,6 +207,7 @@ private void clearCapture() @Override public void testSetCompleted( TestSetReportEntry report ) { + addEntry( report.getSourceId(), report.getRunMode(), new TestSetReportOperation( report ) ); final WrappedReportEntry wrap = wrapTestSet( report ); final List testResults = briefOrPlainFormat ? detailsForThis.getTestResults() : Collections.emptyList(); @@ -229,12 +233,14 @@ public void testSetCompleted( TestSetReportEntry report ) @Override public void testStarting( ReportEntry report ) { + addEntry( report.getSourceId(), report.getRunMode(), new TestReportOperation( report ) ); detailsForThis.testStart(); } @Override public void testSucceeded( ReportEntry reportEntry ) { + addEntry( reportEntry.getSourceId(), reportEntry.getRunMode(), new TestReportOperation( reportEntry ) ); WrappedReportEntry wrapped = wrap( reportEntry, SUCCESS ); detailsForThis.testSucceeded( wrapped ); statisticsReporter.testSucceeded( reportEntry ); @@ -244,6 +250,7 @@ public void testSucceeded( ReportEntry reportEntry ) @Override public void testError( ReportEntry reportEntry ) { + addEntry( reportEntry.getSourceId(), reportEntry.getRunMode(), new TestReportOperation( reportEntry ) ); WrappedReportEntry wrapped = wrap( reportEntry, ERROR ); detailsForThis.testError( wrapped ); statisticsReporter.testError( reportEntry ); @@ -253,6 +260,7 @@ public void testError( ReportEntry reportEntry ) @Override public void testFailed( ReportEntry reportEntry ) { + addEntry( reportEntry.getSourceId(), reportEntry.getRunMode(), new TestReportOperation( reportEntry ) ); WrappedReportEntry wrapped = wrap( reportEntry, FAILURE ); detailsForThis.testFailure( wrapped ); statisticsReporter.testFailed( reportEntry ); @@ -266,6 +274,7 @@ public void testFailed( ReportEntry reportEntry ) @Override public void testSkipped( ReportEntry reportEntry ) { + addEntry( reportEntry.getSourceId(), reportEntry.getRunMode(), new TestReportOperation( reportEntry ) ); WrappedReportEntry wrapped = wrap( reportEntry, SKIPPED ); detailsForThis.testSkipped( wrapped ); statisticsReporter.testSkipped( reportEntry ); @@ -280,6 +289,7 @@ public void testExecutionSkippedByUser() @Override public void testAssumptionFailure( ReportEntry report ) { + addEntry( report.getSourceId(), report.getRunMode(), new TestReportOperation( report ) ); testSkipped( report ); } @@ -323,6 +333,18 @@ public Queue getTestMethodStats() return testMethodStats; } + private void addEntry( Integer source, RunMode runMode, TestOperation operation ) + { + Map>> sourceOperations = + runMode == RERUN_TEST_AFTER_FAILURE ? rerunOperationsPerSource : operationsPerSource; + sourceOperations.compute( source, ( k, v ) -> + { + List> operations = v == null ? new ArrayList<>() : v; + operations.add( operation ); + return operations; + } ); + } + private static String trimTrailingNewLine( final String message ) { final int e = message == null ? 0 : lineBoundSymbolWidth( message ); diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestStatsProcessor.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestStatsProcessor.java new file mode 100644 index 0000000000..1c7ec99dac --- /dev/null +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/TestStatsProcessor.java @@ -0,0 +1,5 @@ +package org.apache.maven.plugin.surefire.report; + +public class TestStatsProcessor +{ +} diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java index bc2fca0c50..5e360b8eb5 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/WrappedReportEntry.java @@ -23,6 +23,7 @@ import org.apache.maven.surefire.api.report.RunMode; import org.apache.maven.surefire.api.report.StackTraceWriter; import org.apache.maven.surefire.api.report.TestSetReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; import javax.annotation.Nonnull; import java.util.Collections; @@ -239,6 +240,11 @@ public Long getTestRunId() return original.getTestRunId(); } + public UniqueID getTestRunUniqueId() + { + return getTestRunId() == null ? null : new UniqueID( getTestRunId() ); + } + @Override public Map getSystemProperties() { diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java index ed3fdc5a19..3c2a9b9836 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/ReportEntry.java @@ -21,6 +21,9 @@ import javax.annotation.Nonnull; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toNameId; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toSourceId; + /** * Describes a single entry for a test report * @@ -41,6 +44,12 @@ public interface ReportEntry */ String getSourceText(); + default Integer getSourceId() + { + Long id = getTestRunId(); + return id == null ? null : toSourceId( id ); + } + /** * The name of the test case * @@ -55,6 +64,12 @@ public interface ReportEntry */ String getNameText(); + default Integer getNameId() + { + Long id = getTestRunId(); + return id == null ? null : toNameId( id ); + } + /** * The group/category of the testcase * @@ -123,4 +138,10 @@ public interface ReportEntry * @return id */ Long getTestRunId(); + + default UniqueID getUniqueId() + { + Long id = getTestRunId(); + return id == null ? null : new UniqueID( id ); + } } 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 3610f85c21..411956f6b7 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 @@ -19,6 +19,9 @@ * under the License. */ +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toNameId; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toSourceId; + /** * This report entry should be used in {@link TestOutputReceiver#writeTestOutput(OutputReportEntry)}. * @@ -118,4 +121,14 @@ public static TestOutputReportEntry stdErrln( String log ) { return new TestOutputReportEntry( log, false, true ); } + + public Integer getSourceId() + { + return toSourceId( getTestRunId() ); + } + + public Integer getNameId() + { + return toNameId( getTestRunId() ); + } } diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/report/UniqueID.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/UniqueID.java new file mode 100644 index 0000000000..d9d58e1b6b --- /dev/null +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/report/UniqueID.java @@ -0,0 +1,70 @@ +package org.apache.maven.surefire.api.report; + +/* + * 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 java.util.Objects; + +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toSourceId; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toTestRunId; + +/** + * + */ +public final class UniqueID +{ + private final Long id; + + public UniqueID( int sourceId, Integer testId ) + { + this( testId == null ? toTestRunId( sourceId ) : toTestRunId( sourceId, testId ) ); + } + + public UniqueID( Long id ) + { + this.id = id; + + } + + public UniqueID toSourceUniqueId() + { + return new UniqueID( id == null ? null : toTestRunId( toSourceId( id ) ) ); + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + UniqueID uniqueID = (UniqueID) o; + return Objects.equals( id, uniqueID.id ); + } + + @Override + public int hashCode() + { + return Objects.hash( id ); + } +} diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/ReportEntryUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/ReportEntryUtils.java new file mode 100644 index 0000000000..423c4af38f --- /dev/null +++ b/surefire-api/src/main/java/org/apache/maven/surefire/api/util/internal/ReportEntryUtils.java @@ -0,0 +1,79 @@ +package org.apache.maven.surefire.api.util.internal; + +/* + * 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. + */ + +/** + * Utility class for {@link org.apache.maven.surefire.api.report.ReportEntry}. + */ +public final class ReportEntryUtils +{ + private ReportEntryUtils() + { + throw new IllegalStateException( "no instantiable constructor" ); + } + + /** + * @param sourceId class id or source id (parent) + * @param testId test child + * @return shifts {@code sourceId} to 32-bit MSB of long and encodes {@code testId} to LSB + */ + public static long toTestRunId( int sourceId, int testId ) + { + return toTestRunId( sourceId ) | testId; + } + + /** + * @param sourceId class id or source id (parent) + * @return shifts in 32 bits + */ + public static long toTestRunId( int sourceId ) + { + return ( (long) sourceId ) << 32; + } + + /** + * @param testRunId encoded 32-bit MSB source and 32-bit LSB name in 64-bit value + * @return shifts {@code testRunId} in 32 bits right + */ + public static int toSourceId( long testRunId ) + { + return (int) ( 0x00000000ffffffffL & ( testRunId >>> 32 ) ); + } + + public static boolean existsSourceId( Long testRunId ) + { + return testRunId != null && toSourceId( testRunId ) != 0; + } + + /** + * + * @param testRunId encoded 32-bit MSB source and 32-bit LSB name in 64-bit value + * @return 32-bit LSB of {@code testRunId} + */ + public static int toNameId( long testRunId ) + { + return (int) ( 0x00000000ffffffffL & testRunId ); + } + + public static boolean existsNameId( Long testRunId ) + { + return testRunId != null && toNameId( testRunId ) != 0; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ReportData.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ReportData.java new file mode 100644 index 0000000000..52f38edc3a --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/ReportData.java @@ -0,0 +1,96 @@ +package org.apache.maven.surefire.extensions; + +/* + * 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 java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.surefire.api.report.UniqueID; +import org.apache.maven.surefire.extensions.testoperations.TestOperation; + +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toCollection; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; + +/** + * + */ +public final class ReportData +{ + private final List> operations = new ArrayList<>(); + private final List> rerunOperations = new ArrayList<>(); + + public void addOperation( TestOperation op ) + { + operations.add( requireNonNull( op ) ); + } + + public void addRetryOperation( TestOperation op ) + { + rerunOperations.add( requireNonNull( op ) ); + } + + public Set getIds() + { + return operations.stream() + .map( TestOperation::getSourceId ) + .collect( toCollection( LinkedHashSet::new ) ); + } + + public List> filterOperations( UniqueID sourceId ) + { + return filterBySourceId( sourceId, operations ); + } + + public List> filterRerunOperations( UniqueID sourceId ) + { + return filterBySourceId( sourceId, rerunOperations ); + } + + public void removeSourceId( UniqueID sourceId ) + { + removeBySourceId( sourceId, operations.iterator() ); + removeBySourceId( sourceId, rerunOperations.iterator() ); + } + + private List> filterBySourceId( UniqueID sourceId, List> sources ) + { + return sources.stream() + .filter( op -> op.getSourceId().equals( sourceId ) ) + .collect( toList() ); + } + + private void removeBySourceId( UniqueID sourceId, Iterator> it ) + { + for ( TestOperation op; it.hasNext(); ) + { + op = it.next(); + if ( op.getSourceId().equals( sourceId ) ) + { + it.remove(); + } + } + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessReportEventListener.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessReportEventListener.java index 20eda3bdb8..4eadc8c715 100644 --- a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessReportEventListener.java +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessReportEventListener.java @@ -19,7 +19,7 @@ * under the License. */ -import org.apache.maven.surefire.api.report.TestSetReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; /** * Creates a report upon handled event "testSetCompleted". @@ -28,16 +28,12 @@ * * author Tibor Digana (tibor17) * @since 3.0.0-M4 - * @param report entry type, see WrappedReportEntry from module the maven-surefire-common - * @param test-set statistics, see TestSetStats from module the maven-surefire-common */ -public interface StatelessReportEventListener +public interface StatelessReportEventListener { /** * The callback is called after the test class has been completed and the state of report is final. - * - * @param report WrappedReportEntry - * @param testSetStats TestSetStats + * @param testSetStats StatelessReportData */ - void testSetCompleted( R report, S testSetStats ); + void testSetCompleted( UniqueID sourceId, ReportData testSetStats ); } diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessTestSetSummaryListener.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessTestSetSummaryListener.java new file mode 100644 index 0000000000..9608440c71 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/StatelessTestSetSummaryListener.java @@ -0,0 +1,6 @@ +package org.apache.maven.surefire.extensions; + +public interface StatelessTestSetSummaryListener +{ + void testSetCompleted( ); +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestAssumptionFailureOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestAssumptionFailureOperation.java new file mode 100644 index 0000000000..61f9a5f916 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestAssumptionFailureOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestAssumptionFailureOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestAssumptionFailureOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestErrorOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestErrorOperation.java new file mode 100644 index 0000000000..b54e5c741a --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestErrorOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestErrorOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestErrorOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestExecutionSkippedByUserOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestExecutionSkippedByUserOperation.java new file mode 100644 index 0000000000..9b51178d7a --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestExecutionSkippedByUserOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestExecutionSkippedByUserOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestExecutionSkippedByUserOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestFailedOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestFailedOperation.java new file mode 100644 index 0000000000..971522a349 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestFailedOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestFailedOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestFailedOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestOperation.java new file mode 100644 index 0000000000..d6e43c7d4a --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestOperation.java @@ -0,0 +1,15 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public abstract class TestOperation +{ + private final long createdAt = System.currentTimeMillis(); + public abstract UniqueID getSourceId(); + + public final long createdAt() + { + return createdAt; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetCompletedOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetCompletedOperation.java new file mode 100644 index 0000000000..333bf21c69 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetCompletedOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.TestSetReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestSetCompletedOperation extends TestOperation +{ + private final TestSetReportEntry event; + private final UniqueID sourceId; + + public TestSetCompletedOperation( TestSetReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetStartingOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetStartingOperation.java new file mode 100644 index 0000000000..00fa1b5d92 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSetStartingOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.TestSetReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestSetStartingOperation extends TestOperation +{ + private final TestSetReportEntry event; + private final UniqueID sourceId; + + public TestSetStartingOperation( TestSetReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSkippedOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSkippedOperation.java new file mode 100644 index 0000000000..36c3d70dbf --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSkippedOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestSkippedOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestSkippedOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestStartingOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestStartingOperation.java new file mode 100644 index 0000000000..a3250a254a --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestStartingOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestStartingOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestStartingOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSucceededOperation.java b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSucceededOperation.java new file mode 100644 index 0000000000..65f28bc756 --- /dev/null +++ b/surefire-extensions-api/src/main/java/org/apache/maven/surefire/extensions/testoperations/TestSucceededOperation.java @@ -0,0 +1,22 @@ +package org.apache.maven.surefire.extensions.testoperations; + +import org.apache.maven.surefire.api.report.ReportEntry; +import org.apache.maven.surefire.api.report.UniqueID; + +public final class TestSucceededOperation extends TestOperation +{ + private final ReportEntry event; + private final UniqueID sourceId; + + public TestSucceededOperation( ReportEntry event ) + { + this.event = event; + sourceId = event.getUniqueId(); + } + + @Override + public UniqueID getSourceId() + { + return sourceId; + } +} diff --git a/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/ClassMethodIndexer.java b/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/ClassMethodIndexer.java index 8e58d7a4c8..d9818e4607 100644 --- a/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/ClassMethodIndexer.java +++ b/surefire-providers/common-java5/src/main/java/org/apache/maven/surefire/report/ClassMethodIndexer.java @@ -26,6 +26,8 @@ import java.util.concurrent.atomic.AtomicInteger; import static java.util.Objects.requireNonNull; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toSourceId; +import static org.apache.maven.surefire.api.util.internal.ReportEntryUtils.toTestRunId; /** * Creates an index for class/method. @@ -44,10 +46,10 @@ public long indexClassMethod( String clazz, String method ) return testIdMapping.computeIfAbsent( key, cm -> { Long classId = testIdMapping.get( new ClassMethod( requireNonNull( clazz ), null ) ); - long c = classId == null ? ( ( (long) classIndex.getAndIncrement() ) << 32 ) : classId; + int c = classId == null ? classIndex.getAndIncrement() : toSourceId( classId ); int m = method == null ? 0 : methodIndex.getAndIncrement(); long id = c | m; - testLocalMapping.set( id ); + testLocalMapping.set( toTestRunId( c, m ) ); return id; } ); } @@ -61,4 +63,9 @@ public Long getLocalIndex() { return testLocalMapping.get(); } + + public void removeLocalIndex() + { + testLocalMapping.remove(); + } } diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java index ad2ec944d2..23ddb83ce5 100644 --- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java @@ -180,10 +180,10 @@ private void invokeAllTests( TestsToRun testsToRun, RunListenerAdapter adapter ) } // Rerun failing tests if requested int count = parameters.getTestRequest().getRerunFailingTestsCount(); - if ( count > 0 && adapter.hasFailingTests() ) + if ( count > 0 ) { adapter.setRunMode( RERUN_TEST_AFTER_FAILURE ); - for ( int i = 0; i < count; i++ ) + for ( int i = 0; i < count && adapter.hasFailingTests(); i++ ) { try { @@ -193,11 +193,6 @@ private void invokeAllTests( TestsToRun testsToRun, RunListenerAdapter adapter ) // Reset adapter's recorded failures and invoke the failed tests again adapter.reset(); launcher.execute( discoveryRequest, adapter ); - // If no tests fail in the rerun, we're done - if ( !adapter.hasFailingTests() ) - { - break; - } } finally { diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java index aeb24576e0..14cf13bb7a 100644 --- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java @@ -172,6 +172,7 @@ public void executionFinished( TestIdentifier testIdentifier, TestExecutionResul createReportEntry( testIdentifier, null, systemProps(), null, elapsed ) ); } } + classMethodIndexer.removeLocalIndex(); } runningTestIdentifiersByUniqueId.remove( testIdentifier.getUniqueId() ); @@ -234,9 +235,14 @@ private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier, { methodText = null; } + StackTraceWriter stw = testExecutionResult == null ? null : toStackTraceWriter( className, methodName, testExecutionResult ); - return new SimpleReportEntry( runMode, classMethodIndexer.indexClassMethod( className, methodName ), className, + + long uniqueId = classMethodIndexer.indexClassMethod( + testIdentifier.getParentId().orElse( className ), testIdentifier.getUniqueId() ); + + return new SimpleReportEntry( runMode, uniqueId, className, classText, methodName, methodText, stw, elapsedTime, reason, systemProperties ); }