1
2
3
4
5
6
7
8
9
10
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
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 }