1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.testcase;
14
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.Future;
21
22 import org.apache.commons.httpclient.HttpState;
23 import org.apache.log4j.Logger;
24
25 import com.eviware.soapui.SoapUI;
26 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
27 import com.eviware.soapui.model.support.PropertiesMap;
28 import com.eviware.soapui.model.testsuite.TestCase;
29 import com.eviware.soapui.model.testsuite.TestRunContext;
30 import com.eviware.soapui.model.testsuite.TestRunListener;
31 import com.eviware.soapui.model.testsuite.TestRunner;
32 import com.eviware.soapui.model.testsuite.TestStep;
33 import com.eviware.soapui.model.testsuite.TestStepResult;
34 import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
35 import com.eviware.soapui.support.UISupport;
36
37 /***
38 * WSDL TestCase Runner - runs all steps in a testcase and collects performance data
39 *
40 * @author Ole.Matzura
41 */
42
43 public class WsdlTestCaseRunner implements Runnable, TestRunner
44 {
45 private TestRunListener [] listeners;
46 private final WsdlTestCase testCase;
47 private Status status;
48 private Throwable error;
49 private WsdlTestRunContext runContext;
50 private List<TestStepResult> testStepResults = new ArrayList<TestStepResult>();
51 private int gotoStepIndex;
52 private long startTime;
53 private String reason;
54 private volatile Future<?> future;
55 private int id;
56 private final static ExecutorService threadPool = Executors.newCachedThreadPool();
57 private final static Logger log = Logger.getLogger( WsdlTestCaseRunner.class );
58
59 private static int idCounter = 0;
60
61 public WsdlTestCaseRunner( WsdlTestCase testCase, PropertiesMap properties )
62 {
63 this.testCase = testCase;
64 status = Status.INITIALIZED;
65 runContext = new WsdlTestRunContext( this, properties );
66 id = ++idCounter;
67 }
68
69 public WsdlTestRunContext getRunContext()
70 {
71 return runContext;
72 }
73
74 public void start( boolean async )
75 {
76 status = Status.RUNNING;
77 if( async )
78 future = threadPool.submit(this);
79 else
80 run();
81 }
82
83 public void cancel( String reason )
84 {
85 if( status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED ||
86 runContext == null ) return;
87 TestStep currentStep = runContext.getCurrentStep();
88 if( currentStep != null )
89 currentStep.cancel();
90 status = Status.CANCELED;
91 this.reason = reason;
92 }
93
94 public void fail( String reason )
95 {
96 if( status == Status.CANCELED || status == Status.FAILED ||
97 runContext == null ) return;
98 TestStep currentStep = runContext.getCurrentStep();
99 if( currentStep != null )
100 currentStep.cancel();
101 status = Status.FAILED;
102 this.reason = reason;
103 }
104
105 public Status getStatus()
106 {
107 return status;
108 }
109
110 public int getId()
111 {
112 return id;
113 }
114
115 public void run()
116 {
117 WsdlTestStep[] testSteps = testCase.getTestSteps();
118 int initCount = 0;
119
120 try
121 {
122 status = Status.RUNNING;
123 startTime = System.currentTimeMillis();
124
125 gotoStepIndex = -1;
126 testStepResults.clear();
127
128 listeners = testCase.getTestRunListeners();
129
130
131 if( testCase.getKeepSession() )
132 {
133 runContext.setProperty( TestRunContext.HTTP_STATE_PROPERTY, new HttpState() );
134 }
135
136 for (int i = 0; i < listeners.length; i++)
137 {
138 listeners[i].beforeRun( this, runContext );
139 if( status == Status.CANCELED || status == Status.FAILED )
140 return;
141 }
142
143 for( ; initCount < testCase.getTestStepCount(); initCount++ )
144 {
145 WsdlTestStep testStep = testCase.getTestStepAt( initCount );
146 if( testStep.isDisabled() )
147 continue;
148
149 try
150 {
151 testStep.prepare( this, runContext );
152 }
153 catch( Exception e )
154 {
155 throw new Exception( "Failed to prepare testStep [" + testStep.getName() + "]; " + e.toString() );
156 }
157 }
158
159 int currentStepIndex = runContext.getCurrentStepIndex();
160
161 for ( currentStepIndex = 0; status != Status.CANCELED && currentStepIndex < testSteps.length; currentStepIndex++)
162 {
163 TestStep currentStep = runContext.getCurrentStep();
164 if( !currentStep.isDisabled() )
165 {
166 for (int i = 0; i < listeners.length; i++) {
167 listeners[i].beforeStep(this, runContext );
168 if( status == Status.CANCELED || status == Status.FAILED )
169 return;
170 }
171
172 TestStepResult stepResult = currentStep.run( this, runContext );
173 testStepResults.add( stepResult );
174
175 for (int i = 0; i < listeners.length; i++)
176 {
177 listeners[i].afterStep( this, runContext, stepResult );
178 }
179
180
181 if( stepResult.getStatus() == TestStepStatus.OK && testCase.getDiscardOkResults() &&
182 !stepResult.isDiscarded() )
183 {
184 stepResult.discard();
185 }
186
187 if( stepResult.getStatus() == TestStepStatus.FAILED )
188 {
189 if( testCase.getFailOnError() )
190 {
191 error = stepResult.getError();
192 fail( "Cancelling due to failed test step" );
193 }
194 else
195 {
196 runContext.setProperty( TestRunner.Status.class.getName(), TestRunner.Status.FAILED );
197 }
198 }
199
200 if( status == Status.CANCELED || status == Status.FAILED )
201 return;
202
203 if( gotoStepIndex != -1 )
204 {
205 currentStepIndex = gotoStepIndex-1;
206 gotoStepIndex = -1;
207 }
208 }
209
210 runContext.setCurrentStep( currentStepIndex+1 );
211 }
212
213 if( runContext.getProperty( TestRunner.Status.class.getName() ) == TestRunner.Status.FAILED &&
214 testCase.getFailTestCaseOnErrors() )
215 {
216 fail( "Failing due to failed test step" );
217 }
218 }
219 catch (Throwable t)
220 {
221 log.error( "Exception during TestCase Execution", t );
222
223 if( t instanceof OutOfMemoryError &&
224 UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
225 {
226 System.exit( 0 );
227 }
228
229 status = Status.FAILED;
230 error = t;
231 reason = t.toString();
232 }
233 finally
234 {
235 if( status == Status.RUNNING )
236 {
237 status = Status.FINISHED;
238 }
239
240 for( int c = 0; c < initCount; c++ )
241 {
242 WsdlTestStep testStep = testCase.getTestStepAt( c );
243 if( !testStep.isDisabled() )
244 testStep.finish( this, runContext );
245 }
246
247 notifyAfterRun();
248 runContext.clear();
249 listeners = null;
250 }
251 }
252
253 private void notifyAfterRun()
254 {
255 if( listeners == null || listeners.length == 0 )
256 return;
257
258 for (int i = 0; i < listeners.length; i++)
259 {
260 listeners[i].afterRun( this, runContext );
261 }
262 }
263
264 public TestCase getTestCase() {
265 return testCase;
266 }
267
268 public synchronized Status waitUntilFinished()
269 {
270 if (future != null)
271 {
272 if (!future.isDone())
273 {
274 try
275 {
276 future.get();
277 }
278 catch (Exception e)
279 {
280 SoapUI.logError( e );
281 }
282 }
283 }
284 else
285 throw new RuntimeException("cannot wait on null future");
286
287
288 return getStatus();
289 }
290
291 public long getTimeTaken()
292 {
293 long sum = 0;
294 for( int c = 0; c < testStepResults.size(); c++ )
295 {
296 TestStepResult testStepResult = testStepResults.get( c );
297 if( testStepResult != null )
298 sum += testStepResult.getTimeTaken();
299 }
300
301 return sum;
302 }
303
304 public long getStartTime()
305 {
306 return startTime;
307 }
308
309 public Throwable getError()
310 {
311 return error;
312 }
313
314 public String getReason()
315 {
316 return reason == null ? error == null ? null : error.toString() : reason;
317 }
318
319 public List<TestStepResult> getResults()
320 {
321 return Collections.unmodifiableList( testStepResults );
322 }
323
324 public void gotoStep(int index)
325 {
326 gotoStepIndex = index;
327 }
328
329 public void gotoStepByName(String stepName)
330 {
331 TestStep testStep = getTestCase().getTestStepByName( stepName );
332 if( testStep != null )
333 gotoStep( getTestCase().getIndexOfTestStep( testStep));
334 }
335 }