You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2022/02/02 23:46:00 UTC

[maven-surefire] branch release/2.22.3 updated: [SUREFIRE-1556] Test XML file is not valid when rerun "fails" with an assumption

This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch release/2.22.3
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git


The following commit(s) were added to refs/heads/release/2.22.3 by this push:
     new d24ac6d  [SUREFIRE-1556] Test XML file is not valid when rerun "fails" with an assumption
d24ac6d is described below

commit d24ac6d1ab5a2584a6d8cacf35eea693b68fc8f4
Author: Tibor Digaňa <ti...@apache.org>
AuthorDate: Fri Jan 28 01:04:12 2022 +0100

    [SUREFIRE-1556] Test XML file is not valid when rerun "fails" with an assumption
    
    (cherry picked from commit 47aebbb6d7faad3db837fe5fe93d8ffb11bf37c8)
---
 .../surefire/report/StatelessXmlReporter.java      |  58 ++++++++---
 .../surefire/report/StatelessXmlReporterTest.java  | 109 ++++++++++++++++++---
 2 files changed, 137 insertions(+), 30 deletions(-)

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 0773788..cd2a7ed 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
@@ -24,7 +24,6 @@ import org.apache.maven.shared.utils.xml.XMLWriter;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.ReporterException;
 import org.apache.maven.surefire.report.SafeThrowable;
-import org.apache.maven.surefire.util.internal.StringUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -33,6 +32,7 @@ import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -44,9 +44,10 @@ import java.util.StringTokenizer;
 import static org.apache.commons.io.IOUtils.closeQuietly;
 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;
 import static org.apache.maven.plugin.surefire.report.ReportEntryType.SUCCESS;
-import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
+import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 
 @SuppressWarnings( { "javadoc", "checkstyle:javadoctype" } )
 // CHECKSTYLE_OFF: LineLength
@@ -85,6 +86,10 @@ import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 @Deprecated // this is no more stateless due to existence of testClassMethodRunHistoryMap since of 2.19. Rename to StatefulXmlReporter in 3.0.
 public class StatelessXmlReporter
 {
+    private static final String XML_INDENT = "  ";
+
+    private static final String XML_NL = "\n";
+
     private final File reportsDirectory;
 
     private final String reportNameSuffix;
@@ -128,8 +133,7 @@ public class StatelessXmlReporter
         OutputStreamWriter fw = getWriter( outputStream );
         try
         {
-            XMLWriter ppw = new PrettyPrintXMLWriter( fw );
-            ppw.setEncoding( StringUtils.UTF_8.name() );
+            XMLWriter ppw = new PrettyPrintXMLWriter( new PrintWriter( fw ), XML_INDENT, XML_NL, UTF_8.name(), null );
 
             createTestSuiteElement( ppw, testSetReportEntry, testSetStats, testSetReportEntry.elapsedTimeAsString() );
 
@@ -176,6 +180,11 @@ public class StatelessXmlReporter
                                                          singleRunEntry.getReportEntryType().getXmlTag(), false );
                                         createOutErrElements( fw, ppw, singleRunEntry, outputStream );
                                     }
