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         testStdOut = initDeferred( "stdout" );
201         testStdErr = initDeferred( "stderr" );
202     }
203 
204     @Override
205     public void testSetCompleted( TestSetReportEntry report )
206     {
207         final WrappedReportEntry wrap = wrapTestSet( report );
208         final List<String> testResults =
209                 briefOrPlainFormat ? detailsForThis.getTestResults() : Collections.<String>emptyList();
210         fileReporter.testSetCompleted( wrap, detailsForThis, testResults );
211         simpleXMLReporter.testSetCompleted( wrap, detailsForThis );
212         statisticsReporter.testSetCompleted();
213         consoleReporter.testSetCompleted( wrap, detailsForThis, testResults );
214         testOutputReceiver.testSetCompleted( wrap );
215         consoleReporter.reset();
216 
217         wrap.getStdout().free();
218         wrap.getStdErr().free();
219 
220         addTestMethodStats();
221         detailsForThis.reset();
222         clearCapture();
223     }
224 
225     // ----------------------------------------------------------------------
226     // Test callback methods:
227     // ----------------------------------------------------------------------
228 
229     @Override
230     public void testStarting( ReportEntry report )
231     {
232         detailsForThis.testStart();
233     }
234 
235     @Override
236     public void testSucceeded( ReportEntry reportEntry )
237     {
238         WrappedReportEntry wrapped = wrap( reportEntry, SUCCESS );
239         detailsForThis.testSucceeded( wrapped );
240         statisticsReporter.testSucceeded( reportEntry );
241         clearCapture();
242     }
243 
244     @Override
245     public void testError( ReportEntry reportEntry )
246     {
247         WrappedReportEntry wrapped = wrap( reportEntry, ERROR );
248         detailsForThis.testError( wrapped );
249         statisticsReporter.testError( reportEntry );
250         clearCapture();
251     }
252 
253     @Override
254     public void testFailed( ReportEntry reportEntry )
255     {
256         WrappedReportEntry wrapped = wrap( reportEntry, FAILURE );
257         detailsForThis.testFailure( wrapped );
258         statisticsReporter.testFailed( reportEntry );
259         clearCapture();
260     }
261 
262     // ----------------------------------------------------------------------
263     // Counters
264     // ----------------------------------------------------------------------
265 
266     @Override
267     public void testSkipped( ReportEntry reportEntry )
268     {
269         WrappedReportEntry wrapped = wrap( reportEntry, SKIPPED );
270         detailsForThis.testSkipped( wrapped );
271         statisticsReporter.testSkipped( reportEntry );
272         clearCapture();
273     }
274 
275     @Override
276     public void testExecutionSkippedByUser()
277     {
278     }
279 
280     @Override
281     public void testAssumptionFailure( ReportEntry report )
282     {
283         testSkipped( report );
284     }
285 
286     private WrappedReportEntry wrap( ReportEntry other, ReportEntryType reportEntryType )
287     {
288         int estimatedElapsed = 0;
289         if ( reportEntryType != SKIPPED )
290         {
291             Integer etime = other.getElapsed();
292             estimatedElapsed = etime == null ? detailsForThis.getElapsedSinceLastStart() : etime;
293         }
294 
295         return new WrappedReportEntry( other, reportEntryType, estimatedElapsed, testStdOut, testStdErr );
296     }
297 
298     private WrappedReportEntry wrapTestSet( TestSetReportEntry other )
299     {
300         return new WrappedReportEntry( other, null, other.getElapsed() != null
301             ? other.getElapsed()
302             : detailsForThis.getElapsedSinceTestSetStart(), testStdOut, testStdErr, other.getSystemProperties() );
303     }
304 
305     public void close()
306     {
307         testOutputReceiver.close();
308     }
309 
310     private void addTestMethodStats()
311     {
312         for ( WrappedReportEntry reportEntry : detailsForThis.getReportEntries() )
313         {
314             TestMethodStats methodStats =
315                 new TestMethodStats( reportEntry.getClassMethodName(), reportEntry.getReportEntryType(),
316                                      reportEntry.getStackTraceWriter() );
317             testMethodStats.add( methodStats );
318         }
319     }
320 
321     public Queue<TestMethodStats> getTestMethodStats()
322     {
323         return testMethodStats;
324     }
325 
326     private static String trimTrailingNewLine( final String message )
327     {
328         final int e = message == null ? 0 : lineBoundSymbolWidth( message );
329         return message != null && e != 0 ? message.substring( 0, message.length() - e ) : message;
330     }
331 
332     private static int lineBoundSymbolWidth( String message )
333     {
334         return message.endsWith( "\r\n" ) ? 2 : ( message.endsWith( "\n" ) || message.endsWith( "\r" ) ? 1 : 0 );
335     }
336 
337     private static Utf8RecodingDeferredFileOutputStream initDeferred( String channel )
338     {
339         return new Utf8RecodingDeferredFileOutputStream( channel );
340     }
341 }