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