+                                    else if ( singleRunEntry.getReportEntryType() == SKIPPED )
+                                    {
+                                        addCommentElementTestCase( "a skipped test execution in re-run phase",
+                                                fw, ppw, outputStream );
+                                    }
                                     else
                                     {
                                         getTestProblems( fw, ppw, singleRunEntry, trimStackTrace, outputStream,
@@ -508,6 +517,29 @@ public class StatelessXmlReporter
         return containsEscapesIllegalXml10( message ) ? escapeXml( message, attribute ) : message;
     }
 
+    private static void addCommentElementTestCase( String comment, OutputStreamWriter outputStreamWriter,
+                                                   XMLWriter xmlWriter, OutputStream fw )
+    {
+        try
+        {
+            xmlWriter.writeText( "" ); // Cheat sax to emit element
+            outputStreamWriter.flush();
+            fw.write( XML_NL.getBytes( UTF_8 ) );
+            fw.write( XML_INDENT.getBytes( UTF_8 ) );
+            fw.write( XML_INDENT.getBytes( UTF_8 ) );
+            fw.write( ByteConstantsHolder.COMMENT_START );
+            fw.write( comment.getBytes( UTF_8 ) );
+            fw.write( ByteConstantsHolder.COMMENT_END );
+            fw.write( XML_NL.getBytes( UTF_8 ) );
+            fw.write( XML_INDENT.getBytes( UTF_8 ) );
+            fw.flush();
+        }
+        catch ( IOException e )
+        {
+            throw new ReporterException( "When writing xml report stdout/stderr", e );
+        }
+    }
+
     private static final class EncodingOutputStream
         extends FilterOutputStream
     {
@@ -608,20 +640,16 @@ public class StatelessXmlReporter
 
     private static final class ByteConstantsHolder
     {
-        private static final byte[] CDATA_START_BYTES;
+        private static final byte[] CDATA_START_BYTES = "<![CDATA[".getBytes( UTF_8 );
 
-        private static final byte[] CDATA_END_BYTES;
+        private static final byte[] CDATA_END_BYTES = "]]>".getBytes( UTF_8 );
 
-        private static final byte[] CDATA_ESCAPE_STRING_BYTES;
+        private static final byte[] CDATA_ESCAPE_STRING_BYTES = "]]><![CDATA[>".getBytes( UTF_8 );
 
-        private static final byte[] AMP_BYTES;
+        private static final byte[] AMP_BYTES = "&amp#".getBytes( UTF_8 );
 
-        static
-        {
-            CDATA_START_BYTES = "<![CDATA[".getBytes( UTF_8 );
-            CDATA_END_BYTES = "]]>".getBytes( UTF_8 );
-            CDATA_ESCAPE_STRING_BYTES = "]]><![CDATA[>".getBytes( UTF_8 );
-            AMP_BYTES = "&amp#".getBytes( UTF_8 );
-        }
+        private static final byte[] COMMENT_START = "<!-- ".getBytes( UTF_8 );
+
+        private static final byte[] COMMENT_END = " --> ".getBytes( UTF_8 );
     }
 }
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
index 445eaa8..901a249 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/report/StatelessXmlReporterTest.java
@@ -21,15 +21,16 @@ package org.apache.maven.plugin.surefire.report;
 
 import junit.framework.TestCase;
 import org.apache.maven.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
-import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.xml.Xpp3Dom;
 import org.apache.maven.shared.utils.xml.Xpp3DomBuilder;
 import org.apache.maven.surefire.report.ReportEntry;
 import org.apache.maven.surefire.report.SimpleReportEntry;
 import org.apache.maven.surefire.report.StackTraceWriter;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.HashMap;
@@ -38,10 +39,15 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
+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.util.internal.ObjectUtils.systemProps;
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
 import static org.apache.maven.surefire.util.internal.StringUtils.UTF_8;
 
-@SuppressWarnings( "ResultOfMethodCallIgnored" )
+@SuppressWarnings( { "ResultOfMethodCallIgnored", "checkstyle:magicnumber" } )
 public class StatelessXmlReporterTest
     extends TestCase
 {
@@ -91,7 +97,7 @@ public class StatelessXmlReporterTest
 
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), getClass().getName(), 12 );
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+            new WrappedReportEntry( reportEntry, SUCCESS, 12, null, null, systemProps() );
         stats.testSucceeded( testSetReportEntry );
         reporter.testSetCompleted( testSetReportEntry, stats );
 
@@ -106,7 +112,7 @@ public class StatelessXmlReporterTest
     {
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+            new WrappedReportEntry( reportEntry, SUCCESS, 12, null, null, systemProps() );
         expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
@@ -135,7 +141,7 @@ public class StatelessXmlReporterTest
         stdErr.write( stdErrBytes, 0, stdErrBytes.length );
         WrappedReportEntry t2 =
             new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriter, 13 ),
