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