View Javadoc

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