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