-                                    ReportEntryType.ERROR, 13, stdOut, stdErr );
+                                    ERROR, 13, stdOut, stdErr );
 
         stats.testSucceeded( t2 );
         StatelessXmlReporter reporter = new StatelessXmlReporter( reportDir, null, false, 0,
@@ -149,8 +155,8 @@ public class StatelessXmlReporterTest
         Xpp3Dom properties = testSuite.getChild( "properties" );
         assertEquals( System.getProperties().size(), properties.getChildCount() );
         Xpp3Dom child = properties.getChild( 1 );
-        assertFalse( StringUtils.isEmpty( child.getAttribute( "value" ) ) );
-        assertFalse( StringUtils.isEmpty( child.getAttribute( "name" ) ) );
+        assertFalse( isBlank( child.getAttribute( "value" ) ) );
+        assertFalse( isBlank( child.getAttribute( "name" ) ) );
 
         Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
         Xpp3Dom tca = testcase[0];
@@ -178,7 +184,7 @@ public class StatelessXmlReporterTest
         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), TEST_ONE, 12 );
 
         WrappedReportEntry testSetReportEntry =
-            new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
+                new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
         expectedReportFile = new File( reportDir, "TEST-" + TEST_ONE + ".xml" );
 
         stats.testSucceeded( testSetReportEntry );
@@ -194,22 +200,22 @@ public class StatelessXmlReporterTest
 
         WrappedReportEntry testTwoFirstError =
             new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriterOne, 5 ),
-                                    ReportEntryType.ERROR, 5, createStdOutput( firstRunOut ),
+                                    ERROR, 5, createStdOutput( firstRunOut ),
                                     createStdOutput( firstRunErr ) );
 
         WrappedReportEntry testTwoSecondError =
             new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_TWO, stackTraceWriterTwo, 13 ),
-                                    ReportEntryType.ERROR, 13, createStdOutput( secondRunOut ),
+                                    ERROR, 13, createStdOutput( secondRunOut ),
                                     createStdOutput( secondRunErr ) );
 
         WrappedReportEntry testThreeFirstRun =
             new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_THREE, stackTraceWriterOne, 13 ),
-                                    ReportEntryType.FAILURE, 13, createStdOutput( firstRunOut ),
+                                    FAILURE, 13, createStdOutput( firstRunOut ),
                                     createStdOutput( firstRunErr ) );
 
         WrappedReportEntry testThreeSecondRun =
             new WrappedReportEntry( new SimpleReportEntry( Inner.class.getName(), TEST_THREE, stackTraceWriterTwo, 2 ),
-                                    ReportEntryType.SUCCESS, 2, createStdOutput( secondRunOut ),
+                                    SUCCESS, 2, createStdOutput( secondRunOut ),
                                     createStdOutput( secondRunErr ) );
 
         stats.testSucceeded( testTwoFirstError );
@@ -226,14 +232,14 @@ public class StatelessXmlReporterTest
 
         FileInputStream fileInputStream = new FileInputStream( expectedReportFile );
 
-        Xpp3Dom testSuite = Xpp3DomBuilder.build( new InputStreamReader( fileInputStream, UTF_8 ) );
+        Xpp3Dom testSuite = Xpp3DomBuilder.build( new InputStreamReader( fileInputStream, UTF_8) );
         assertEquals( "testsuite", testSuite.getName() );
         assertEquals( "0.012", testSuite.getAttribute( "time" ) );
         Xpp3Dom properties = testSuite.getChild( "properties" );
         assertEquals( System.getProperties().size(), properties.getChildCount() );
         Xpp3Dom child = properties.getChild( 1 );
