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