1 package org.apache.maven.surefire.suite;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.shared.utils.StringUtils;
23 import org.apache.maven.shared.utils.io.IOUtil;
24 import org.apache.maven.shared.utils.xml.PrettyPrintXMLWriter;
25 import org.apache.maven.shared.utils.xml.Xpp3Dom;
26 import org.apache.maven.shared.utils.xml.Xpp3DomBuilder;
27 import org.apache.maven.shared.utils.xml.Xpp3DomWriter;
28
29 import java.io.BufferedInputStream;
30 import java.io.ByteArrayOutputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileNotFoundException;
34 import java.io.FileWriter;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.PrintWriter;
38
39
40
41
42
43
44
45
46
47 public class RunResult
48 {
49 private final int completedCount;
50
51 private final int errors;
52
53 private final int failures;
54
55 private final int skipped;
56
57 private final int flakes;
58
59 private final String failure;
60
61 private final boolean timeout;
62
63 public static final int SUCCESS = 0;
64
65 private static final int FAILURE = 255;
66
67 private static final int NO_TESTS = 254;
68
69 public static RunResult timeout( RunResult accumulatedAtTimeout )
70 {
71 return errorCode( accumulatedAtTimeout, accumulatedAtTimeout.getFailure(), true );
72 }
73
74 public static RunResult failure( RunResult accumulatedAtTimeout, Exception cause )
75 {
76 return errorCode( accumulatedAtTimeout, getStackTrace( cause ), accumulatedAtTimeout.isTimeout() );
77 }
78
79 private static RunResult errorCode( RunResult other, String failure, boolean timeout )
80 {
81 return new RunResult( other.getCompletedCount(), other.getErrors(), other.getFailures(), other.getSkipped(),
82 failure, timeout );
83
84 }
85
86 public RunResult( int completedCount, int errors, int failures, int skipped )
87 {
88 this( completedCount, errors, failures, skipped, null, false );
89 }
90
91 public RunResult( int completedCount, int errors, int failures, int skipped, int flakes )
92 {
93 this( completedCount, errors, failures, skipped, flakes, null, false );
94 }
95
96 public RunResult( int completedCount, int errors, int failures, int skipped, String failure, boolean timeout )
97 {
98 this( completedCount, errors, failures, skipped, 0, failure, timeout );
99 }
100
101 public RunResult( int completedCount, int errors, int failures, int skipped, int flakes, String failure,
102 boolean timeout )
103 {
104 this.completedCount = completedCount;
105 this.errors = errors;
106 this.failures = failures;
107 this.skipped = skipped;
108 this.failure = failure;
109 this.timeout = timeout;
110 this.flakes = flakes;
111 }
112
113 private static String getStackTrace( Exception e )
114 {
115 if ( e == null )
116 {
117 return null;
118 }
119 ByteArrayOutputStream out = new ByteArrayOutputStream();
120 PrintWriter pw = new PrintWriter( out );
121 try
122 {
123 e.printStackTrace( pw );
124 }
125 finally
126 {
127 pw.close();
128 }
129 return new String( out.toByteArray() );
130 }
131
132 public int getCompletedCount()
133 {
134 return completedCount;
135 }
136
137 public int getErrors()
138 {
139 return errors;
140 }
141
142 public int getFlakes()
143 {
144 return flakes;
145 }
146
147 public int getFailures()
148 {
149 return failures;
150 }
151
152 public int getSkipped()
153 {
154 return skipped;
155 }
156
157 public Integer getFailsafeCode()
158 {
159 if ( completedCount == 0 )
160 {
161 return NO_TESTS;
162 }
163 if ( !isErrorFree() )
164 {
165 return FAILURE;
166 }
167 return null;
168 }
169
170
171 public boolean isErrorFree()
172 {
173 return getFailures() == 0 && getErrors() == 0;
174 }
175
176
177 public boolean isFailureOrTimeout()
178 {
179 return this.timeout || isFailure();
180 }
181
182 public boolean isFailure()
183 {
184 return failure != null;
185 }
186
187 public String getFailure()
188 {
189 return failure;
190 }
191
192 public boolean isTimeout()
193 {
194 return timeout;
195 }
196
197
198 public RunResult aggregate( RunResult other )
199 {
200 String failureMessage = getFailure() != null ? getFailure() : other.getFailure();
201 boolean timeout = isTimeout() || other.isTimeout();
202 int completed = getCompletedCount() + other.getCompletedCount();
203 int fail = getFailures() + other.getFailures();
204 int ign = getSkipped() + other.getSkipped();
205 int err = getErrors() + other.getErrors();
206 int flakes = getFlakes() + other.getFlakes();
207 return new RunResult( completed, err, fail, ign, flakes, failureMessage, timeout );
208 }
209
210 public static RunResult noTestsRun()
211 {
212 return new RunResult( 0, 0, 0, 0 );
213 }
214
215 private Xpp3Dom create( String node, String value )
216 {
217 Xpp3Dom dom = new Xpp3Dom( node );
218 dom.setValue( value );
219 return dom;
220 }
221
222 private Xpp3Dom create( String node, int value )
223 {
224 return create( node, Integer.toString( value ) );
225 }
226
227 Xpp3Dom asXpp3Dom()
228 {
229 Xpp3Dom dom = new Xpp3Dom( "failsafe-summary" );
230 Integer failsafeCode = getFailsafeCode();
231 if ( failsafeCode != null )
232 {
233 dom.setAttribute( "result", Integer.toString( failsafeCode ) );
234 }
235 dom.setAttribute( "timeout", Boolean.toString( this.timeout ) );
236 dom.addChild( create( "completed", this.completedCount ) );
237 dom.addChild( create( "errors", this.errors ) );
238 dom.addChild( create( "failures", this.failures ) );
239 dom.addChild( create( "skipped", this.skipped ) );
240 dom.addChild( create( "failureMessage", this.failure ) );
241 return dom;
242 }
243
244 public static RunResult fromInputStream( InputStream inputStream, String encoding )
245 throws FileNotFoundException
246 {
247 Xpp3Dom dom = Xpp3DomBuilder.build( inputStream, encoding );
248 boolean timeout = Boolean.parseBoolean( dom.getAttribute( "timeout" ) );
249 int completed = Integer.parseInt( dom.getChild( "completed" ).getValue() );
250 int errors = Integer.parseInt( dom.getChild( "errors" ).getValue() );
251 int failures = Integer.parseInt( dom.getChild( "failures" ).getValue() );
252 int skipped = Integer.parseInt( dom.getChild( "skipped" ).getValue() );
253 String failureMessage1 = dom.getChild( "failureMessage" ).getValue();
254 String failureMessage = StringUtils.isEmpty( failureMessage1 ) ? null : failureMessage1;
255 return new RunResult( completed, errors, failures, skipped, failureMessage, timeout );
256 }
257
258 public void writeSummary( File summaryFile, boolean inProgress, String encoding )
259 throws IOException
260 {
261 if ( !summaryFile.getParentFile().isDirectory() )
262 {
263
264 summaryFile.getParentFile().mkdirs();
265 }
266
267 FileInputStream fin = null;
268 FileWriter writer = null;
269 try
270 {
271 RunResult mergedSummary = this;
272 if ( summaryFile.exists() && inProgress )
273 {
274 fin = new FileInputStream( summaryFile );
275
276 RunResult runResult = RunResult.fromInputStream( new BufferedInputStream( fin ), encoding );
277 mergedSummary = mergedSummary.aggregate( runResult );
278 }
279
280 writer = new FileWriter( summaryFile );
281 writer.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
282 PrettyPrintXMLWriter prettyPrintXMLWriter = new PrettyPrintXMLWriter( writer );
283 Xpp3DomWriter.write( prettyPrintXMLWriter, mergedSummary.asXpp3Dom() );
284 }
285 finally
286 {
287 IOUtil.close( fin );
288 IOUtil.close( writer );
289 }
290 }
291
292 @SuppressWarnings( "RedundantIfStatement" )
293 public boolean equals( Object o )
294 {
295 if ( this == o )
296 {
297 return true;
298 }
299 if ( o == null || getClass() != o.getClass() )
300 {
301 return false;
302 }
303
304 RunResult runResult = (RunResult) o;
305
306 if ( completedCount != runResult.completedCount )
307 {
308 return false;
309 }
310 if ( errors != runResult.errors )
311 {
312 return false;
313 }
314 if ( failures != runResult.failures )
315 {
316 return false;
317 }
318 if ( skipped != runResult.skipped )
319 {
320 return false;
321 }
322 if ( timeout != runResult.timeout )
323 {
324 return false;
325 }
326 if ( failure != null ? !failure.equals( runResult.failure ) : runResult.failure != null )
327 {
328 return false;
329 }
330
331 return true;
332 }
333
334 public int hashCode()
335 {
336 int result = completedCount;
337 result = 31 * result + errors;
338 result = 31 * result + failures;
339 result = 31 * result + skipped;
340 result = 31 * result + ( failure != null ? failure.hashCode() : 0 );
341 result = 31 * result + ( timeout ? 1 : 0 );
342 return result;
343 }
344 }