1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.support;
14
15 import java.util.Timer;
16 import java.util.TimerTask;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.Future;
20
21 import org.apache.log4j.Logger;
22
23 import com.eviware.soapui.SoapUI;
24 import com.eviware.soapui.model.testsuite.TestRunContext;
25 import com.eviware.soapui.model.testsuite.TestRunnable;
26 import com.eviware.soapui.model.testsuite.TestRunner;
27 import com.eviware.soapui.support.UISupport;
28 import com.eviware.soapui.support.types.StringToObjectMap;
29
30 /***
31 * WSDL TestCase Runner - runs all steps in a testcase and collects performance
32 * data
33 *
34 * @author Ole.Matzura
35 */
36
37 public abstract class AbstractTestRunner<T extends TestRunnable, T2 extends TestRunContext> implements Runnable,
38 TestRunner
39 {
40 private final T testRunnable;
41 private Status status;
42 private Throwable error;
43 private T2 runContext;
44 private long startTime;
45 private String reason;
46 private volatile Future<?> future;
47 private int id;
48 private final static ExecutorService threadPool = Executors.newCachedThreadPool();
49
50 private final static Logger log = Logger.getLogger( AbstractTestRunner.class );
51
52 private static int idCounter = 0;
53
54 private Timer timeoutTimer;
55 private TimeoutTimerTask timeoutTimerTask;
56 private Thread thread;
57 private long timeTaken;
58
59 public AbstractTestRunner( T modelItem, StringToObjectMap properties )
60 {
61 this.testRunnable = modelItem;
62 status = Status.INITIALIZED;
63 id = ++idCounter;
64
65 runContext = createContext( properties );
66 }
67
68 public abstract T2 createContext( StringToObjectMap properties );
69
70 public T2 getRunContext()
71 {
72 return runContext;
73 }
74
75 public void start( boolean async )
76 {
77 status = Status.RUNNING;
78 if( async )
79 future = threadPool.submit( this );
80 else
81 run();
82 }
83
84 public void cancel( String reason )
85 {
86 if( status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED || runContext == null )
87 return;
88 onCancel( reason );
89 status = Status.CANCELED;
90 this.reason = reason;
91 }
92
93 protected void onCancel( String reason2 )
94 {
95 }
96
97 public void fail( String reason )
98 {
99 if( status == Status.CANCELED || status == Status.FAILED || runContext == null )
100 return;
101 onFail( reason );
102 status = Status.FAILED;
103 this.reason = reason;
104 }
105
106 protected void onFail( String reason )
107 {
108 }
109
110 public Status getStatus()
111 {
112 return status;
113 }
114
115 public int getId()
116 {
117 return id;
118 }
119
120 public Thread getThread()
121 {
122 return thread;
123 }
124
125 public void run()
126 {
127 if( future != null )
128 {
129 thread = Thread.currentThread();
130 thread.setName( "TestRunner Thread for " + testRunnable.getName() );
131 }
132
133 try
134 {
135 status = Status.RUNNING;
136 setStartTime();
137
138 internalRun( runContext );
139 }
140 catch( Throwable t )
141 {
142 log.error( "Exception during Test Execution", t );
143
144 if( t instanceof OutOfMemoryError && UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
145 {
146 System.exit( 0 );
147 }
148
149 status = Status.FAILED;
150 error = t;
151 reason = t.toString();
152 }
153 finally
154 {
155 setTimeTaken();
156 if( timeoutTimer != null )
157 {
158 timeoutTimer.cancel();
159 }
160
161 if( status == Status.RUNNING )
162 {
163 status = Status.FINISHED;
164 }
165
166 internalFinally( runContext );
167 }
168 }
169
170 protected void setStartTime()
171 {
172 startTime = System.currentTimeMillis();
173 }
174
175 public boolean isRunning()
176 {
177 return getStatus() == Status.RUNNING;
178 }
179
180 public boolean isCanceled()
181 {
182 return getStatus() == Status.CANCELED;
183 }
184
185 public boolean isFailed()
186 {
187 return getStatus() == Status.FAILED;
188 }
189
190 protected void setStatus( Status status )
191 {
192 this.status = status;
193 }
194
195 protected void setError( Throwable error )
196 {
197 this.error = error;
198 }
199
200 protected abstract void internalRun( T2 runContext2 ) throws Exception;
201
202 protected abstract void internalFinally( T2 runContext2 );
203
204 protected void startTimeoutTimer( long timeout )
205 {
206 timeoutTimer = new Timer();
207 timeoutTimerTask = new TimeoutTimerTask();
208 timeoutTimer.schedule( timeoutTimerTask, timeout );
209 }
210
211 public T getTestRunnable()
212 {
213 return testRunnable;
214 }
215
216 public synchronized Status waitUntilFinished()
217 {
218 if( future != null )
219 {
220 if( !future.isDone() )
221 {
222 try
223 {
224 future.get();
225 }
226 catch( Exception e )
227 {
228 SoapUI.logError( e );
229 }
230 }
231 }
232 else
233 throw new RuntimeException( "cannot wait on null future" );
234
235 return getStatus();
236 }
237
238 protected void setTimeTaken()
239 {
240 timeTaken = System.currentTimeMillis() - startTime;
241 }
242
243 public long getTimeTaken()
244 {
245 return timeTaken;
246 }
247
248 public long getStartTime()
249 {
250 return startTime;
251 }
252
253 public Throwable getError()
254 {
255 return error;
256 }
257
258 public String getReason()
259 {
260 return reason == null ? error == null ? null : error.toString() : reason;
261 }
262
263 private final class TimeoutTimerTask extends TimerTask
264 {
265 @Override
266 public void run()
267 {
268 fail( "TestCase timed out" );
269 }
270 }
271
272
273 }