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