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.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 				// always discard result if there were no errors
321 				if( !added )
322 				{
323 					result.discard();
324 				}
325 			}				
326 			else result.discard();
327 		}
328 	}
329 
330 	public LoadStrategy getLoadStrategy()
331 	{
332 		return loadStrategy;
333 	}
334 	
335 	public void setLoadStrategy( LoadStrategy loadStrategy )
336 	{
337 		this.loadStrategy.removeConfigurationChangeListener( loadStrategyListener );
338 		removeLoadTestRunListener( this.loadStrategy );
339 		
340 		this.loadStrategy = loadStrategy;
341 		this.loadStrategy.addConfigurationChangeListener( loadStrategyListener );
342 		addLoadTestRunListener( this.loadStrategy );
343 		
344 		getConfig().getLoadStrategy().setType( loadStrategy.getType() );
345 		getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
346 	}
347 
348 	private class LoadStrategyConfigurationChangeListener implements PropertyChangeListener
349 	{
350 		public void propertyChange(PropertyChangeEvent evt)
351 		{
352 			getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
353 		}
354 	}
355 
356 	public LoadTestAssertion addAssertion( String type, String targetStep, boolean showConfig )
357 	{
358 		LoadTestAssertion assertion = LoadTestAssertionRegistry.createAssertion( type, this );
359 		assertion.setTargetStep( targetStep );
360 		
361 		if( assertion instanceof Configurable && showConfig )
362 		{
363 			if( !((Configurable)assertion).configure() )
364 				return null;
365 		}
366 		
367 		assertions.add( assertion );
368 		
369 		getConfig().addNewAssertion().set( assertion.getConfiguration() );
370 		assertion.addPropertyChangeListener( LoadTestAssertion.CONFIGURATION_PROPERTY, configurationChangeListener );
371 		fireAssertionAdded( assertion );
372 		
373 		return assertion;
374 	}
375 	
376 	public void removeAssertion( LoadTestAssertion assertion)
377 	{
378 		int ix = assertions.indexOf( assertion );
379 		if( ix >= 0 )
380 		{
381 			try
382 			{
383 				assertions.remove( ix );
384 				fireAssertionRemoved(assertion);
385 			}
386 			finally
387 			{
388 				assertion.removePropertyChangeListener( configurationChangeListener );
389 				assertion.release();
390 				getConfig().removeAssertion( ix );
391 			}
392 		}
393 	}
394 
395 	private void fireAssertionRemoved(LoadTestAssertion assertion)
396 	{
397 		if( !listeners.isEmpty() )
398 		{
399 			LoadTestListener[] l = listeners.toArray( new LoadTestListener[listeners.size()] );
400 			for( LoadTestListener listener : l )
401 			{
402 				listener.assertionRemoved( assertion );
403 			}
404 		}
405 	}
406 	
407 	private void fireAssertionAdded(LoadTestAssertion assertion)
408 	{
409 		if( !listeners.isEmpty() )
410 		{
411 			LoadTestListener[] l = listeners.toArray( new LoadTestListener[listeners.size()] );
412 			for( LoadTestListener listener : l )
413 			{
414 				listener.assertionAdded( assertion );
415 			}
416 		}
417 	}
418 
419 	public int getAssertionCount()
420 	{
421 		return assertions.size();
422 	}
423 	
424 	public LoadTestAssertion getAssertionAt( int index )
425 	{
426 		return assertions.get( index );
427 	}
428 	
429 	private class ConfigurationChangePropertyListener implements PropertyChangeListener
430 	{
431 		public void propertyChange(PropertyChangeEvent evt)
432 		{
433 			 int ix = assertions.indexOf( evt.getSource() );
434 			 if( ix >= 0 )
435 			 {
436 				 getConfig().getAssertionArray( ix ).set( assertions.get( ix ).getConfiguration() );
437 			 }
438 		}
439 	}
440 
441 	public LoadTestLog getLoadTestLog()
442 	{
443 		return loadTestLog;
444 	}
445 
446 	public List<LoadTestAssertion> getAssertionList()
447 	{
448 		return assertions;
449 	}
450 	
451 	public void addLoadTestListener( LoadTestListener listener )
452 	{
453 		listeners.add( listener );
454 	}
455 
456 	public void removeLoadTestListener( LoadTestListener listener )
457 	{
458 		listeners.remove( listener );
459 	}
460 
461 	public void addLoadTestRunListener(LoadTestRunListener listener)
462 	{
463 		runListeners.add( listener );
464 	}
465 
466 	public void removeLoadTestRunListener(LoadTestRunListener listener)
467 	{
468 		runListeners.remove( listener );
469 	}
470 	
471 	public LoadTestRunListener [] getLoadTestRunListeners()
472 	{
473 		return runListeners.toArray( new LoadTestRunListener[runListeners.size()] );
474 	}
475 
476 	/***
477 	 * Release internal objects so they can remove listeners
478 	 */
479 	
480 	public void release()
481 	{
482 		super.release();
483 		
484 		statisticsModel.release();
485 		loadTestLog.release();
486 		
487 		for( LoadTestAssertion assertion : assertions )
488 			assertion.release();
489 	}
490 
491 	public boolean isRunning()
492 	{
493 		return runner != null && runner.getStatus() == LoadTestRunner.Status.RUNNING;
494 	}
495 
496 	public WsdlLoadTestRunner getRunner()
497 	{
498 		return runner;
499 	}
500 }