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 return new String( out.toByteArray() );
122 }
123
124 public int getCompletedCount()
125 {
126 return completedCount;
127 }
128
129 public int getErrors()
130 {
131 return errors;
132 }
133
134 public int getFlakes()
135 {
136 return flakes;
137 }
138
139 public int getFailures()
140 {
141 return failures;
142 }
143
144 public int getSkipped()
145 {
146 return skipped;
147 }
148
149 public Integer getFailsafeCode()
150 {
151 if ( completedCount == 0 )
152 {
153 return NO_TESTS;
154 }
155 if ( !isErrorFree() )
156 {
157 return FAILURE;
158 }
159 return null;
160 }
161
162
163 public boolean isErrorFree()
164 {
165 return getFailures() == 0 && getErrors() == 0;
166 }
167
168
169 public boolean isFailureOrTimeout()
170 {
171 return this.timeout || isFailure();
172 }
173
174 public boolean isFailure()
175 {
176 return failure != null;
177 }
178
179 public String getFailure()
180 {
181 return failure;
182 }
183
184 public boolean isTimeout()
185 {
186 return timeout;
187 }
188
189
190 public RunResult aggregate( RunResult other )
191 {
192 String failureMessage = getFailure() != null ? getFailure() : other.getFailure();
193 boolean timeout = isTimeout() || other.isTimeout();
194 int completed = getCompletedCount() + other.getCompletedCount();
195 int fail = getFailures() + other.getFailures();
196 int ign = getSkipped() + other.getSkipped();
197 int err = getErrors() + other.getErrors();
198 int flakes = getFlakes() + other.getFlakes();
199 return new RunResult( completed, err, fail, ign, flakes, failureMessage, timeout );
200 }
201
202 public static RunResult noTestsRun()
203 {
204 return new RunResult( 0, 0, 0, 0 );
205 }
206
207 private Xpp3Dom create( String node, String value )
208 {
209 Xpp3Dom dom = new Xpp3Dom( node );
210 dom.setValue( value );
211 return dom;
212 }
213
214 private Xpp3Dom create( String node, int value )
215 {
216 return create( node, Integer.toString( value ) );
217 }
218
219 Xpp3Dom asXpp3Dom()
220 {
221 Xpp3Dom dom = new Xpp3Dom( "failsafe-summary" );
222 Integer failsafeCode = getFailsafeCode();
223 if ( failsafeCode != null )
224 {
225 dom.setAttribute( "result", Integer.toString( failsafeCode ) );
226 }
227 dom.setAttribute( "timeout", Boolean.toString( this.timeout ) );
228 dom.addChild( create( "completed", this.completedCount ) );
229 dom.addChild( create( "errors", this.errors ) );
230 dom.addChild( create( "failures", this.failures ) );
231 dom.addChild( create( "skipped", this.skipped ) );
232 dom.addChild( create( "failureMessage", this.failure ) );
233 return dom;
234 }
235
236 public static RunResult fromInputStream( InputStream inputStream, String encoding )
237 throws FileNotFoundException
238 {
239 Xpp3Dom dom = Xpp3DomBuilder.build( inputStream, encoding );
240 boolean timeout = Boolean.parseBoolean( dom.getAttribute( "timeout" ) );
241 int completed = Integer.parseInt( dom.getChild( "completed" ).getValue() );
242 int errors = Integer.parseInt( dom.getChild( "errors" ).getValue() );
243 int failures = Integer.parseInt( dom.getChild( "failures" ).getValue() );
244 int skipped = Integer.parseInt( dom.getChild( "skipped" ).getValue() );
245 String failureMessage1 = dom.getChild( "failureMessage" ).getValue();
246 String failureMessage = StringUtils.isEmpty( failureMessage1 ) ? null : failureMessage1;
247 return new RunResult( completed, errors, failures, skipped, failureMessage, timeout );
248 }
249
250 public void writeSummary( File summaryFile, boolean inProgress, String encoding )
251 throws IOException
252 {
253 if ( !summaryFile.getParentFile().isDirectory() )
254 {
255
256 summaryFile.getParentFile().mkdirs();
257 }
258
259 FileInputStream fin = null;
260 FileWriter writer = null;
261 try
262 {
263 RunResult mergedSummary = this;
264 if ( summaryFile.exists() && inProgress )
265 {
266 fin = new FileInputStream( summaryFile );
267
268 RunResult runResult = RunResult.fromInputStream( new BufferedInputStream( fin ), encoding );
269 mergedSummary = mergedSummary.aggregate( runResult );
270 }
271
272 writer = new FileWriter( summaryFile );
273 writer.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
274 PrettyPrintXMLWriter prettyPrintXMLWriter = new PrettyPrintXMLWriter( writer );
275 Xpp3DomWriter.write( prettyPrintXMLWriter, mergedSummary.asXpp3Dom() );
276 }
277 finally
278 {
279 IOUtil.close( fin );
280 IOUtil.close( writer );
281 }
282 }
283
284 @SuppressWarnings( "RedundantIfStatement" )
285 public boolean equals( Object o )
286 {
287 if ( this == o )
288 {
289 return true;
290 }
291 if ( o == null || getClass() != o.getClass() )
292 {
293 return false;
294 }
295
296 RunResult runResult = (RunResult) o;
297
298 if ( completedCount != runResult.completedCount )
299 {
300 return false;
301 }
302 if ( errors != runResult.errors )
303 {
304 return false;
305 }
306 if ( failures != runResult.failures )
307 {
308 return false;
309 }
310 if ( skipped != runResult.skipped )
311 {
312 return false;
313 }
314 if ( timeout != runResult.timeout )
315 {
316 return false;
317 }
318 if ( failure != null ? !failure.equals( runResult.failure ) : runResult.failure != null )
319 {
320 return false;
321 }
322
323 return true;
324 }
325
326 public int hashCode()
327 {
328 int result = completedCount;
329 result = 31 * result + errors;
330 result = 31 * result + failures;
331 result = 31 * result + skipped;
332 result = 31 * result + ( failure != null ? failure.hashCode() : 0 );
333 result = 31 * result + ( timeout ? 1 : 0 );
334 return result;
335 }
336 }