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 org.apache.maven.shared.utils.logging.MessageBuilder;
23  import org.apache.maven.surefire.report.ReportEntry;
24  
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.List;
28  import java.util.Queue;
29  import java.util.concurrent.ConcurrentLinkedQueue;
30  
31  import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
32  
33  /**
34   * Maintains per-thread test result state. Not thread safe.
35   */
36  public class TestSetStats
37  {
38      private static final String TESTS = "Tests ";
39      private static final String RUN = "run: ";
40      private static final String TESTS_RUN = "Tests run: ";
41      private static final String FAILURES = "Failures: ";
42      private static final String ERRORS = "Errors: ";
43      private static final String SKIPPED = "Skipped: ";
44      private static final String FAILURE_MARKER = " <<< FAILURE!";
45      private static final String IN_MARKER = " - in ";
46      private static final String COMMA = ", ";
47  
48      private final Queue<WrappedReportEntry> reportEntries = new ConcurrentLinkedQueue<>();
49  
50      private final boolean trimStackTrace;
51  
52      private final boolean plainFormat;
53  
54      private long testSetStartAt;
55  
56      private long testStartAt;
57  
58      private int completedCount;
59  
60      private int errors;
61  
62      private int failures;
63  
64      private int skipped;
65  
66      private long lastStartAt;
67  
68      public TestSetStats( boolean trimStackTrace, boolean plainFormat )
69      {
70          this.trimStackTrace = trimStackTrace;
71          this.plainFormat = plainFormat;
72      }
73  
74      public int getElapsedSinceTestSetStart()
75      {
76          return testSetStartAt > 0 ? (int) ( System.currentTimeMillis() - testSetStartAt ) : 0;
77      }
78  
79      public int getElapsedSinceLastStart()
80      {
81          return lastStartAt > 0 ? (int) ( System.currentTimeMillis() - lastStartAt ) : 0;
82      }
83  
84      public void testSetStart()
85      {
86          testSetStartAt = System.currentTimeMillis();
87          lastStartAt = testSetStartAt;
88      }
89  
90      public void testStart()
91      {
92          testStartAt = System.currentTimeMillis();
93          lastStartAt = testStartAt;
94      }
95  
96      private void finishTest( WrappedReportEntry reportEntry )
97      {
98          reportEntries.add( reportEntry );
99          incrementCompletedCount();
100         // SUREFIRE-398 skipped tests call endTest without calling testStarting
101         // if startTime = 0, set it to endTime, so the diff will be 0
102         if ( testStartAt == 0 )
103         {
104             testStartAt = System.currentTimeMillis();
105         }
106     }
107 
108     public void testSucceeded( WrappedReportEntry reportEntry )
109     {
110         finishTest( reportEntry );
111     }
112 
113     public void testError( WrappedReportEntry reportEntry )
114     {
115         errors += 1;
116         finishTest( reportEntry );
117     }
118 
119     public void testFailure( WrappedReportEntry reportEntry )
120     {
121         failures += 1;
122         finishTest( reportEntry );
123     }
124 
125     public void testSkipped( WrappedReportEntry reportEntry )
126     {
127         skipped += 1;
128         finishTest( reportEntry );
129     }
130 
131     public void reset()
132     {
133         completedCount = 0;
134         errors = 0;
135         failures = 0;
136         skipped = 0;
137 
138         for ( WrappedReportEntry entry : reportEntries )
139         {
140             entry.getStdout().free();
141             entry.getStdErr().free();
142         }
143 
144         reportEntries.clear();
145     }
146 
147     public int getCompletedCount()
148     {
149         return completedCount;
150     }
151 
152     public int getErrors()
153     {
154         return errors;
155     }
156 
157     public int getFailures()
158     {
159         return failures;
160     }
161 
162     public int getSkipped()
163     {
164         return skipped;
165     }
166 
167     private void incrementCompletedCount()
168     {
169         completedCount += 1;
170     }
171 
172     public String getTestSetSummary( WrappedReportEntry reportEntry )
173     {
174         String summary = TESTS_RUN + completedCount
175                                  + COMMA
176                                  + FAILURES + failures
177                                  + COMMA
178                                  + ERRORS + errors
179                                  + COMMA
180                                  + SKIPPED + skipped
181                                  + COMMA
182                                  + reportEntry.getElapsedTimeVerbose();
183 
184         if ( failures > 0 || errors > 0 )
185         {
186             summary += FAILURE_MARKER;
187         }
188 
189         summary += IN_MARKER + reportEntry.getNameWithGroup();
190 
191         return summary;
192     }
193 
194     public String getColoredTestSetSummary( WrappedReportEntry reportEntry )
195     {
196         final boolean isSuccessful = failures == 0 && errors == 0 && skipped == 0;
197         final boolean isFailure = failures > 0;
198         final boolean isError = errors > 0;
199         final boolean isFailureOrError = isFailure | isError;
200         final boolean isSkipped = skipped > 0;
201         final  MessageBuilder builder = buffer();
202         if ( isSuccessful )
203         {
204             if ( completedCount == 0 )
205             {
206                 builder.strong( TESTS_RUN ).strong( completedCount );
207             }
208             else
209             {
210                 builder.success( TESTS_RUN ).success( completedCount );
211             }
212         }
213         else
214         {
215             if ( isFailureOrError )
216             {
217                 builder.failure( TESTS ).strong( RUN ).strong( completedCount );
218             }
219             else
220             {
221                 builder.warning( TESTS ).strong( RUN ).strong( completedCount );
222             }
223         }
224         builder.a( COMMA );
225         if ( isFailure )
226         {
227             builder.failure( FAILURES ).failure( failures );
228         }
229         else
230         {
231             builder.a( FAILURES ).a( failures );
232         }
233         builder.a( COMMA );
234         if ( isError )
235         {
236             builder.failure( ERRORS ).failure( errors );
237         }
238         else
239         {
240             builder.a( ERRORS ).a( errors );
241         }
242         builder.a( COMMA );
243         if ( isSkipped )
244         {
245             builder.warning( SKIPPED ).warning( skipped );
246         }
247         else
248         {
249             builder.a( SKIPPED ).a( skipped );
250         }
251         builder.a( COMMA )
252                 .a( reportEntry.getElapsedTimeVerbose() );
253         if ( isFailureOrError )
254         {
255             builder.failure( FAILURE_MARKER );
256         }
257         builder.a( IN_MARKER );
258         return concatenateWithTestGroup( builder, reportEntry );
259     }
260 
261     public List<String> getTestResults()
262     {
263         List<String> result = new ArrayList<>();
264         for ( WrappedReportEntry testResult : reportEntries )
265         {
266             if ( testResult.isErrorOrFailure() )
267             {
268                 result.add( testResult.getOutput( trimStackTrace ) );
269             }
270             else if ( plainFormat && testResult.isSkipped() )
271             {
272                 result.add( testResult.getName() + " skipped" );
273             }
274             else if ( plainFormat && testResult.isSucceeded() )
275             {
276                 result.add( testResult.getElapsedTimeSummary() );
277             }
278         }
279         // This should be Map with an enum and the enums will be displayed with colors on console.
280         return result;
281     }
282 
283     public Collection<WrappedReportEntry> getReportEntries()
284     {
285         return reportEntries;
286     }
287 
288     /**
289      * Append the test set message for a report.
290      * e.g. "org.foo.BarTest ( of group )"
291      *
292      * @param builder    MessageBuilder with preceded text inside
293      * @param report     report whose test set is starting
294      * @return the message
295      */
296     static String concatenateWithTestGroup( MessageBuilder builder, ReportEntry report )
297     {
298         final String testClass = report.getNameWithGroup();
299         int delimiter = testClass.lastIndexOf( '.' );
300         String pkg = testClass.substring( 0, 1 + delimiter );
301         String cls = testClass.substring( 1 + delimiter );
302         return builder.a( pkg )
303                        .strong( cls )
304                        .toString();
305     }
306 }