View Javadoc

1   package org.apache.maven.surefire.suite;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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   * Represents a test-run-result; this may be from a single test run or an aggregated result.
40   * <p/>
41   * In the case of timeout==true, the run-counts reflect the state of the test-run at the time
42   * of the timeout.
43   *
44   * @author Kristian Rosenvold
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()  // Only used for compatibility reasons.
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     /* Indicates if the tests are error free */
144     public boolean isErrorFree()
145     {
146         return getFailures() == 0 && getErrors() == 0;
147     }
148 
149     /* Indicates test timeout or technical failure */
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             //noinspection ResultOfMethodCallIgnored
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 }