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.loadtest;
    14
    15  import java.beans.PropertyChangeEvent;
    16  import java.beans.PropertyChangeListener;
    17  import java.util.ArrayList;
    18  import java.util.HashSet;
    19  import java.util.List;
    20  import java.util.Set;
    21
    22  import org.apache.log4j.Logger;
    23
    24  import com.eviware.soapui.config.LoadStrategyConfig;
    25  import com.eviware.soapui.config.LoadTestAssertionConfig;
    26  import com.eviware.soapui.config.LoadTestConfig;
    27  import com.eviware.soapui.config.LoadTestLimitTypesConfig;
    28  import com.eviware.soapui.config.LoadTestLimitTypesConfig.Enum;
    29  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
    30  import com.eviware.soapui.impl.wsdl.loadtest.assertions.AbstractLoadTestAssertion;
    31  import com.eviware.soapui.impl.wsdl.loadtest.assertions.LoadTestAssertionRegistry;
    32  import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics;
    33  import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLog;
    34  import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLogErrorEntry;
    35  import com.eviware.soapui.impl.wsdl.loadtest.strategy.BurstLoadStrategy;
    36  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategy;
    37  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyFactory;
    38  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyRegistry;
    39  import com.eviware.soapui.impl.wsdl.loadtest.strategy.SimpleLoadStrategy;
    40  import com.eviware.soapui.impl.wsdl.support.Configurable;
    41  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
    42  import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
    43  import com.eviware.soapui.model.testsuite.LoadTest;
    44  import com.eviware.soapui.model.testsuite.LoadTestRunContext;
    45  import com.eviware.soapui.model.testsuite.LoadTestRunListener;
    46  import com.eviware.soapui.model.testsuite.LoadTestRunner;
    47  import com.eviware.soapui.model.testsuite.TestRunContext;
    48  import com.eviware.soapui.model.testsuite.TestRunner;
    49  import com.eviware.soapui.model.testsuite.TestStepResult;
    50  import com.eviware.soapui.model.testsuite.LoadTestRunner.Status;
    51
    52  /***
    53   * TestCase implementation for LoadTests
    54   *
    55   * @todo add assertionFailed event to LoadTestListener
    56   * @todo create and return LoadTestAssertionResult from load-test assertions
    57   *
    58   * @author Ole.Matzura
    59   */
    60
    61  public class WsdlLoadTest extends AbstractWsdlModelItem<LoadTestConfig> implements LoadTest
    62  {
    63  	public final static String THREADCOUNT_PROPERTY = WsdlLoadTest.class.getName() + "@threadcount";
    64  	public final static String STARTDELAY_PROPERTY = WsdlLoadTest.class.getName() + "@startdelay";
    65  	public final static String TESTLIMIT_PROPERTY = WsdlLoadTest.class.getName() + "@testlimit";
    66  	public final static String HISTORYLIMIT_PROPERTY = WsdlLoadTest.class.getName() + "@historylimit";
    67  	public final static String LIMITTYPE_PROPERRY = WsdlLoadTest.class.getName() + "@limittype";
    68  	public final static String SAMPLEINTERVAL_PROPERRY = WsdlLoadTest.class.getName() + "@sample-interval";
    69
    70     private final static Logger logger = Logger.getLogger( WsdlLoadTest.class );
    71     private InternalTestRunListener internalTestRunListener = new InternalTestRunListener();
    72
    73  	private WsdlTestCase testCase;
    74  	private LoadTestStatistics statisticsModel;
    75  	private LoadStrategy loadStrategy = new BurstLoadStrategy();
    76  	private LoadTestLog loadTestLog;
    77
    78  	private LoadStrategyConfigurationChangeListener loadStrategyListener = new LoadStrategyConfigurationChangeListener();
    79  	private List<LoadTestAssertion> assertions = new ArrayList<LoadTestAssertion>();
    80  	private ConfigurationChangePropertyListener configurationChangeListener = new ConfigurationChangePropertyListener();
    81  	private Set<LoadTestListener> listeners = new HashSet<LoadTestListener>();
    82  	private Set<LoadTestRunListener> runListeners = new HashSet<LoadTestRunListener>();
    83  	private WsdlLoadTestRunner runner;
    84
    85     public WsdlLoadTest(WsdlTestCase testCase, LoadTestConfig config )
    86     {
    87     	super( config, testCase, "/loadTest.gif" );
    88
    89        this.testCase = testCase;
    90
    91  		if( getConfig().getThreadCount() < 1 )
    92  			getConfig().setThreadCount( 5 );
    93
    94  		if( getConfig().getLimitType() == null )
    95  		{
    96  			getConfig().setLimitType( LoadTestLimitTypesConfig.TIME );
    97  			getConfig().setTestLimit( 60 );
    98  		}
    99
    100 		if( !getConfig().isSetHistoryLimit() )
    101 		{
    102 			getConfig().setHistoryLimit( -1 );
    103 		}
    104
    105       addLoadTestRunListener( internalTestRunListener );
    106
    107       LoadStrategyConfig ls = getConfig().getLoadStrategy();
    108       if( ls == null )
    109       {
    110       	ls = getConfig().addNewLoadStrategy();
    111       	ls.setType( SimpleLoadStrategy.STRATEGY_TYPE );
    112       }
    113
    114       LoadStrategyFactory factory = LoadStrategyRegistry.getInstance().getFactory( ls.getType() );
    115       if( factory == null )
    116       {
    117       	ls.setType( SimpleLoadStrategy.STRATEGY_TYPE );
    118       	factory = LoadStrategyRegistry.getInstance().getFactory( ls.getType() );
    119       }
    120
    121       loadStrategy = factory.build( ls.getConfig() );
    122       loadStrategy.addConfigurationChangeListener( loadStrategyListener );
    123
    124       addLoadTestRunListener( loadStrategy );
    125
    126       statisticsModel = new LoadTestStatistics( this );
    127
    128       if( getConfig().xgetSampleInterval() == null )
    129       	setSampleInterval( LoadTestStatistics.DEFAULT_SAMPLE_INTERVAL );
    130
    131       statisticsModel.setUpdateFrequency( getSampleInterval() );
    132
    133       List<LoadTestAssertionConfig> assertionList = getConfig().getAssertionList();
    134       for( LoadTestAssertionConfig assertionConfig : assertionList )
    135       {
    136       	AbstractLoadTestAssertion assertion = LoadTestAssertionRegistry.buildAssertion( assertionConfig, this );
    137       	if( assertion != null )
    138       	{
    139       		assertions.add( assertion);
    140       		assertion.addPropertyChangeListener( LoadTestAssertion.CONFIGURATION_PROPERTY, configurationChangeListener );
    141       	}
    142       	else
    143       	{
    144       		logger.warn( "Failed to build LoadTestAssertion from getConfig() [" + assertionConfig + "]" );
    145       	}
    146       }
    147
    148       if( getConfig().xgetResetStatisticsOnThreadCountChange() == null )
    149       	getConfig().setResetStatisticsOnThreadCountChange( true );
    150
    151       if( getConfig().xgetCalculateTPSOnTimePassed() == null )
    152       	getConfig().setCalculateTPSOnTimePassed( false );
    153
    154       loadTestLog = new LoadTestLog( this );
    155    }
    156
    157    public LoadTestStatistics getStatisticsModel()
    158    {
    159    	return statisticsModel;
    160    }
    161
    162    public long getThreadCount()
    163    {
    164    	return getConfig().getThreadCount();
    165    }
    166
    167    public void setThreadCount( long threadCount )
    168    {
    169    	if( threadCount < 1 || threadCount == getThreadCount() )
    170    		return;
    171
    172    	long oldCount = getThreadCount();
    173    	getConfig().setThreadCount( (int) threadCount );
    174    	notifyPropertyChanged( THREADCOUNT_PROPERTY, oldCount, threadCount );
    175    }
    176
    177    public boolean getResetStatisticsOnThreadCountChange()
    178    {
    179    	return getConfig().getResetStatisticsOnThreadCountChange();
    180    }
    181
    182    public void setResetStatisticsOnThreadCountChange( boolean value )
    183    {
    184    	getConfig().setResetStatisticsOnThreadCountChange( value );
    185    }
    186
    187    public boolean getCalculateTPSOnTimePassed()
    188    {
    189    	return getConfig().getCalculateTPSOnTimePassed();
    190    }
    191
    192    public void setCalculateTPSOnTimePassed( boolean value )
    193    {
    194    	getConfig().setCalculateTPSOnTimePassed( value );
    195    }
    196
    197    public int getStartDelay()
    198    {
    199    	return getConfig().getStartDelay();
    200    }
    201
    202    public void setStartDelay( int startDelay )
    203    {
    204    	if( startDelay < 0 )
    205    		return;
    206
    207    	int oldDelay = getStartDelay();
    208    	getConfig().setStartDelay( startDelay );
    209    	notifyPropertyChanged( STARTDELAY_PROPERTY, oldDelay, startDelay );
    210    }
    211
    212    public long getHistoryLimit()
    213    {
    214    	return getConfig().getHistoryLimit();
    215    }
    216
    217    public void setHistoryLimit( long historyLimit )
    218    {
    219    	long oldLimit = getHistoryLimit();
    220    	getConfig().setHistoryLimit( historyLimit );
    221    	if( historyLimit == 0 )
    222
    223
    224    	notifyPropertyChanged( HISTORYLIMIT_PROPERTY, oldLimit, historyLimit );
    225    }
    226
    227    public long getTestLimit()
    228    {
    229    	return getConfig().getTestLimit();
    230    }
    231
    232    public void setTestLimit( long testLimit )
    233    {
    234    	if( testLimit < 0 )
    235    		return;
    236
    237    	long oldLimit = getTestLimit();
    238    	getConfig().setTestLimit( testLimit );
    239    	notifyPropertyChanged( TESTLIMIT_PROPERTY, oldLimit, testLimit );
    240    }
    241
    242    public long getSampleInterval()
    243    {
    244    	return getConfig().getSampleInterval();
    245    }
    246
    247    public void setSampleInterval( int sampleInterval )
    248    {
    249    	if( sampleInterval < 0 )
    250    		return;
    251
    252    	long oldInterval = getSampleInterval();
    253    	getConfig().setSampleInterval( sampleInterval );
    254
    255    	statisticsModel.setUpdateFrequency( sampleInterval );
    256
    257    	notifyPropertyChanged( TESTLIMIT_PROPERTY, oldInterval, sampleInterval );
    258    }
    259
    260    public Enum getLimitType()
    261    {
    262    	return getConfig().getLimitType();
    263    }
    264
    265    public void setLimitType( Enum limitType )
    266    {
    267    	if( limitType == null )
    268    		return;
    269
    270    	Enum oldType = getLimitType();
    271    	getConfig().setLimitType( limitType );
    272    	notifyPropertyChanged( LIMITTYPE_PROPERRY, oldType, limitType );
    273    }
    274
    275    public WsdlTestCase getTestCase()
    276 	{
    277 		return testCase;
    278 	}
    279
    280    public synchronized WsdlLoadTestRunner run()
    281    {
    282    	getStatisticsModel().reset();
    283    	if( runner != null && runner.getStatus() == Status.RUNNING )
    284    		return null;
    285
    286    	runner = new WsdlLoadTestRunner( this );
    287    	runner.start();
    288    	return runner;
    289 	}
    290
    291 	private class InternalTestRunListener extends LoadTestRunListenerAdapter
    292 	{
    293 		public void afterTestCase(LoadTestRunner loadTestRunner, LoadTestRunContext context, TestRunner testRunner, TestRunContext runContext)
    294 		{
    295 			if( !assertions.isEmpty() )
    296 			{
    297 				for( LoadTestAssertion assertion : assertions )
    298 				{
    299 					String error = assertion.assertResults( loadTestRunner, context, testRunner, runContext );
    300 					if( error != null )
    301 					{
    302 						loadTestLog.addEntry( new LoadTestLogErrorEntry( assertion.getName(), error, assertion.getIcon() ));
    303 						statisticsModel.addError( LoadTestStatistics.TOTAL );
    304 					}
    305 				}
    306 			}
    307 		}
    308
    309 		public void afterTestStep(LoadTestRunner loadTestRunner, LoadTestRunContext context, TestRunner testRunner, TestRunContext runContext, TestStepResult result)
    310 		{
    311 			if( !assertions.isEmpty() )
    312 			{
    313 				boolean added = false;
    314
    315 				for( LoadTestAssertion assertion : assertions )
    316 				{
    317 					String error = assertion.assertResult( loadTestRunner, context, result, testRunner, runContext );
    318 					if( error != null )
    319 					{
    320 						int indexOfTestStep = testRunner.getTestCase().getIndexOfTestStep( result.getTestStep() );
    321
    322 						loadTestLog.addEntry( new LoadTestLogErrorEntry( assertion.getName(), error, result, assertion.getIcon() ));
    323 						statisticsModel.addError( indexOfTestStep);
    324
    325 						added = true;
    326 					}
    327 				}
    328
    329 				// always discard result if there were no errors
    330 				if( !added )
    331 				{
    332 					result.discard();
    333 				}
    334 			}
    335 			else result.discard();
    336 		}
    337 	}
    338
    339 	public LoadStrategy getLoadStrategy()
    340 	{
    341 		return loadStrategy;
    342 	}
    343
    344 	public void setLoadStrategy( LoadStrategy loadStrategy )
    345 	{
    346 		this.loadStrategy.removeConfigurationChangeListener( loadStrategyListener );
    347 		removeLoadTestRunListener( this.loadStrategy );
    348
    349 		this.loadStrategy = loadStrategy;
    350 		this.loadStrategy.addConfigurationChangeListener( loadStrategyListener );
    351 		addLoadTestRunListener( this.loadStrategy );
    352
    353 		getConfig().getLoadStrategy().setType( loadStrategy.getType() );
    354 		getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
    355 	}
    356
    357 	private class LoadStrategyConfigurationChangeListener implements PropertyChangeListener
    358 	{
    359 		public void propertyChange(PropertyChangeEvent evt)
    360 		{
    361 			getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
    362 		}
    363 	}
    364
    365 	public LoadTestAssertion addAssertion( String type, String targetStep, boolean showConfig )
    366 	{
    367 		LoadTestAssertion assertion = LoadTestAssertionRegistry.createAssertion( type, this );
    368 		assertion.setTargetStep( targetStep );
    369
    370 		if( assertion instanceof Configurable && showConfig )
    371 		{
    372 			if( !((Configurable)assertion).configure() )
    373 				return null;
    374 		}
    375
    376 		assertions.add( assertion );
    377
    378 		getConfig().addNewAssertion().set( assertion.getConfiguration() );
    379 		assertion.addPropertyChangeListener( LoadTestAssertion.CONFIGURATION_PROPERTY, configurationChangeListener );
    380 		fireAssertionAdded( assertion );
    381
    382 		return assertion;
    383 	}
    384
    385 	public void removeAssertion( LoadTestAssertion assertion)
    386 	{
    387 		int ix = assertions.indexOf( assertion );
    388 		if( ix >= 0 )
    389 		{
    390 			try
    391 			{
    392 				assertions.remove( ix );
    393 				fireAssertionRemoved(assertion);
    394 			}
    395 			finally
    396 			{
    397 				assertion.removePropertyChangeListener( configurationChangeListener );
    398 				assertion.release();
    399 				getConfig().removeAssertion( ix );
    400 			}
    401 		}
    402 	}
    403
    404 	private void fireAssertionRemoved(LoadTestAssertion assertion)
    405 	{
    406 		if( !listeners.isEmpty() )
    407 		{
    408 			LoadTestListener[] l = listeners.toArray( new LoadTestListener[listeners.size()] );
    409 			for( LoadTestListener listener : l )
    410 			{
    411 				listener.assertionRemoved( assertion );
    412 			}
    413 		}
    414 	}
    415
    416 	private void fireAssertionAdded(LoadTestAssertion assertion)
    417 	{
    418 		if( !listeners.isEmpty() )
    419 		{
    420 			LoadTestListener[] l = listeners.toArray( new LoadTestListener[listeners.size()] );
    421 			for( LoadTestListener listener : l )
    422 			{
    423 				listener.assertionAdded( assertion );
    424 			}
    425 		}
    426 	}
    427
    428 	public int getAssertionCount()
    429 	{
    430 		return assertions.size();
    431 	}
    432
    433 	public LoadTestAssertion getAssertionAt( int index )
    434 	{
    435 		return assertions.get( index );
    436 	}
    437
    438 	private class ConfigurationChangePropertyListener implements PropertyChangeListener
    439 	{
    440 		public void propertyChange(PropertyChangeEvent evt)
    441 		{
    442 			 int ix = assertions.indexOf( evt.getSource() );
    443 			 if( ix >= 0 )
    444 			 {
    445 				 getConfig().getAssertionArray( ix ).set( assertions.get( ix ).getConfiguration() );
    446 			 }
    447 		}
    448 	}
    449
    450 	public LoadTestLog getLoadTestLog()
    451 	{
    452 		return loadTestLog;
    453 	}
    454
    455 	public List<LoadTestAssertion> getAssertionList()
    456 	{
    457 		return assertions;
    458 	}
    459
    460 	public void addLoadTestListener( LoadTestListener listener )
    461 	{
    462 		listeners.add( listener );
    463 	}
    464
    465 	public void removeLoadTestListener( LoadTestListener listener )
    466 	{
    467 		listeners.remove( listener );
    468 	}
    469
    470 	public void addLoadTestRunListener(LoadTestRunListener listener)
    471 	{
    472 		runListeners.add( listener );
    473 	}
    474
    475 	public void removeLoadTestRunListener(LoadTestRunListener listener)
    476 	{
    477 		runListeners.remove( listener );
    478 	}
    479
    480 	public LoadTestRunListener [] getLoadTestRunListeners()
    481 	{
    482 		return runListeners.toArray( new LoadTestRunListener[runListeners.size()] );
    483 	}
    484
    485 	/***
    486 	 * Release internal objects so they can remove listeners
    487 	 */
    488
    489 	public void release()
    490 	{
    491 		super.release();
    492
    493 		statisticsModel.release();
    494 		loadTestLog.release();
    495
    496 		for( LoadTestAssertion assertion : assertions )
    497 			assertion.release();
    498 	}
    499
    500 	public boolean isRunning()
    501 	{
    502 		return runner != null && runner.getStatus() == LoadTestRunner.Status.RUNNING;
    503 	}
    504
    505 	public WsdlLoadTestRunner getRunner()
    506 	{
    507 		return runner;
    508 	}
    509
    510 	public void resetConfigOnMove( LoadTestConfig config )
    511 	{
    512 		setConfig( config );
    513
    514 		loadStrategy.updateConfig( config.getLoadStrategy().getConfig() );
    515
    516 		List<LoadTestAssertionConfig> assertionList = config.getAssertionList();
    517 		for( int c = 0; c < assertionList.size(); c++ )
    518 		{
    519 			assertions.get( c ).updateConfiguration( assertionList.get( c ) );
    520 		}
    521 	}
    522 }