/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.support;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.collections.list.TreeList;
import org.apache.http.protocol.BasicHttpContext;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestRunListener;
import com.eviware.soapui.model.testsuite.TestRunnable;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestStepResult;
import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
import com.eviware.soapui.support.types.StringToObjectMap;
/**
* Abstract runner class - runs all steps in a TestCase or a SecurityTest and
* collects performance data
*
* @author dragica.soldo
*/
public abstract class AbstractTestCaseRunner<T extends TestRunnable, T2 extends WsdlTestRunContext> extends
AbstractTestRunner<T, T2> implements TestCaseRunner {
private TestRunListener[] testRunListeners = new TestRunListener[0];
@SuppressWarnings("unchecked")
private List<TestStepResult> testStepResults = Collections.synchronizedList(new TreeList());
private int gotoStepIndex;
private int resultCount;
private int initCount;
private int startStep = 0;
public AbstractTestCaseRunner(T modelItem, StringToObjectMap properties) {
super(modelItem, properties);
}
public int getGotoStepIndex() {
return gotoStepIndex;
}
public int getStartStep() {
return startStep;
}
public void setStartStep(int startStep) {
this.startStep = startStep;
}
public void onCancel(String reason) {
TestStep currentStep = getRunContext().getCurrentStep();
if (currentStep != null) {
currentStep.cancel();
}
}
public void onFail(String reason) {
TestStep currentStep = getRunContext().getCurrentStep();
if (currentStep != null) {
currentStep.cancel();
}
}
public void internalRun(T2 runContext) throws Exception {
WsdlTestCase testCase = getTestCase();
gotoStepIndex = -1;
testStepResults.clear();
// create state for testcase if specified
if (testCase.getKeepSession()) {
if (!(runContext.getProperty(SubmitContext.HTTP_STATE_PROPERTY) instanceof BasicHttpContext)) {
runContext.setProperty(SubmitContext.HTTP_STATE_PROPERTY, HttpClientSupport.createEmptyContext());
}
} else {
runContext.setProperty(SubmitContext.HTTP_STATE_PROPERTY, null);
}
fillInTestRunnableListeners();
runSetupScripts(runContext);
if (!isRunning()) {
return;
}
if (testCase.getTimeout() > 0) {
startTimeoutTimer(testCase.getTimeout());
}
notifyBeforeRun();
if (!isRunning()) {
return;
}
initCount = getStartStep();
setStartTime();
for (; initCount < testCase.getTestStepCount() && isRunning(); initCount++) {
WsdlTestStep testStep = testCase.getTestStepAt(initCount);
if (testStep.isDisabled()) {
continue;
}
try {
testStep.prepare(this, runContext);
} catch (Exception e) {
setStatus(Status.FAILED);
SoapUI.logError(e);
throw new Exception("Failed to prepare testStep [" + testStep.getName() + "]; " + e.toString());
}
}
int currentStepIndex = startStep;
runContext.setCurrentStep(currentStepIndex);
for (; isRunning() && currentStepIndex < testCase.getTestStepCount(); currentStepIndex++) {
if ((currentStepIndex = runCurrentTestStep(runContext, currentStepIndex)) == -2) {
return;
}
}
failTestRunnableOnErrors(runContext);
preserveContext(getRunContext());
}
protected abstract void failTestRunnableOnErrors(T2 runContext);
/**
* Runs current testStep , returns index of the next step to be run and -2 in
* case execution should break if canceled
*
* @param runContext
* @param currentStepIndex
* @return
* @throws Exception
*/
protected abstract int runCurrentTestStep(T2 runContext, int currentStepIndex) throws Exception;
protected void internalFinally(T2 runContext) {
WsdlTestCase testCase = getTestCase();
for (int c = 0; c < initCount && c < testCase.getTestStepCount(); c++) {
WsdlTestStep testStep = testCase.getTestStepAt(c);
if (!testStep.isDisabled()) {
testStep.finish(this, runContext);
}
}
try {
runTearDownScripts(runContext);
} catch (Exception e) {
SoapUI.logError(e);
}
notifyAfterRun();
clear(runContext);
}
protected void runSetupScripts(T2 runContext) throws Exception {
getTestCase().runSetupScript(runContext, this);
}
protected void runTearDownScripts(T2 runContext) throws Exception {
getTestCase().runTearDownScript(runContext, this);
}
protected void clear(T2 runContext) {
runContext.clear();
testRunListeners = null;
}
protected void fillInTestRunnableListeners() {
testRunListeners = getTestCase().getTestRunListeners();
}
public TestStepResult runTestStepByName(String name) {
return runTestStep(getTestCase().getTestStepByName(name), true, true);
}
public TestStepResult runTestStep(TestStep testStep) {
return runTestStep(testStep, true, true);
}
public TestStepResult runTestStep(TestStep testStep, boolean discard, boolean process) {
if (!runBeforeSteps(testStep)) {
return null;
}
TestStepResult stepResult = testStep.run(this, getRunContext());
testStepResults.add(stepResult);
resultCount++;
// TODO check all replacements of getTestRunnable with getTestCase in the
// method
// enforceMaxResults( getTestRunnable().getMaxResults() );
enforceMaxResults(getTestCase().getMaxResults());
for (int i = 0; i < testRunListeners.length; i++) {
if (Arrays.asList(getTestCase().getTestRunListeners()).contains(testRunListeners[i])) {
testRunListeners[i].afterStep(this, getRunContext(), stepResult);
}
}
// discard?
// if( discard && stepResult.getStatus() == TestStepStatus.OK &&
// getTestRunnable().getDiscardOkResults()
if (discard && stepResult.getStatus() == TestStepStatus.OK && getTestCase().getDiscardOkResults()
&& !stepResult.isDiscarded()) {
stepResult.discard();
}
if (process && stepResult.getStatus() == TestStepStatus.FAILED) {
// if( getTestRunnable().getFailOnError() )
if (getTestCase().getFailOnError()) {
setError(stepResult.getError());
fail("Cancelling due to failed test step");
} else {
getRunContext().setProperty(TestCaseRunner.Status.class.getName(), TestCaseRunner.Status.FAILED);
}
}
// preserveContext( getRunContext() );
return stepResult;
}
protected boolean runBeforeSteps(TestStep testStep) {
for (TestRunListener testRunListener : testRunListeners) {
if (Arrays.asList(getTestCase().getTestRunListeners()).contains(testRunListener)) {
testRunListener.beforeStep(this, getRunContext(), testStep);
}
if (!isRunning()) {
return false;
}
}
return true;
}
/**
* create backup of context properties in WsdlTestCase. This is used for RUN
* FROM HERE action.
*
* @param runContext
*/
private void preserveContext(T2 runContext) {
getTestCase().setRunFromHereContext(runContext.getProperties());
}
protected void notifyAfterRun() {
if (testRunListeners == null || testRunListeners.length == 0) {
return;
}
for (int i = 0; i < testRunListeners.length; i++) {
try {
if (Arrays.asList(getTestCase().getTestRunListeners()).contains(testRunListeners[i])) {
testRunListeners[i].afterRun(this, getRunContext());
}
} catch (Throwable t) {
SoapUI.logError(t);
}
}
}
protected void notifyBeforeRun() {
if (testRunListeners == null || testRunListeners.length == 0) {
return;
}
for (int i = 0; i < testRunListeners.length; i++) {
try {
if (Arrays.asList(getTestCase().getTestRunListeners()).contains(testRunListeners[i])) {
testRunListeners[i].beforeRun(this, getRunContext());
}
} catch (Throwable t) {
SoapUI.logError(t);
}
}
}
public abstract WsdlTestCase getTestCase();
public long getTimeTaken() {
long sum = 0;
for (int c = 0; c < testStepResults.size(); c++) {
TestStepResult testStepResult = testStepResults.get(c);
if (testStepResult != null) {
sum += testStepResult.getTimeTaken();
}
}
return sum;
}
public List<TestStepResult> getResults() {
return testStepResults;
}
public void setResultCount(int resultCount) {
this.resultCount = resultCount;
}
public int getResultCount() {
return resultCount;
}
public void gotoStep(int index) {
gotoStepIndex = index;
}
public void enforceMaxResults(long maxResults) {
if (maxResults < 1) {
return;
}
while (testStepResults.size() > maxResults) {
testStepResults.remove(0);
}
}
public void gotoStepByName(String stepName) {
TestStep testStep = getTestCase().getTestStepByName(stepName);
if (testStep != null) {
gotoStep(getTestCase().getIndexOfTestStep(testStep));
}
}
}