001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.testcase;
014:
015: import java.util.ArrayList;
016: import java.util.Collections;
017: import java.util.List;
018: import java.util.concurrent.ExecutorService;
019: import java.util.concurrent.Executors;
020: import java.util.concurrent.Future;
021:
022: import org.apache.commons.httpclient.HttpState;
023: import org.apache.log4j.Logger;
024:
025: import com.eviware.soapui.SoapUI;
026: import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
027: import com.eviware.soapui.model.support.PropertiesMap;
028: import com.eviware.soapui.model.testsuite.TestCase;
029: import com.eviware.soapui.model.testsuite.TestRunContext;
030: import com.eviware.soapui.model.testsuite.TestRunListener;
031: import com.eviware.soapui.model.testsuite.TestRunner;
032: import com.eviware.soapui.model.testsuite.TestStep;
033: import com.eviware.soapui.model.testsuite.TestStepResult;
034: import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
035: import com.eviware.soapui.support.UISupport;
036:
037: /**
038: * WSDL TestCase Runner - runs all steps in a testcase and collects performance data
039: *
040: * @author Ole.Matzura
041: */
042:
043: public class WsdlTestCaseRunner implements Runnable, TestRunner {
044: private TestRunListener[] listeners;
045: private final WsdlTestCase testCase;
046: private Status status;
047: private Throwable error;
048: private WsdlTestRunContext runContext;
049: private List<TestStepResult> testStepResults = new ArrayList<TestStepResult>();
050: private int gotoStepIndex;
051: private long startTime;
052: private String reason;
053: private volatile Future<?> future;
054: private int id;
055: private final static ExecutorService threadPool = Executors
056: .newCachedThreadPool();
057: private final static Logger log = Logger
058: .getLogger(WsdlTestCaseRunner.class);
059:
060: private static int idCounter = 0;
061:
062: public WsdlTestCaseRunner(WsdlTestCase testCase,
063: PropertiesMap properties) {
064: this .testCase = testCase;
065: status = Status.INITIALIZED;
066: runContext = new WsdlTestRunContext(this , properties);
067: id = ++idCounter;
068: }
069:
070: public WsdlTestRunContext getRunContext() {
071: return runContext;
072: }
073:
074: public void start(boolean async) {
075: status = Status.RUNNING;
076: if (async)
077: future = threadPool.submit(this );
078: else
079: run();
080: }
081:
082: public void cancel(String reason) {
083: if (status == Status.CANCELED || status == Status.FINISHED
084: || status == Status.FAILED || runContext == null)
085: return;
086: TestStep currentStep = runContext.getCurrentStep();
087: if (currentStep != null)
088: currentStep.cancel();
089: status = Status.CANCELED;
090: this .reason = reason;
091: }
092:
093: public void fail(String reason) {
094: if (status == Status.CANCELED || status == Status.FAILED
095: || runContext == null)
096: return;
097: TestStep currentStep = runContext.getCurrentStep();
098: if (currentStep != null)
099: currentStep.cancel();
100: status = Status.FAILED;
101: this .reason = reason;
102: }
103:
104: public Status getStatus() {
105: return status;
106: }
107:
108: public int getId() {
109: return id;
110: }
111:
112: public void run() {
113: WsdlTestStep[] testSteps = testCase.getTestSteps();
114: int initCount = 0;
115:
116: try {
117: status = Status.RUNNING;
118: startTime = System.currentTimeMillis();
119:
120: gotoStepIndex = -1;
121: testStepResults.clear();
122:
123: listeners = testCase.getTestRunListeners();
124:
125: // create state for testcase if specified
126: if (testCase.getKeepSession()) {
127: runContext.setProperty(
128: TestRunContext.HTTP_STATE_PROPERTY,
129: new HttpState());
130: }
131:
132: for (int i = 0; i < listeners.length; i++) {
133: listeners[i].beforeRun(this , runContext);
134: if (status == Status.CANCELED
135: || status == Status.FAILED)
136: return;
137: }
138:
139: for (; initCount < testCase.getTestStepCount(); initCount++) {
140: WsdlTestStep testStep = testCase
141: .getTestStepAt(initCount);
142: if (testStep.isDisabled())
143: continue;
144:
145: try {
146: testStep.prepare(this , runContext);
147: } catch (Exception e) {
148: throw new Exception("Failed to prepare testStep ["
149: + testStep.getName() + "]; " + e.toString());
150: }
151: }
152:
153: int currentStepIndex = runContext.getCurrentStepIndex();
154:
155: for (currentStepIndex = 0; status != Status.CANCELED
156: && currentStepIndex < testSteps.length; currentStepIndex++) {
157: TestStep currentStep = runContext.getCurrentStep();
158: if (!currentStep.isDisabled()) {
159: for (int i = 0; i < listeners.length; i++) {
160: listeners[i].beforeStep(this , runContext);
161: if (status == Status.CANCELED
162: || status == Status.FAILED)
163: return;
164: }
165:
166: TestStepResult stepResult = currentStep.run(this ,
167: runContext);
168: testStepResults.add(stepResult);
169:
170: for (int i = 0; i < listeners.length; i++) {
171: listeners[i].afterStep(this , runContext,
172: stepResult);
173: }
174:
175: // discard?
176: if (stepResult.getStatus() == TestStepStatus.OK
177: && testCase.getDiscardOkResults()
178: && !stepResult.isDiscarded()) {
179: stepResult.discard();
180: }
181:
182: if (stepResult.getStatus() == TestStepStatus.FAILED) {
183: if (testCase.getFailOnError()) {
184: error = stepResult.getError();
185: fail("Cancelling due to failed test step");
186: } else {
187: runContext.setProperty(
188: TestRunner.Status.class.getName(),
189: TestRunner.Status.FAILED);
190: }
191: }
192:
193: if (status == Status.CANCELED
194: || status == Status.FAILED)
195: return;
196:
197: if (gotoStepIndex != -1) {
198: currentStepIndex = gotoStepIndex - 1;
199: gotoStepIndex = -1;
200: }
201: }
202:
203: runContext.setCurrentStep(currentStepIndex + 1);
204: }
205:
206: if (runContext.getProperty(TestRunner.Status.class
207: .getName()) == TestRunner.Status.FAILED
208: && testCase.getFailTestCaseOnErrors()) {
209: fail("Failing due to failed test step");
210: }
211: } catch (Throwable t) {
212: log.error("Exception during TestCase Execution", t);
213:
214: if (t instanceof OutOfMemoryError
215: && UISupport.confirm("Exit now without saving?",
216: "Out of Memory Error")) {
217: System.exit(0);
218: }
219:
220: status = Status.FAILED;
221: error = t;
222: reason = t.toString();
223: } finally {
224: if (status == Status.RUNNING) {
225: status = Status.FINISHED;
226: }
227:
228: for (int c = 0; c < initCount; c++) {
229: WsdlTestStep testStep = testCase.getTestStepAt(c);
230: if (!testStep.isDisabled())
231: testStep.finish(this , runContext);
232: }
233:
234: notifyAfterRun();
235: runContext.clear();
236: listeners = null;
237: }
238: }
239:
240: private void notifyAfterRun() {
241: if (listeners == null || listeners.length == 0)
242: return;
243:
244: for (int i = 0; i < listeners.length; i++) {
245: listeners[i].afterRun(this , runContext);
246: }
247: }
248:
249: public TestCase getTestCase() {
250: return testCase;
251: }
252:
253: public synchronized Status waitUntilFinished() {
254: if (future != null) {
255: if (!future.isDone()) {
256: try {
257: future.get();
258: } catch (Exception e) {
259: SoapUI.logError(e);
260: }
261: }
262: } else
263: throw new RuntimeException("cannot wait on null future");
264:
265: return getStatus();
266: }
267:
268: public long getTimeTaken() {
269: long sum = 0;
270: for (int c = 0; c < testStepResults.size(); c++) {
271: TestStepResult testStepResult = testStepResults.get(c);
272: if (testStepResult != null)
273: sum += testStepResult.getTimeTaken();
274: }
275:
276: return sum;
277: }
278:
279: public long getStartTime() {
280: return startTime;
281: }
282:
283: public Throwable getError() {
284: return error;
285: }
286:
287: public String getReason() {
288: return reason == null ? error == null ? null : error.toString()
289: : reason;
290: }
291:
292: public List<TestStepResult> getResults() {
293: return Collections.unmodifiableList(testStepResults);
294: }
295:
296: public void gotoStep(int index) {
297: gotoStepIndex = index;
298: }
299:
300: public void gotoStepByName(String stepName) {
301: TestStep testStep = getTestCase().getTestStepByName(stepName);
302: if (testStep != null)
303: gotoStep(getTestCase().getIndexOfTestStep(testStep));
304: }
305: }
|