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
58 public AbstractTestRunner( T modelItem, StringToObjectMap properties )
59 {
60 this.testRunnable = modelItem;
61 status = Status.INITIALIZED;
62 id = ++idCounter;
63
64 runContext = createContext( properties );
65 }
66
67 public abstract T2 createContext( StringToObjectMap properties );
68
69 public T2 getRunContext()
70 {
71 return runContext;
72 }
73
74 public void start( boolean async )
75 {
76 status = Status.RUNNING;
77 if( async )
78 future = threadPool.submit( this );
79 else
80 run();
81 }
82
83 public void cancel( String reason )
84 {
85 if( status == Status.CANCELED || status == Status.FINISHED || status == Status.FAILED || runContext == null )
86 return;
87 onCancel( reason );
88 status = Status.CANCELED;
89 this.reason = reason;
90 }
91
92 protected void onCancel( String reason2 )
93 {
94 }
95
96 public void fail( String reason )
97 {
98 if( status == Status.CANCELED || status == Status.FAILED || runContext == null )
99 return;
100 onFail( reason );
101 status = Status.FAILED;
102 this.reason = reason;
103 }
104
105 protected void onFail( String reason )
106 {
107 }
108
109 public Status getStatus()
110 {
111 return status;
112 }
113
114 public int getId()
115 {
116 return id;
117 }
118
119 public Thread getThread()
120 {
121 return thread;
122 }
123
124 public void run()
125 {
126 if( future != null )
127 {
128 thread = Thread.currentThread();
129 thread.setName( "TestRunner Thread for " + testRunnable.getName() );
130 }
131
132 try
133 {
134 status = Status.RUNNING;
135 startTime = System.currentTimeMillis();
136
137 internalRun( runContext );
138 }
139 catch( Throwable t )
140 {
141 log.error( "Exception during Test Execution", t );
142
143 if( t instanceof OutOfMemoryError && UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
144 {
145 System.exit( 0 );
146 }
147
148 status = Status.FAILED;
149 error = t;
150 reason = t.toString();
151 }
152 finally
153 {
154 if( timeoutTimer != null )
155 {
156 timeoutTimer.cancel();
157 }
158
159 if( status == Status.RUNNING )
160 {
161 status = Status.FINISHED;
162 }
163
164 internalFinally( runContext );
165 }
166 }
167
168 public boolean isRunning()
169 {
170 return getStatus() == Status.RUNNING;
171 }
172
173 public boolean isCanceled()
174 {
175 return getStatus() == Status.CANCELED;
176 }
177
178 public boolean isFailed()
179 {
180 return getStatus() == Status.FAILED;
181 }
182
183 protected void setStatus( Status status )
184 {
185 this.status = status;
186 }
187
188 protected void setError( Throwable error )
189 {
190 this.error = error;
191 }
192
193 protected abstract void internalRun( T2 runContext2 ) throws Exception;
194
195 protected abstract void internalFinally( T2 runContext2 );
196
197 protected void startTimeoutTimer( long timeout )
198 {
199 timeoutTimer = new Timer();
200 timeoutTimerTask = new TimeoutTimerTask();
201 timeoutTimer.schedule( timeoutTimerTask, timeout );
202 }
203
204 public T getTestRunnable()
205 {
206 return testRunnable;
207 }
208
209 public synchronized Status waitUntilFinished()
210 {
211 if( future != null )
212 {
213 if( !future.isDone() )
214 {
215 try
216 {
217 future.get();
218 }
219 catch( Exception e )
220 {
221 SoapUI.logError( e );
222 }
223 }
224 }
225 else
226 throw new RuntimeException( "cannot wait on null future" );
227
228 return getStatus();
229 }
230
231 public long getTimeTaken()
232 {
233 return System.currentTimeMillis() - startTime;
234 }
235
236 public long getStartTime()
237 {
238 return startTime;
239 }
240
241 public Throwable getError()
242 {
243 return error;
244 }
245
246 public String getReason()
247 {
248 return reason == null ? error == null ? null : error.toString() : reason;
249 }
250
251 private final class TimeoutTimerTask extends TimerTask
252 {
253 @Override
254 public void run()
255 {
256 fail( "TestCase timed out" );
257 }
258 }
259
260
261 }