View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.surefire.report;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.Queue;
25  import java.util.concurrent.ConcurrentLinkedQueue;
26  
27  import org.apache.maven.surefire.api.report.ReportEntry;
28  import org.apache.maven.surefire.shared.utils.logging.MessageBuilder;
29  
30  import static org.apache.maven.surefire.api.report.CategorizedReportEntry.GROUP_PREFIX;
31  import static org.apache.maven.surefire.shared.utils.logging.MessageUtils.buffer;
32  
33  /**
34   * Maintains per-thread test result state. Not thread safe.
35   */
36  public class TestSetStats {
37      private static final String TESTS = "Tests ";
38      private static final String RUN = "run: ";
39      private static final String TESTS_RUN = "Tests run: ";
40      private static final String FAILURES = "Failures: ";
41      private static final String ERRORS = "Errors: ";
42      private static final String SKIPPED = "Skipped: ";
43      private static final String FAILURE_MARKER = " <<< FAILURE!";
44      private static final String IN_MARKER = " -- in ";
45      private static final String COMMA = ", ";
46  
47      private final Queue<WrappedReportEntry> reportEntries = new ConcurrentLinkedQueue<>();
48  
49      private final boolean trimStackTrace;
50  
51      private final boolean plainFormat;
52  
53      private long testSetStartAt;
54  
55      private long testStartAt;
56  
57      private int completedCount;
58  
59      private int errors;
60  
61      private int failures;
62  
63      private int skipped;
64  
65      private long lastStartAt;
66  
67      public TestSetStats(boolean trimStackTrace, boolean plainFormat) {
68          this.trimStackTrace = trimStackTrace;
69          this.plainFormat = plainFormat;
70      }
71  
72      public int getElapsedSinceTestSetStart() {
73          return testSetStartAt > 0 ? (int) (System.currentTimeMillis() - testSetStartAt) : 0;
74      }
75  
76      public int getElapsedSinceLastStart() {
77          return lastStartAt > 0 ? (int) (System.currentTimeMillis() - lastStartAt) : 0;
78      }
79  
80      public void testSetStart() {
81          testSetStartAt = System.currentTimeMillis();
82          lastStartAt = testSetStartAt;
83      }
84  
85      public void testStart() {
86          testStartAt = System.currentTimeMillis();
87          lastStartAt = testStartAt;
88      }
89  
90      private void finishTest(WrappedReportEntry reportEntry) {
91          reportEntries.add(reportEntry);
92          incrementCompletedCount();
93          // SUREFIRE-398 skipped tests call endTest without calling testStarting
94          // if startTime = 0, set it to endTime, so the diff will be 0
95          if (testStartAt == 0) {
96              testStartAt = System.currentTimeMillis();
97          }
98      }
99  
100     public void testSucceeded(WrappedReportEntry reportEntry) {
101         finishTest(reportEntry);
102     }
103 
104     public void testError(WrappedReportEntry reportEntry) {
105         errors += 1;
106         finishTest(reportEntry);
107     }
108 
109     public void testFailure(WrappedReportEntry reportEntry) {
110         failures += 1;
111         finishTest(reportEntry);
112     }
113 
114     public void testSkipped(WrappedReportEntry reportEntry) {
115         skipped += 1;
116         finishTest(reportEntry);
117     }
118 
119     public void reset() {
120         completedCount = 0;
121         errors = 0;
122         failures = 0;
123         skipped = 0;
124 
125         for (WrappedReportEntry entry : reportEntries) {
126             entry.getStdout().free();
127             entry.getStdErr().free();
128         }
129 
130         reportEntries.clear();
131     }
132 
133     public int getCompletedCount() {
134         return completedCount;
135     }
136 
137     public int getErrors() {
138         return errors;
139     }
140 
141     public int getFailures() {
142         return failures;
143     }
144 
145     public int getSkipped() {
146         return skipped;
147     }
148 
149     private void incrementCompletedCount() {
150         completedCount += 1;
151     }
152 
153     public String getTestSetSummary(WrappedReportEntry reportEntry, boolean phrasedClassName) {
154         String summary = TESTS_RUN
155                 + completedCount
156                 + COMMA
157                 + FAILURES
158                 + failures
159                 + COMMA
160                 + ERRORS
161                 + errors
162                 + COMMA
163                 + SKIPPED
164                 + skipped
165                 + COMMA
166                 + reportEntry.getElapsedTimeVerbose();
167 
168         if (failures > 0 || errors > 0) {
169             summary += FAILURE_MARKER;
170         }
171 
172         summary += IN_MARKER;
173         summary += phrasedClassName ? reportEntry.getReportNameWithGroup() : reportEntry.getNameWithGroup();
174 
175         return summary;
176     }
177 
178     public String getColoredTestSetSummary(WrappedReportEntry reportEntry, boolean phrasedClassName) {
179         final boolean isSuccessful = failures == 0 && errors == 0 && skipped == 0;
180         final boolean isFailure = failures > 0;
181         final boolean isError = errors > 0;
182         final boolean isFailureOrError = isFailure | isError;
183         final boolean isSkipped = skipped > 0;
184         final MessageBuilder builder = buffer();
185         if (isSuccessful) {
186             if (completedCount == 0) {
187                 builder.strong(TESTS_RUN).strong(completedCount);
188             } else {
189                 builder.success(TESTS_RUN).success(completedCount);
190             }
191         } else {
192             if (isFailureOrError) {
193                 builder.failure(TESTS).strong(RUN).strong(completedCount);
194             } else {
195                 builder.warning(TESTS).strong(RUN).strong(completedCount);
196             }
197         }
198         builder.a(COMMA);
199         if (isFailure) {
200             builder.failure(FAILURES).failure(failures);
201         } else {
202             builder.a(FAILURES).a(failures);
203         }
204         builder.a(COMMA);
205         if (isError) {
206             builder.failure(ERRORS).failure(errors);
207         } else {
208             builder.a(ERRORS).a(errors);
209         }
210         builder.a(COMMA);
211         if (isSkipped) {
212             builder.warning(SKIPPED).warning(skipped);
213         } else {
214             builder.a(SKIPPED).a(skipped);
215         }
216         builder.a(COMMA).a(reportEntry.getElapsedTimeVerbose());
217         if (isFailureOrError) {
218             builder.failure(FAILURE_MARKER);
219         }
220         builder.a(IN_MARKER);
221         return concatenateWithTestGroup(builder, reportEntry, phrasedClassName);
222     }
223 
224     public List<String> getTestResults() {
225         List<String> result = new ArrayList<>();
226         for (WrappedReportEntry testResult : reportEntries) {
227             if (testResult.isErrorOrFailure()) {
228                 result.add(testResult.getOutput(trimStackTrace));
229             } else if (plainFormat && testResult.isSkipped()) {
230                 result.add(testResult.getSourceName() + " skipped");
231             } else if (plainFormat && testResult.isSucceeded()) {
232                 result.add(testResult.getElapsedTimeSummary());
233             }
234         }
235         // This should be Map with an enum and the enums will be displayed with colors on console.
236         return result;
237     }
238 
239     public Collection<WrappedReportEntry> getReportEntries() {
240         return reportEntries;
241     }
242 
243     /**
244      * Append the test set message for a report.
245      * e.g. "org.foo.BarTest ( of group )" or phrased text "test class description ( of group )".
246      *
247      * @param builder    MessageBuilder with preceded text inside
248      * @param report     report whose test set is starting
249      * @return the message
250      */
251     static String concatenateWithTestGroup(MessageBuilder builder, ReportEntry report, boolean phrasedClassName) {
252         if (phrasedClassName && report.getReportNameWithGroup() != null) {
253             return builder.strong(report.getReportNameWithGroup()).toString();
254         } else {
255             String testClass = report.getNameWithGroup();
256             int indexOfGroup = testClass.indexOf(GROUP_PREFIX);
257             int delimiter = testClass.lastIndexOf('.', indexOfGroup == -1 ? testClass.length() : indexOfGroup);
258             String pkg = testClass.substring(0, 1 + delimiter);
259             String cls = testClass.substring(1 + delimiter);
260             return builder.a(pkg).strong(cls).toString();
261         }
262     }
263 }