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 java.io.IOException;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Queue;
26  import java.util.concurrent.ConcurrentLinkedQueue;
27  
28  import org.apache.maven.plugin.surefire.runorder.StatisticsReporter;
29  import org.apache.maven.surefire.api.report.ReportEntry;
30  import org.apache.maven.surefire.api.report.TestOutputReportEntry;
31  import org.apache.maven.surefire.api.report.TestReportListener;
32  import org.apache.maven.surefire.api.report.TestSetReportEntry;
33  import org.apache.maven.surefire.extensions.ConsoleOutputReportEventListener;
34  import org.apache.maven.surefire.extensions.StatelessReportEventListener;
35  import org.apache.maven.surefire.extensions.StatelessTestsetInfoConsoleReportEventListener;
36  import org.apache.maven.surefire.extensions.StatelessTestsetInfoFileReportEventListener;
37  
38  import static org.apache.maven.plugin.surefire.report.ReportEntryType.ERROR;
39  import static org.apache.maven.plugin.surefire.report.ReportEntryType.FAILURE;
40  import static org.apache.maven.plugin.surefire.report.ReportEntryType.SKIPPED;
41  import static org.apache.maven.plugin.surefire.report.ReportEntryType.SUCCESS;
42  
43  /**
44   * Reports data for a single test set.
45   * <br>
46   *
47   * @author Kristian Rosenvold
48   */
49  public class TestSetRunListener
50      implements TestReportListener<TestOutputReportEntry>
51  {
52      private final Queue<TestMethodStats> testMethodStats = new ConcurrentLinkedQueue<>();
53  
54      private final TestSetStats detailsForThis;
55  
56      private final ConsoleOutputReportEventListener testOutputReceiver;
57  
58      private final boolean briefOrPlainFormat;
59  
60      private final StatelessReportEventListener<WrappedReportEntry, TestSetStats> simpleXMLReporter;
61  
62      private final StatelessTestsetInfoConsoleReportEventListener<WrappedReportEntry, TestSetStats> consoleReporter;
63  
64      private final StatelessTestsetInfoFileReportEventListener<WrappedReportEntry, TestSetStats> fileReporter;
65  
66      private final StatisticsReporter statisticsReporter;
67  
68      private final Object lock;
69  
70      private Utf8RecodingDeferredFileOutputStream testStdOut = initDeferred( "stdout" );
71  
72      private Utf8RecodingDeferredFileOutputStream testStdErr = initDeferred( "stderr" );
73  
74      @SuppressWarnings( "checkstyle:parameternumber" )
75      public TestSetRunListener( StatelessTestsetInfoConsoleReportEventListener<WrappedReportEntry, TestSetStats>
76                                             consoleReporter,
77                                 StatelessTestsetInfoFileReportEventListener<WrappedReportEntry, TestSetStats>
78                                         fileReporter,
79                                 StatelessReportEventListener<WrappedReportEntry, TestSetStats> simpleXMLReporter,
80                                 ConsoleOutputReportEventListener testOutputReceiver,
81                                 StatisticsReporter statisticsReporter, boolean trimStackTrace,
82                                 boolean isPlainFormat, boolean briefOrPlainFormat, Object lock )
83      {
84          this.consoleReporter = consoleReporter;
85          this.fileReporter = fileReporter;
86          this.statisticsReporter = statisticsReporter;
87          this.simpleXMLReporter = simpleXMLReporter;
88          this.testOutputReceiver = testOutputReceiver;
89          this.briefOrPlainFormat = briefOrPlainFormat;
90          detailsForThis = new TestSetStats( trimStackTrace, isPlainFormat );
91          this.lock = lock;
92      }
93  
94      @Override
95      public boolean isDebugEnabled()
96      {
97          return consoleReporter.getConsoleLogger().isDebugEnabled();
98      }
99  
100     @Override
101     public void debug( String message )
102     {
103         synchronized ( lock )
104         {
105             consoleReporter.getConsoleLogger().debug( trimTrailingNewLine( message ) );
106         }
107     }
108 
109     @Override
110     public boolean isInfoEnabled()
111     {
112         return consoleReporter.getConsoleLogger().isInfoEnabled();
113     }
114 
115     @Override
116     public void info( String message )
117     {
118         synchronized ( lock )
119         {
120             consoleReporter.getConsoleLogger().info( trimTrailingNewLine( message ) );
121         }
122     }
123 
124     @Override
125     public boolean isWarnEnabled()
126     {
127         return consoleReporter.getConsoleLogger().isWarnEnabled();
128     }
129 
130     @Override
131     public void warning( String message )
132     {
133         synchronized ( lock )
134         {
135             consoleReporter.getConsoleLogger().warning( trimTrailingNewLine( message ) );
136         }
137     }
138 
139     @Override
140     public boolean isErrorEnabled()
141     {
142         return consoleReporter.getConsoleLogger().isErrorEnabled();
143     }
144 
145     @Override
146     public void error( String message )
147     {
148         synchronized ( lock )
149         {
150             consoleReporter.getConsoleLogger().error( trimTrailingNewLine( message ) );
151         }
152     }
153 
154     @Override
155     public void error( String message, Throwable t )
156     {
157         synchronized ( lock )
158         {
159             consoleReporter.getConsoleLogger().error( trimTrailingNewLine( message ), t );
160         }
161     }
162 
163     @Override
164     public void error( Throwable t )
165     {
166         synchronized ( lock )
167         {
168             consoleReporter.getConsoleLogger().error( t );
169         }
170     }
171 
172     @Override
173     public void writeTestOutput( TestOutputReportEntry reportEntry )
174     {
175         try
176         {
177             synchronized ( lock )
178             {
179                 Utf8RecodingDeferredFileOutputStream stream = reportEntry.isStdOut() ? testStdOut : testStdErr;
180                 stream.write( reportEntry.getLog(), reportEntry.isNewLine() );
181                 testOutputReceiver.writeTestOutput( reportEntry );
182             }
183         }
184         catch ( IOException e )
185         {
186             throw new RuntimeException( e );
187         }
188     }
189 
190     @Override
191     public void testSetStarting( TestSetReportEntry report )
192     {
193         detailsForThis.testSetStart();
194         consoleReporter.testSetStarting( report );
195         testOutputReceiver.testSetStarting( report );
196     }
197 
198     private void clearCapture()
199     {
200         if ( testStdOut != null )
201         {
202             testStdOut.commit();
203         }
204 
205         if ( testStdErr != null )
206         {
207             testStdErr.commit();
208         }
209 
210         testStdOut = initDeferred( "stdout" );
211         testStdErr = initDeferred( "stderr" );
212     }
213 
214     @Override
215     public void testSetCompleted( TestSetReportEntry report )
216     {
217         final WrappedReportEntry wrap = wrapTestSet( report );
218         final List<String> testResults =
219                 briefOrPlainFormat ? detailsForThis.getTestResults() : Collections.<String>emptyList();
220         fileReporter.testSetCompleted( wrap, detailsForThis, testResults );
221         simpleXMLReporter.testSetCompleted( wrap, detailsForThis );
222         statisticsReporter.testSetCompleted();
223         consoleReporter.testSetCompleted( wrap, detailsForThis, testResults );
224         testOutputReceiver.testSetCompleted( wrap );
225         consoleReporter.reset();
226 
227         wrap.getStdout().free();
228         wrap.getStdErr().free();
229 
230         addTestMethodStats();
231         detailsForThis.reset();
232         clearCapture();
233     }
234 
235     // ----------------------------------------------------------------------
236     // Test callback methods:
237     // ----------------------------------------------------------------------
238 
239     @Override
240     public void testStarting( ReportEntry report )
241     {
242         detailsForThis.testStart();
243     }
244 
245     @Override
246     public void testSucceeded( ReportEntry reportEntry )
247     {
248         WrappedReportEntry wrapped = wrap( reportEntry, SUCCESS );
249         detailsForThis.testSucceeded( wrapped );
250         statisticsReporter.testSucceeded( reportEntry );
251         clearCapture();
252     }
253 
254     @Override
255     public void testError( ReportEntry reportEntry )
256     {
257         WrappedReportEntry wrapped = wrap( reportEntry, ERROR );
258         detailsForThis.testError( wrapped );
259         statisticsReporter.testError( reportEntry );
260         clearCapture();
261     }
262 
263     @Override
264     public void testFailed( ReportEntry reportEntry )
265     {
266         WrappedReportEntry wrapped = wrap( reportEntry, FAILURE );
267         detailsForThis.testFailure( wrapped );
268         statisticsReporter.testFailed( reportEntry );
269         clearCapture();
270     }
271 
272     // ----------------------------------------------------------------------
273     // Counters
274     // ----------------------------------------------------------------------
275 
276     @Override
277     public void testSkipped( ReportEntry reportEntry )
278     {
279         WrappedReportEntry wrapped = wrap( reportEntry, SKIPPED );
280         detailsForThis.testSkipped( wrapped );
281         statisticsReporter.testSkipped( reportEntry );
282         clearCapture();
283     }
284 
285     @Override
286     public void testExecutionSkippedByUser()
287     {
288         clearCapture();
289     }
290 
291     @Override
292     public void testAssumptionFailure( ReportEntry report )
293     {
294         testSkipped( report );
295     }
296 
297     private WrappedReportEntry wrap( ReportEntry other, ReportEntryType reportEntryType )
298     {
299         int estimatedElapsed = 0;
300         if ( reportEntryType != SKIPPED )
301         {
302             Integer etime = other.getElapsed();
303             estimatedElapsed = etime == null ? detailsForThis.getElapsedSinceLastStart() : etime;
304         }
305 
306         return new WrappedReportEntry( other, reportEntryType, estimatedElapsed, testStdOut, testStdErr );
307     }
308 
309     private WrappedReportEntry wrapTestSet( TestSetReportEntry other )
310     {
311         return new WrappedReportEntry( other, null, other.getElapsed() != null
312             ? other.getElapsed()
313             : detailsForThis.getElapsedSinceTestSetStart(), testStdOut, testStdErr, other.getSystemProperties() );
314     }
315 
316     public void close()
317     {
318         testOutputReceiver.close();
319     }
320 
321     private void addTestMethodStats()
322     {
323         for ( WrappedReportEntry reportEntry : detailsForThis.getReportEntries() )
324         {
325             TestMethodStats methodStats =
326                 new TestMethodStats( reportEntry.getClassMethodName(), reportEntry.getReportEntryType(),
327                                      reportEntry.getStackTraceWriter() );
328             testMethodStats.add( methodStats );
329         }
330     }
331 
332     public Queue<TestMethodStats> getTestMethodStats()
333     {
334         return testMethodStats;
335     }
336 
337     private static String trimTrailingNewLine( final String message )
338     {
339         final int e = message == null ? 0 : lineBoundSymbolWidth( message );
340         return message != null && e != 0 ? message.substring( 0, message.length() - e ) : message;
341     }
342 
343     private static int lineBoundSymbolWidth( String message )
344     {
345         return message.endsWith( "\r\n" ) ? 2 : ( message.endsWith( "\n" ) || message.endsWith( "\r" ) ? 1 : 0 );
346     }
347 
348     private static Utf8RecodingDeferredFileOutputStream initDeferred( String channel )
349     {
350         return new Utf8RecodingDeferredFileOutputStream( channel );
351     }
352 }