/* * SoapUI, Copyright (C) 2004-2016 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 com.eviware.soapui.SoapUI; import com.eviware.soapui.model.testsuite.TestRunContext; import com.eviware.soapui.model.testsuite.TestRunnable; import com.eviware.soapui.model.testsuite.TestRunner; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.types.StringToObjectMap; import org.apache.log4j.Logger; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Future; /** * WSDL TestCase Runner - runs all steps in a testcase and collects performance * data * * @author Ole.Matzura */ public abstract class AbstractTestRunner<T extends TestRunnable, T2 extends TestRunContext> implements Runnable, TestRunner { private final T testRunnable; private Status status; private Throwable error; private T2 runContext; private long startTime; private String reason; private volatile Future<?> future; private int id; private final static Logger log = Logger.getLogger(AbstractTestRunner.class); private static int idCounter = 0; private Timer timeoutTimer; private TimeoutTimerTask timeoutTimerTask; private Thread thread; private long timeTaken; public AbstractTestRunner(T modelItem, StringToObjectMap properties) { this.testRunnable = modelItem; status = Status.INITIALIZED; id = ++idCounter; runContext = createContext(properties); } public abstract T2 createContext(StringToObjectMap properties); public T2 getRunContext() { return runContext; } public void start(boolean async) { status = Status.RUNNING; if (async) { future = SoapUI.getThreadPool().submit(this); } else { run(); } } public void cancel(String reason) { if (status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED || runContext == null) { return; } onCancel(reason); status = Status.CANCELED; this.reason = reason; } protected void onCancel(String reason2) { } public void fail(String reason) { if (status == Status.CANCELED || status == Status.FAILED || runContext == null) { return; } onFail(reason); status = Status.FAILED; this.reason = reason; } protected void onFail(String reason) { } public Status getStatus() { return status; } public int getId() { return id; } public Thread getThread() { return thread; } public void run() { if (future != null) { thread = Thread.currentThread(); if (System.getProperty("soapui.enablenamedthreads") != null) { thread.setName("TestRunner Thread for " + testRunnable.getName()); } } try { status = Status.RUNNING; setStartTime(); internalRun(runContext); } catch (Throwable t) { log.error("Exception during Test Execution", t); if (t instanceof OutOfMemoryError && UISupport.confirm("Exit now without saving?", "Out of Memory Error")) { System.exit(0); } status = Status.FAILED; error = t; reason = t.toString(); } finally { setTimeTaken(); if (timeoutTimer != null) { timeoutTimer.cancel(); } if (status == Status.RUNNING) { status = Status.FINISHED; } internalFinally(runContext); } } protected void setStartTime() { startTime = System.currentTimeMillis(); } public boolean isRunning() { return getStatus() == Status.RUNNING; } public boolean isCanceled() { return getStatus() == Status.CANCELED; } public boolean isFailed() { return getStatus() == Status.FAILED; } protected void setStatus(Status status) { this.status = status; } protected void setError(Throwable error) { this.error = error; } protected abstract void internalRun(T2 runContext2) throws Exception; protected abstract void internalFinally(T2 runContext2); protected void startTimeoutTimer(long timeout) { timeoutTimer = new Timer(); timeoutTimerTask = new TimeoutTimerTask(); timeoutTimer.schedule(timeoutTimerTask, timeout); } public T getTestRunnable() { return testRunnable; } public synchronized Status waitUntilFinished() { if (future != null) { if (!future.isDone()) { try { future.get(); } catch (Exception e) { SoapUI.logError(e); } } } else { throw new RuntimeException("cannot wait on null future"); } return getStatus(); } protected void setTimeTaken() { timeTaken = System.currentTimeMillis() - startTime; } public long getTimeTaken() { return timeTaken; } public long getStartTime() { return startTime; } public Throwable getError() { return error; } public String getReason() { return reason == null ? error == null ? null : error.toString() : reason; } private final class TimeoutTimerTask extends TimerTask { @Override public void run() { fail("TestCase timed out"); } } }