-        assertFalse( StringUtils.isEmpty( child.getAttribute( "value" ) ) );
-        assertFalse( StringUtils.isEmpty( child.getAttribute( "name" ) ) );
+        assertFalse( isBlank( child.getAttribute( "value" ) ) );
+        assertFalse( isBlank( child.getAttribute( "name" ) ) );
 
         Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
         Xpp3Dom testCaseOne = testcase[0];
@@ -277,6 +283,79 @@ public class StatelessXmlReporterTest
         assertNull( testCaseThree.getChild( "system-err" ) );
     }
 
+    public void testOutputRerunFlakyAssumption()
+            throws IOException
+    {
+        expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
+
+        StackTraceWriter stackTraceWriterOne = new DeserializedStacktraceWriter( "A fud msg", "trimmed",
+                "fail at foo" );
+
+        StackTraceWriter stackTraceWriterTwo =
+                new DeserializedStacktraceWriter( "A fud msg two", "trimmed two", "fail at foo two" );
+
+        String firstRunOut = "first run out";
+        String firstRunErr = "first run err";
+        String secondRunOut = "second run out";
+        String secondRunErr = "second run err";
+
+        WrappedReportEntry testTwoFirstError =
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_TWO,
+                        stackTraceWriterOne, 5 ), ERROR, 5, createStdOutput( firstRunOut ),
+                        createStdOutput( firstRunErr ) );
+
+        stats.testSucceeded( testTwoFirstError );
+
+        WrappedReportEntry testTwoSecondError =
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), TEST_TWO,
+                        stackTraceWriterTwo, 13 ), SKIPPED, 13, createStdOutput( secondRunOut ),
+                        createStdOutput( secondRunErr ) );
+
+        rerunStats.testSucceeded( testTwoSecondError );
+
+        StatelessXmlReporter reporter =
+                new StatelessXmlReporter( reportDir, null, false, 1,
+                        new HashMap<String, Map<String, List<WrappedReportEntry>>>(), XSD );
+
+        WrappedReportEntry testSetReportEntry =
+                new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), getClass().getName(),
+                        stackTraceWriterOne, 5 ), ERROR, 20, createStdOutput( firstRunOut ),
+                        createStdOutput( firstRunErr ) );
+
+        reporter.testSetCompleted( testSetReportEntry, stats );
+        reporter.testSetCompleted( testSetReportEntry, rerunStats );
+
+        FileInputStream fileInputStream = new FileInputStream( expectedReportFile );
+
+        Xpp3Dom testSuite = Xpp3DomBuilder.build( new InputStreamReader( fileInputStream, UTF_8) );
+        assertEquals( "testsuite", testSuite.getName() );
+        assertEquals( "0.02", testSuite.getAttribute( "time" ) );
+
+        Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
+        assertEquals( 1, testcase.length );
+        Xpp3Dom testCaseOne = testcase[0];
+        assertEquals( getClass().getName(), testCaseOne.getAttribute( "classname" ) );
+        assertEquals( TEST_TWO, testCaseOne.getAttribute( "name" ) );
+        assertEquals( "0.005", testCaseOne.getAttribute( "time" ) );
+
+        Xpp3Dom[] testCaseElements = testCaseOne.getChildren();
+        assertEquals( 3, testCaseElements.length );
+        assertEquals( "error", testCaseElements[0].getName() );
+        assertEquals( "system-out", testCaseElements[1].getName() );
+        assertEquals( "system-err", testCaseElements[2].getName() );
+        long linesWithComments = 0;
+        BufferedReader reader = new BufferedReader( new FileReader( expectedReportFile ) );
+        for( String line = reader.readLine(); line != null; line = reader.readLine() )
+        {
+            line = reader.readLine();
+            if ( line.contains( "<!-- a skipped test execution in re-run phase -->" ) )
+            {
+                linesWithComments++;
+            }
+        }
+        assertEquals( 1, linesWithComments );
+    }
+
     private boolean defaultCharsetSupportsSpecialChar()
     {
         // some charsets are not able to deal with \u0115 on both ways of the conversion