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