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 }