View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.testcase;
14  
15  import java.util.ArrayList;
16  import java.util.Collections;
17  import java.util.List;
18  import java.util.concurrent.ExecutorService;
19  import java.util.concurrent.Executors;
20  import java.util.concurrent.Future;
21  
22  import org.apache.commons.httpclient.HttpState;
23  import org.apache.log4j.Logger;
24  
25  import com.eviware.soapui.SoapUI;
26  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
27  import com.eviware.soapui.model.support.PropertiesMap;
28  import com.eviware.soapui.model.testsuite.TestCase;
29  import com.eviware.soapui.model.testsuite.TestRunContext;
30  import com.eviware.soapui.model.testsuite.TestRunListener;
31  import com.eviware.soapui.model.testsuite.TestRunner;
32  import com.eviware.soapui.model.testsuite.TestStep;
33  import com.eviware.soapui.model.testsuite.TestStepResult;
34  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
35  import com.eviware.soapui.support.UISupport;
36  
37  /***
38   * WSDL TestCase Runner - runs all steps in a testcase and collects performance data
39   * 
40   * @author Ole.Matzura
41   */
42  
43  public class WsdlTestCaseRunner implements Runnable, TestRunner
44  {
45  	private TestRunListener [] listeners;
46  	private final WsdlTestCase testCase;
47  	private Status status;
48  	private Throwable error;
49  	private WsdlTestRunContext runContext;
50  	private List<TestStepResult> testStepResults = new ArrayList<TestStepResult>();
51  	private int gotoStepIndex;
52  	private long startTime;
53  	private String reason;
54  	private volatile Future<?> future;
55  	private int id;
56  	private final static ExecutorService threadPool = Executors.newCachedThreadPool();
57  	private final static Logger log = Logger.getLogger( WsdlTestCaseRunner.class );
58  	
59  	private static int idCounter = 0;
60  	
61  	public WsdlTestCaseRunner( WsdlTestCase testCase, PropertiesMap properties )
62  	{
63  		this.testCase = testCase;
64  		status = Status.INITIALIZED;
65  		runContext = new WsdlTestRunContext( this, properties );
66  		id = ++idCounter;
67  	}
68  	
69  	public WsdlTestRunContext 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 ||
86  				runContext == null ) return;
87  		TestStep currentStep = runContext.getCurrentStep();
88  		if( currentStep != null )
89  			currentStep.cancel();
90  		status = Status.CANCELED;
91  		this.reason = reason;
92  	}
93  
94  	public void fail( String reason )
95  	{
96  		if( status == Status.CANCELED || status == Status.FAILED ||
97  				runContext == null ) return;
98  		TestStep currentStep = runContext.getCurrentStep();
99  		if( currentStep != null )
100 			currentStep.cancel();
101 		status = Status.FAILED;
102 		this.reason = reason;
103 	}
104 	
105 	public Status getStatus()
106 	{
107 		return status;
108 	}
109 
110 	public int getId()
111 	{
112 		return id;
113 	}
114 
115 	public void run() 
116 	{
117 		WsdlTestStep[] testSteps = testCase.getTestSteps();
118 		int initCount = 0;
119 		
120 		try 
121 		{
122 			status = Status.RUNNING;
123 			startTime = System.currentTimeMillis();
124 			
125 			gotoStepIndex = -1;
126 			testStepResults.clear();
127 			
128 			listeners = testCase.getTestRunListeners();
129 			
130 			// create state for testcase if specified
131 			if( testCase.getKeepSession() )
132 			{
133 			   runContext.setProperty( TestRunContext.HTTP_STATE_PROPERTY, new HttpState() );	
134 			}
135 			
136 			for (int i = 0; i < listeners.length; i++) 
137 			{
138 				listeners[i].beforeRun( this, runContext );
139 				if( status == Status.CANCELED || status == Status.FAILED )
140 					return;
141 			}
142 			
143 			for( ; initCount < testCase.getTestStepCount(); initCount++ )
144 			{
145 				WsdlTestStep testStep = testCase.getTestStepAt( initCount );
146 				if( testStep.isDisabled() )
147 					continue;
148 				
149 				try
150 				{
151 					testStep.prepare( this, runContext );
152 				}
153 				catch( Exception e )
154 				{
155 					throw new Exception( "Failed to prepare testStep [" + testStep.getName() + "]; " + e.toString() );
156 				}
157 			}
158 			
159 			int currentStepIndex = runContext.getCurrentStepIndex();
160 
161 			for ( currentStepIndex = 0; status != Status.CANCELED && currentStepIndex < testSteps.length; currentStepIndex++) 
162 			{
163 				TestStep currentStep = runContext.getCurrentStep();
164 				if( !currentStep.isDisabled() )
165 				{
166 					for (int i = 0; i < listeners.length; i++) {
167 						listeners[i].beforeStep(this, runContext );
168 						if( status == Status.CANCELED || status == Status.FAILED )
169 							return;
170 					}
171 					
172 					TestStepResult stepResult = currentStep.run( this, runContext );
173 					testStepResults.add( stepResult );
174 					
175 					for (int i = 0; i < listeners.length; i++) 
176 					{
177 						listeners[i].afterStep( this, runContext, stepResult );
178 					}
179 					
180 					// discard?
181 					if( stepResult.getStatus() == TestStepStatus.OK && testCase.getDiscardOkResults() && 
182 						 !stepResult.isDiscarded()	)
183 					{
184 						stepResult.discard();
185 					}
186 	
187 					if( stepResult.getStatus() == TestStepStatus.FAILED )
188 					{
189 						if( testCase.getFailOnError()  )
190 						{
191 							error = stepResult.getError();
192 							fail( "Cancelling due to failed test step" );
193 						}
194 						else
195 						{
196 							runContext.setProperty( TestRunner.Status.class.getName(), TestRunner.Status.FAILED );
197 						}
198 					}
199 					
200 					if( status == Status.CANCELED || status == Status.FAILED )
201 						return;
202 	
203 					if( gotoStepIndex != -1 )
204 					{
205 						currentStepIndex = gotoStepIndex-1;
206 						gotoStepIndex = -1;
207 					}
208 				}
209 				
210 				runContext.setCurrentStep( currentStepIndex+1 );
211 			}
212 			
213 			if( runContext.getProperty( TestRunner.Status.class.getName() ) == TestRunner.Status.FAILED &&
214 				 testCase.getFailTestCaseOnErrors() )
215 			{
216 				fail( "Failing due to failed test step" );
217 			}
218 		} 
219 		catch (Throwable t) 
220 		{
221 			log.error( "Exception during TestCase Execution", t );
222 
223 			if( t instanceof OutOfMemoryError && 
224 			    UISupport.confirm( "Exit now without saving?", "Out of Memory Error" ) )
225 			{
226 				System.exit( 0 );
227 			}
228 			
229 			status = Status.FAILED;
230 			error = t;
231 			reason = t.toString();
232 		}
233 		finally
234 		{
235 			if( status == Status.RUNNING )
236 			{
237 				status = Status.FINISHED;
238 			}
239 			
240 			for( int c = 0; c < initCount; c++ )
241 			{
242 				WsdlTestStep testStep = testCase.getTestStepAt( c );
243 				if( !testStep.isDisabled() )
244 					testStep.finish( this, runContext );
245 			}
246 			
247 			notifyAfterRun();
248 			runContext.clear();
249 			listeners = null;
250 		}
251 	}
252 
253 	private void notifyAfterRun()
254 	{
255 		if( listeners == null || listeners.length == 0 )
256 			return;
257 		
258 		for (int i = 0; i < listeners.length; i++) 
259 		{
260 			listeners[i].afterRun( this, runContext );
261 		}
262 	}
263 
264 	public TestCase getTestCase() {
265 		return testCase;
266 	}
267 
268 	public synchronized Status waitUntilFinished()
269 	{
270 		if (future != null)
271 		{
272 			if (!future.isDone())
273 			{
274 				try
275 				{
276 					future.get();
277 				}
278 				catch (Exception e)
279 				{
280 					SoapUI.logError( e );
281 				}
282 			}
283 		}
284 		else
285 			throw new RuntimeException("cannot wait on null future");
286 
287 		
288 		return getStatus();
289 	}
290 	
291 	public long getTimeTaken()
292 	{
293 		long sum = 0;
294 		for( int c = 0; c < testStepResults.size(); c++ )
295 		{
296 			TestStepResult testStepResult = testStepResults.get( c );
297 			if( testStepResult != null )
298 				sum += testStepResult.getTimeTaken();
299 		}
300 		
301 		return sum;
302 	}
303 	
304 	public long getStartTime()
305 	{
306 		return startTime;
307 	}
308 
309 	public Throwable getError()
310 	{
311 		return error;
312 	}
313 	
314 	public String getReason()
315 	{
316 		return reason == null ? error == null ? null : error.toString() : reason;
317 	}
318 
319 	public List<TestStepResult> getResults()
320 	{
321 		return Collections.unmodifiableList( testStepResults );
322 	}
323 
324 	public void gotoStep(int index)
325 	{
326 		gotoStepIndex  = index;
327 	}
328 
329 	public void gotoStepByName(String stepName)
330 	{
331 		TestStep testStep = getTestCase().getTestStepByName( stepName );
332 		if( testStep != null )
333 			gotoStep( getTestCase().getIndexOfTestStep( testStep));
334 	}
335 }