View Javadoc
1   package org.apache.maven.plugin.surefire.report;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import junit.framework.TestCase;
23  import org.apache.maven.plugin.surefire.booterclient.output.DeserializedStacktraceWriter;
24  import org.apache.maven.surefire.shared.utils.StringUtils;
25  import org.apache.maven.surefire.shared.utils.xml.Xpp3Dom;
26  import org.apache.maven.surefire.shared.utils.xml.Xpp3DomBuilder;
27  import org.apache.maven.surefire.api.report.ReportEntry;
28  import org.apache.maven.surefire.api.report.SimpleReportEntry;
29  import org.apache.maven.surefire.api.report.StackTraceWriter;
30  
31  import java.io.File;
32  import java.io.FileInputStream;
33  import java.io.IOException;
34  import java.io.InputStreamReader;
35  import java.util.Deque;
36  import java.util.HashMap;
37  import java.util.concurrent.ConcurrentHashMap;
38  import java.util.concurrent.atomic.AtomicInteger;
39  
40  import static java.nio.charset.StandardCharsets.UTF_8;
41  import static org.apache.maven.surefire.api.util.internal.ObjectUtils.systemProps;
42  
43  /**
44   *
45   */
46  @SuppressWarnings( "ResultOfMethodCallIgnored" )
47  public class StatelessXmlReporterTest
48          extends TestCase
49  {
50      private static final String XSD =
51              "https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report-3.0.xsd";
52      private static final String TEST_ONE = "aTestMethod";
53      private static final String TEST_TWO = "bTestMethod";
54      private static final String TEST_THREE = "cTestMethod";
55      private static final AtomicInteger FOLDER_POSTFIX = new AtomicInteger();
56  
57      private TestSetStats stats;
58      private TestSetStats rerunStats;
59      private File expectedReportFile;
60      private File reportDir;
61  
62      @Override
63      protected void setUp()
64              throws Exception
65      {
66          stats = new TestSetStats( false, true );
67          rerunStats = new TestSetStats( false, true );
68  
69          File basedir = new File( "." );
70          File target = new File( basedir.getCanonicalFile(), "target" );
71          target.mkdir();
72          String reportRelDir = getClass().getSimpleName() + "-" + FOLDER_POSTFIX.incrementAndGet();
73          reportDir = new File( target, reportRelDir );
74          reportDir.mkdir();
75      }
76  
77      @Override
78      protected void tearDown()
79      {
80          if ( expectedReportFile != null )
81          {
82              expectedReportFile.delete();
83          }
84      }
85  
86      public void testFileNameWithoutSuffix()
87      {
88          StatelessXmlReporter reporter =
89                  new StatelessXmlReporter( reportDir, null, false, 0,
90                          new ConcurrentHashMap<String, Deque<WrappedReportEntry>>(), XSD, "3.0",
91                          false, false, false, false );
92          reporter.cleanTestHistoryMap();
93  
94          ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), null, getClass().getName(), null, 12 );
95          WrappedReportEntry testSetReportEntry = new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS,
96                  12, null, null, systemProps() );
97          stats.testSucceeded( testSetReportEntry );
98          reporter.testSetCompleted( testSetReportEntry, stats );
99  
100         expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
101         assertTrue( "Report file (" + expectedReportFile.getAbsolutePath() + ") doesn't exist",
102                 expectedReportFile.exists() );
103     }
104 
105 
106     public void testAllFieldsSerialized()
107             throws IOException
108     {
109         ReportEntry reportEntry = new SimpleReportEntry( getClass().getName(), null, TEST_ONE, null, 12 );
110         WrappedReportEntry testSetReportEntry =
111                 new WrappedReportEntry( reportEntry, ReportEntryType.SUCCESS, 12, null, null, systemProps() );
112         expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
113 
114         stats.testSucceeded( testSetReportEntry );
115         StackTraceWriter stackTraceWriter = new DeserializedStacktraceWriter( "A fud msg", "trimmed", "fail at foo" );
116         Utf8RecodingDeferredFileOutputStream stdOut = new Utf8RecodingDeferredFileOutputStream( "fds" );
117         String stdOutPrefix;
118         String stdErrPrefix;
119         if ( defaultCharsetSupportsSpecialChar() )
120         {
121             stdErrPrefix = "std-\u0115rr";
122             stdOutPrefix = "st]]>d-o\u00DCt";
123         }
124         else
125         {
126             stdErrPrefix = "std-err";
127             stdOutPrefix = "st]]>d-out";
128         }
129 
130         stdOut.write( stdOutPrefix + "<null>!\u0020\u0000\u001F", false );
131 
132         Utf8RecodingDeferredFileOutputStream stdErr = new Utf8RecodingDeferredFileOutputStream( "fds" );
133 
134         stdErr.write( stdErrPrefix + "?&-&amp;&#163;\u0020\u0000\u001F", false );
135         WrappedReportEntry t2 =
136                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_TWO, null,
137                         stackTraceWriter, 13 ), ReportEntryType.ERROR, 13, stdOut, stdErr );
138 
139         stats.testSucceeded( t2 );
140         StatelessXmlReporter reporter = new StatelessXmlReporter( reportDir, null, false, 0,
141                 new ConcurrentHashMap<String, Deque<WrappedReportEntry>>(), XSD, "3.0", false, false, false, false );
142         reporter.testSetCompleted( testSetReportEntry, stats );
143 
144         FileInputStream fileInputStream = new FileInputStream( expectedReportFile );
145 
146         Xpp3Dom testSuite = Xpp3DomBuilder.build( new InputStreamReader( fileInputStream, UTF_8 ) );
147         assertEquals( "testsuite", testSuite.getName() );
148         Xpp3Dom properties = testSuite.getChild( "properties" );
149         assertEquals( System.getProperties().size(), properties.getChildCount() );
150         Xpp3Dom child = properties.getChild( 1 );
151         assertFalse( StringUtils.isEmpty( child.getAttribute( "value" ) ) );
152         assertFalse( StringUtils.isEmpty( child.getAttribute( "name" ) ) );
153 
154         Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
155         Xpp3Dom tca = testcase[0];
156         assertEquals( TEST_ONE, tca.getAttribute( "name" ) );
157         assertEquals( "0.012", tca.getAttribute( "time" ) );
158         assertEquals( getClass().getName(), tca.getAttribute( "classname" ) );
159 
160         Xpp3Dom tcb = testcase[1];
161         assertEquals( TEST_TWO, tcb.getAttribute( "name" ) );
162         assertEquals( "0.013", tcb.getAttribute( "time" ) );
163         assertEquals( getClass().getName(), tcb.getAttribute( "classname" ) );
164         Xpp3Dom errorNode = tcb.getChild( "error" );
165         assertNotNull( errorNode );
166         assertEquals( "A fud msg", errorNode.getAttribute( "message" ) );
167         assertEquals( "fail at foo", errorNode.getAttribute( "type" ) );
168         assertEquals( stdOutPrefix + "<null>! &amp#0;&amp#31;", tcb.getChild( "system-out" ).getValue() );
169 
170 
171         assertEquals( stdErrPrefix + "?&-&amp;&#163; &amp#0;&amp#31;", tcb.getChild( "system-err" ).getValue() );
172     }
173 
174     public void testOutputRerunFlakyFailure()
175             throws IOException
176     {
177         WrappedReportEntry testSetReportEntry =
178                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_ONE, null, 12 ),
179                         ReportEntryType.SUCCESS, 12, null, null, systemProps() );
180         expectedReportFile = new File( reportDir, "TEST-" + getClass().getName() + ".xml" );
181 
182         stats.testSucceeded( testSetReportEntry );
183         StackTraceWriter stackTraceWriterOne = new DeserializedStacktraceWriter( "A fud msg", "trimmed",
184                 "fail at foo" );
185         StackTraceWriter stackTraceWriterTwo =
186                 new DeserializedStacktraceWriter( "A fud msg two", "trimmed two", "fail at foo two" );
187 
188         String firstRunOut = "first run out";
189         String firstRunErr = "first run err";
190         String secondRunOut = "second run out";
191         String secondRunErr = "second run err";
192 
193         WrappedReportEntry testTwoFirstError =
194                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_TWO, null,
195                         stackTraceWriterOne, 5 ), ReportEntryType.ERROR, 5, createStdOutput( firstRunOut ),
196                         createStdOutput( firstRunErr ) );
197 
198         WrappedReportEntry testTwoSecondError =
199                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_TWO, null,
200                         stackTraceWriterTwo, 13 ), ReportEntryType.ERROR, 13, createStdOutput( secondRunOut ),
201                         createStdOutput( secondRunErr ) );
202 
203         WrappedReportEntry testThreeFirstRun =
204                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_THREE, null,
205                         stackTraceWriterOne, 13 ), ReportEntryType.FAILURE, 13, createStdOutput( firstRunOut ),
206                         createStdOutput( firstRunErr ) );
207 
208         WrappedReportEntry testThreeSecondRun =
209                 new WrappedReportEntry( new SimpleReportEntry( getClass().getName(), null, TEST_THREE, null,
210                         stackTraceWriterTwo, 2 ), ReportEntryType.SUCCESS, 2, createStdOutput( secondRunOut ),
211                         createStdOutput( secondRunErr ) );
212 
213         stats.testSucceeded( testTwoFirstError );
214         stats.testSucceeded( testThreeFirstRun );
215         rerunStats.testSucceeded( testTwoSecondError );
216         rerunStats.testSucceeded( testThreeSecondRun );
217 
218         StatelessXmlReporter reporter =
219                 new StatelessXmlReporter( reportDir, null, false, 1,
220                         new HashMap<String, Deque<WrappedReportEntry>>(), XSD, "3.0", false, false, false, false );
221 
222         reporter.testSetCompleted( testSetReportEntry, stats );
223         reporter.testSetCompleted( testSetReportEntry, rerunStats );
224 
225         FileInputStream fileInputStream = new FileInputStream( expectedReportFile );
226 
227         Xpp3Dom testSuite = Xpp3DomBuilder.build( new InputStreamReader( fileInputStream, UTF_8 ) );
228         assertEquals( "testsuite", testSuite.getName() );
229         assertEquals( "0.012", testSuite.getAttribute( "time" ) );
230         Xpp3Dom properties = testSuite.getChild( "properties" );
231         assertEquals( System.getProperties().size(), properties.getChildCount() );
232         Xpp3Dom child = properties.getChild( 1 );
233         assertFalse( StringUtils.isEmpty( child.getAttribute( "value" ) ) );
234         assertFalse( StringUtils.isEmpty( child.getAttribute( "name" ) ) );
235 
236         Xpp3Dom[] testcase = testSuite.getChildren( "testcase" );
237         Xpp3Dom testCaseOne = testcase[0];
238         assertEquals( TEST_ONE, testCaseOne.getAttribute( "name" ) );
239         assertEquals( "0.012", testCaseOne.getAttribute( "time" ) );
240         assertEquals( getClass().getName(), testCaseOne.getAttribute( "classname" ) );
241 
242         Xpp3Dom testCaseTwo = testcase[1];
243         assertEquals( TEST_TWO, testCaseTwo.getAttribute( "name" ) );
244         // Run time for a rerun failing test is the run time of the first run
245         assertEquals( "0.005", testCaseTwo.getAttribute( "time" ) );
246         assertEquals( getClass().getName(), testCaseTwo.getAttribute( "classname" ) );
247         Xpp3Dom errorNode = testCaseTwo.getChild( "error" );
248         Xpp3Dom rerunErrorNode = testCaseTwo.getChild( "rerunError" );
249         assertNotNull( errorNode );
250         assertNotNull( rerunErrorNode );
251 
252         assertEquals( "A fud msg", errorNode.getAttribute( "message" ) );
253         assertEquals( "fail at foo", errorNode.getAttribute( "type" ) );
254 
255         // Check rerun error node contains all the information
256         assertEquals( firstRunOut, testCaseTwo.getChild( "system-out" ).getValue() );
257         assertEquals( firstRunErr, testCaseTwo.getChild( "system-err" ).getValue() );
258         assertEquals( secondRunOut, rerunErrorNode.getChild( "system-out" ).getValue() );
259         assertEquals( secondRunErr, rerunErrorNode.getChild( "system-err" ).getValue() );
260         assertEquals( "A fud msg two", rerunErrorNode.getAttribute( "message" ) );
261         assertEquals( "fail at foo two", rerunErrorNode.getAttribute( "type" ) );
262 
263         // Check flaky failure node
264         Xpp3Dom testCaseThree = testcase[2];
265         assertEquals( TEST_THREE, testCaseThree.getAttribute( "name" ) );
266         // Run time for a flaky test is the run time of the first successful run
267         assertEquals( "0.002", testCaseThree.getAttribute( "time" ) );
268         assertEquals( getClass().getName(), testCaseThree.getAttribute( "classname" ) );
269         Xpp3Dom flakyFailureNode = testCaseThree.getChild( "flakyFailure" );
270         assertNotNull( flakyFailureNode );
271         assertEquals( firstRunOut, flakyFailureNode.getChild( "system-out" ).getValue() );
272         assertEquals( firstRunErr, flakyFailureNode.getChild( "system-err" ).getValue() );
273         // system-out and system-err should not be present for flaky failures
274         assertNull( testCaseThree.getChild( "system-out" ) );
275         assertNull( testCaseThree.getChild( "system-err" ) );
276     }
277 
278     private boolean defaultCharsetSupportsSpecialChar()
279     {
280         // some charsets are not able to deal with \u0115 on both ways of the conversion
281         return "\u0115\u00DC".equals( new String( "\u0115\u00DC".getBytes() ) );
282     }
283 
284     private Utf8RecodingDeferredFileOutputStream createStdOutput( String content )
285             throws IOException
286     {
287         Utf8RecodingDeferredFileOutputStream stdOut = new Utf8RecodingDeferredFileOutputStream( "fds2" );
288         stdOut.write( content, false );
289         return stdOut;
290     }
291 }