1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.testcase;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
17 import com.eviware.soapui.model.iface.SubmitContext;
18 import com.eviware.soapui.model.testsuite.*;
19 import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
20 import com.eviware.soapui.support.UISupport;
21 import com.eviware.soapui.support.types.StringToObjectMap;
22 import org.apache.commons.httpclient.HttpState;
23 import org.apache.log4j.Logger;
24
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Timer;
28 import java.util.TimerTask;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.Future;
32
33 /***
34 * WSDL TestCase Runner - runs all steps in a testcase and collects performance data
35 *
36 * @author Ole.Matzura
37 */
38
39 public class WsdlTestCaseRunner implements Runnable, TestRunner
40 {
41 private TestRunListener[] listeners;
42 private final WsdlTestCase testCase;
43 private Status status;
44 private Throwable error;
45 private WsdlTestRunContext runContext;
46 private List<TestStepResult> testStepResults = new LinkedList<TestStepResult>();
47 private int gotoStepIndex;
48 private long startTime;
49 private String reason;
50 private volatile Future<?> future;
51 private int id;
52 private int resultCount;
53 private final static ExecutorService threadPool = Executors.newCachedThreadPool();
54
55 private final static Logger log = Logger.getLogger(WsdlTestCaseRunner.class);
56
57 private static int idCounter = 0;
58 private Timer timeoutTimer;
59 private TimeoutTimerTask timeoutTimerTask;
60
61 public WsdlTestCaseRunner(WsdlTestCase testCase, StringToObjectMap 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 int initCount = 0;
118
119 if( future != null )
120 {
121 Thread.currentThread().setName( "TestCaseRunner Thread for " + testCase.getName() );
122 }
123
124 try
125 {
126 gotoStepIndex = -1;
127 testStepResults.clear();
128
129
130 if (testCase.getKeepSession())
131 {
132 runContext.setProperty(SubmitContext.HTTP_STATE_PROPERTY, new HttpState());
133 }
134
135 testCase.runSetupScript(runContext, this);
136
137 status = Status.RUNNING;
138 startTime = System.currentTimeMillis();
139
140 if (testCase.getTimeout() > 0)
141 {
142 timeoutTimer = new Timer();
143 timeoutTimerTask = new TimeoutTimerTask();
144 timeoutTimer.schedule(timeoutTimerTask, testCase.getTimeout());
145 }
146
147 listeners = testCase.getTestRunListeners();
148 notifyBeforeRun();
149
150 for (; initCount < testCase.getTestStepCount() && status == Status.RUNNING; initCount++)
151 {
152 WsdlTestStep testStep = testCase.getTestStepAt(initCount);
153 if (testStep.isDisabled())
154 continue;
155
156 try
157 {
158 testStep.prepare(this, runContext);
159 }
160 catch (Exception e)
161 {
162 status = Status.FAILED;
163 SoapUI.logError(e);
164 throw new Exception("Failed to prepare testStep [" + testStep.getName() + "]; " + e.toString());
165 }
166 }
167
168 int currentStepIndex = 0;
169
170 for (; status == Status.RUNNING && currentStepIndex < testCase.getTestStepCount(); currentStepIndex++)
171 {
172 TestStep currentStep = runContext.getCurrentStep();
173 if (!currentStep.isDisabled())
174 {
175 TestStepResult stepResult = runTestStep(currentStep, true, true);
176 if (stepResult == null)
177 return;
178
179 if (status == Status.CANCELED || status == Status.FAILED)
180 return;
181
182 if (gotoStepIndex != -1)
183 {
184 currentStepIndex = gotoStepIndex - 1;
185 gotoStepIndex = -1;
186 }
187 }
188
189 runContext.setCurrentStep(currentStepIndex + 1);
190 }
191
192 if (runContext.getProperty(TestRunner.Status.class.getName()) == TestRunner.Status.FAILED &&
193 testCase.getFailTestCaseOnErrors())
194 {
195 fail("Failing due to failed test step");
196 }
197 }
198 catch (Throwable t)
199 {
200 log.error("Exception during TestCase Execution", t);
201
202 if (t instanceof OutOfMemoryError &&
203 UISupport.confirm("Exit now without saving?", "Out of Memory Error"))
204 {
205 System.exit(0);
206 }
207
208 status = Status.FAILED;
209 error = t;
210 reason = t.toString();
211 }
212 finally
213 {
214 if (timeoutTimer != null)
215 {
216 timeoutTimer.cancel();
217 }
218
219 if (status == Status.RUNNING)
220 {
221 status = Status.FINISHED;
222 }
223
224 for (int c = 0; c < initCount; c++)
225 {
226 WsdlTestStep testStep = testCase.getTestStepAt(c);
227 if (!testStep.isDisabled())
228 testStep.finish(this, runContext);
229 }
230
231 notifyAfterRun();
232
233 try
234 {
235 testCase.runTearDownScript(runContext, this);
236 }
237 catch (Exception e)
238 {
239 SoapUI.logError(e);
240 }
241
242 runContext.clear();
243 listeners = null;
244 }
245 }
246
247 public TestStepResult runTestStepByName( String name )
248 {
249 return runTestStep( getTestCase().getTestStepByName( name ), true, true );
250 }
251
252 public TestStepResult runTestStep(TestStep testStep )
253 {
254 return runTestStep( testStep, true, true );
255 }
256
257 public TestStepResult runTestStep(TestStep testStep, boolean discard, boolean process)
258 {
259 for (int i = 0; i < listeners.length; i++)
260 {
261 listeners[i].beforeStep(this, runContext);
262 if (status == Status.CANCELED || status == Status.FAILED)
263 return null;
264 }
265
266 TestStepResult stepResult = testStep.run(this, runContext);
267 testStepResults.add(stepResult);
268 resultCount++;
269 enforceMaxResults( testCase.getMaxResults());
270
271 for (int i = 0; i < listeners.length; i++)
272 {
273 listeners[i].afterStep(this, runContext, stepResult);
274 }
275
276
277 if (discard && stepResult.getStatus() == TestStepStatus.OK && testCase.getDiscardOkResults() &&
278 !stepResult.isDiscarded())
279 {
280 stepResult.discard();
281 }
282
283 if (process && stepResult.getStatus() == TestStepStatus.FAILED)
284 {
285 if (testCase.getFailOnError())
286 {
287 error = stepResult.getError();
288 fail("Cancelling due to failed test step");
289 }
290 else
291 {
292 runContext.setProperty(TestRunner.Status.class.getName(), TestRunner.Status.FAILED);
293 }
294 }
295
296 return stepResult;
297 }
298
299 private void notifyAfterRun()
300 {
301 if (listeners == null || listeners.length == 0)
302 return;
303
304 for (int i = 0; i < listeners.length; i++)
305 {
306 listeners[i].afterRun(this, runContext);
307 }
308 }
309
310 private void notifyBeforeRun()
311 {
312 if (listeners == null || listeners.length == 0)
313 return;
314
315 for (int i = 0; i < listeners.length; i++)
316 {
317 listeners[i].beforeRun(this, runContext);
318 }
319 }
320
321 public TestCase getTestCase()
322 {
323 return testCase;
324 }
325
326 public synchronized Status waitUntilFinished()
327 {
328 if (future != null)
329 {
330 if (!future.isDone())
331 {
332 try
333 {
334 future.get();
335 }
336 catch (Exception e)
337 {
338 SoapUI.logError(e);
339 }
340 }
341 }
342 else
343 throw new RuntimeException("cannot wait on null future");
344
345
346 return getStatus();
347 }
348
349 public long getTimeTaken()
350 {
351 long sum = 0;
352 for (int c = 0; c < testStepResults.size(); c++)
353 {
354 TestStepResult testStepResult = testStepResults.get(c);
355 if (testStepResult != null)
356 sum += testStepResult.getTimeTaken();
357 }
358
359 return sum;
360 }
361
362 public long getStartTime()
363 {
364 return startTime;
365 }
366
367 public Throwable getError()
368 {
369 return error;
370 }
371
372 public String getReason()
373 {
374 return reason == null ? error == null ? null : error.toString() : reason;
375 }
376
377 public List<TestStepResult> getResults()
378 {
379 return testStepResults;
380 }
381
382 public int getResultCount()
383 {
384 return resultCount;
385 }
386
387 public void gotoStep(int index)
388 {
389 gotoStepIndex = index;
390 }
391
392 public void enforceMaxResults( long maxResults )
393 {
394 if (maxResults < 1)
395 return;
396
397 synchronized (this)
398 {
399 while (testStepResults.size() > maxResults)
400 {
401 testStepResults.remove(0);
402 }
403 }
404 }
405
406 public void gotoStepByName(String stepName)
407 {
408 TestStep testStep = getTestCase().getTestStepByName(stepName);
409 if (testStep != null)
410 gotoStep(getTestCase().getIndexOfTestStep(testStep));
411 }
412
413 private final class TimeoutTimerTask extends TimerTask
414 {
415 @Override
416 public void run()
417 {
418 fail("TestCase timed out");
419 }
420 }
421 }