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 }