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 private final static Logger log = Logger.getLogger(WsdlTestCaseRunner.class);
55
56 private static int idCounter = 0;
57 private Timer timeoutTimer;
58 private TimeoutTimerTask timeoutTimerTask;
59
60 public WsdlTestCaseRunner(WsdlTestCase testCase, StringToObjectMap properties)
61 {
62 this.testCase = testCase;
63 status = Status.INITIALIZED;
64 runContext = new WsdlTestRunContext(this, properties);
65 id = ++idCounter;
66 }
67
68 public WsdlTestRunContext getRunContext()
69 {
70 return runContext;
71 }
72
73 public void start(boolean async)
74 {
75 status = Status.RUNNING;
76 if (async)
77 future = threadPool.submit(this);
78 else
79 run();
80 }
81
82 public void cancel(String reason)
83 {
84 if (status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED ||
85 runContext == null) return;
86 TestStep currentStep = runContext.getCurrentStep();
87 if (currentStep != null)
88 currentStep.cancel();
89 status = Status.CANCELED;
90 this.reason = reason;
91 }
92
93 public void fail(String reason)
94 {
95 if (status == Status.CANCELED || status == Status.FAILED ||
96 runContext == null) return;
97 TestStep currentStep = runContext.getCurrentStep();
98 if (currentStep != null)
99 currentStep.cancel();
100 status = Status.FAILED;
101 this.reason = reason;
102 }
103
104 public Status getStatus()
105 {
106 return status;
107 }
108
109 public int getId()
110 {
111 return id;
112 }
113
114 public void run()
115 {
116 int initCount = 0;
117
118 try
119 {
120 gotoStepIndex = -1;
121 testStepResults.clear();
122
123 listeners = testCase.getTestRunListeners();
124
125
126 if (testCase.getKeepSession())
127 {
128 runContext.setProperty(SubmitContext.HTTP_STATE_PROPERTY, new HttpState());
129 }
130
131 testCase.runSetupScript(runContext, this);
132
133 status = Status.RUNNING;
134 startTime = System.currentTimeMillis();
135
136 if (testCase.getTimeout() > 0)
137 {
138 timeoutTimer = new Timer();
139 timeoutTimerTask = new TimeoutTimerTask();
140 timeoutTimer.schedule(timeoutTimerTask, testCase.getTimeout());
141 }
142
143 for (int i = 0; i < listeners.length; i++)
144 {
145 listeners[i].beforeRun(this, runContext);
146 if (status != Status.RUNNING)
147 return;
148 }
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 = runContext.getCurrentStepIndex();
169
170 for (currentStepIndex = 0; 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 runTestStep(TestStep testStep, boolean discard, boolean process)
248 {
249 for (int i = 0; i < listeners.length; i++)
250 {
251 listeners[i].beforeStep(this, runContext);
252 if (status == Status.CANCELED || status == Status.FAILED)
253 return null;
254 }
255
256 TestStepResult stepResult = testStep.run(this, runContext);
257 testStepResults.add(stepResult);
258 resultCount++;
259 enforceMaxSize();
260
261 for (int i = 0; i < listeners.length; i++)
262 {
263 listeners[i].afterStep(this, runContext, stepResult);
264 }
265
266
267 if (discard && stepResult.getStatus() == TestStepStatus.OK && testCase.getDiscardOkResults() &&
268 !stepResult.isDiscarded())
269 {
270 stepResult.discard();
271 }
272
273 if (process && stepResult.getStatus() == TestStepStatus.FAILED)
274 {
275 if (testCase.getFailOnError())
276 {
277 error = stepResult.getError();
278 fail("Cancelling due to failed test step");
279 }
280 else
281 {
282 runContext.setProperty(TestRunner.Status.class.getName(), TestRunner.Status.FAILED);
283 }
284 }
285
286 return stepResult;
287 }
288
289 private void notifyAfterRun()
290 {
291 if (listeners == null || listeners.length == 0)
292 return;
293
294 for (int i = 0; i < listeners.length; i++)
295 {
296 listeners[i].afterRun(this, runContext);
297 }
298 }
299
300 public TestCase getTestCase()
301 {
302 return testCase;
303 }
304
305 public synchronized Status waitUntilFinished()
306 {
307 if (future != null)
308 {
309 if (!future.isDone())
310 {
311 try
312 {
313 future.get();
314 }
315 catch (Exception e)
316 {
317 SoapUI.logError(e);
318 }
319 }
320 }
321 else
322 throw new RuntimeException("cannot wait on null future");
323
324
325 return getStatus();
326 }
327
328 public long getTimeTaken()
329 {
330 long sum = 0;
331 for (int c = 0; c < testStepResults.size(); c++)
332 {
333 TestStepResult testStepResult = testStepResults.get(c);
334 if (testStepResult != null)
335 sum += testStepResult.getTimeTaken();
336 }
337
338 return sum;
339 }
340
341 public long getStartTime()
342 {
343 return startTime;
344 }
345
346 public Throwable getError()
347 {
348 return error;
349 }
350
351 public String getReason()
352 {
353 return reason == null ? error == null ? null : error.toString() : reason;
354 }
355
356 public List<TestStepResult> getResults()
357 {
358 return testStepResults;
359 }
360
361 public int getResultCount()
362 {
363 return resultCount;
364 }
365
366 public void gotoStep(int index)
367 {
368 gotoStepIndex = index;
369 }
370
371 private void enforceMaxSize()
372 {
373 int maxResults = testCase.getMaxResults();
374 if (maxResults < 1)
375 return;
376
377 synchronized (this)
378 {
379 while (testStepResults.size() > maxResults)
380 {
381 testStepResults.remove(0);
382 }
383 }
384 }
385
386 public void gotoStepByName(String stepName)
387 {
388 TestStep testStep = getTestCase().getTestStepByName(stepName);
389 if (testStep != null)
390 gotoStep(getTestCase().getIndexOfTestStep(testStep));
391 }
392
393 private final class TimeoutTimerTask extends TimerTask
394 {
395 @Override
396 public void run()
397 {
398 fail("TestCase timed out");
399 }
400 }
401 }