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.io.File;
18 import java.io.FileNotFoundException;
19 import java.io.PrintWriter;
20 import java.util.ArrayList;
21 import java.util.Date;
22 import java.util.HashSet;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Set;
26
27 import org.apache.log4j.Logger;
28
29 import com.eviware.soapui.SoapUI;
30 import com.eviware.soapui.config.LoadStrategyConfig;
31 import com.eviware.soapui.config.LoadTestAssertionConfig;
32 import com.eviware.soapui.config.LoadTestConfig;
33 import com.eviware.soapui.config.LoadTestLimitTypesConfig;
34 import com.eviware.soapui.config.LoadTestLimitTypesConfig.Enum;
35 import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
36 import com.eviware.soapui.impl.wsdl.loadtest.assertions.AbstractLoadTestAssertion;
37 import com.eviware.soapui.impl.wsdl.loadtest.assertions.LoadTestAssertionRegistry;
38 import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics;
39 import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLog;
40 import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLogErrorEntry;
41 import com.eviware.soapui.impl.wsdl.loadtest.strategy.BurstLoadStrategy;
42 import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategy;
43 import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyFactory;
44 import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyRegistry;
45 import com.eviware.soapui.impl.wsdl.loadtest.strategy.SimpleLoadStrategy;
46 import com.eviware.soapui.impl.wsdl.support.Configurable;
47 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
48 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner;
49 import com.eviware.soapui.impl.wsdl.teststeps.SimplePathPropertySupport;
50 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
51 import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
52 import com.eviware.soapui.model.testsuite.LoadTest;
53 import com.eviware.soapui.model.testsuite.LoadTestRunContext;
54 import com.eviware.soapui.model.testsuite.LoadTestRunListener;
55 import com.eviware.soapui.model.testsuite.LoadTestRunner;
56 import com.eviware.soapui.model.testsuite.TestCaseRunContext;
57 import com.eviware.soapui.model.testsuite.TestCaseRunner;
58 import com.eviware.soapui.model.testsuite.TestRunnable;
59 import com.eviware.soapui.model.testsuite.TestRunner;
60 import com.eviware.soapui.model.testsuite.TestStepResult;
61 import com.eviware.soapui.model.testsuite.TestRunner.Status;
62 import com.eviware.soapui.settings.HttpSettings;
63 import com.eviware.soapui.support.StringUtils;
64 import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
65 import com.eviware.soapui.support.scripting.SoapUIScriptEngineRegistry;
66 import com.eviware.soapui.support.types.StringList;
67 import com.eviware.soapui.support.types.StringToObjectMap;
68
69 /***
70 * TestCase implementation for LoadTests
71 *
72 * @author Ole.Matzura
73 * @todo add assertionFailed event to LoadTestListener
74 * @todo create and return LoadTestAssertionResult from load-test assertions
75 */
76
77 public class WsdlLoadTest extends AbstractWsdlModelItem<LoadTestConfig> implements LoadTest, TestRunnable
78 {
79 public final static String THREADCOUNT_PROPERTY = WsdlLoadTest.class.getName() + "@threadcount";
80 public final static String STARTDELAY_PROPERTY = WsdlLoadTest.class.getName() + "@startdelay";
81 public final static String TESTLIMIT_PROPERTY = WsdlLoadTest.class.getName() + "@testlimit";
82 public final static String HISTORYLIMIT_PROPERTY = WsdlLoadTest.class.getName() + "@historylimit";
83 public final static String LIMITTYPE_PROPERRY = WsdlLoadTest.class.getName() + "@limittype";
84 public final static String SAMPLEINTERVAL_PROPERRY = WsdlLoadTest.class.getName() + "@sample-interval";
85 public static final String MAXASSERTIONERRORS_PROPERTY = WsdlLoadTest.class.getName() + "@max-assertion-errors";
86 public final static String SETUP_SCRIPT_PROPERTY = WsdlTestCase.class.getName() + "@setupScript";
87 public final static String TEARDOWN_SCRIPT_PROPERTY = WsdlTestCase.class.getName() + "@tearDownScript";
88
89 private final static Logger logger = Logger.getLogger( WsdlLoadTest.class );
90 public static final int DEFAULT_STRATEGY_INTERVAL = 500;
91
92 private InternalTestRunListener internalTestRunListener = new InternalTestRunListener();
93
94 private WsdlTestCase testCase;
95 private LoadTestStatistics statisticsModel;
96 private LoadStrategy loadStrategy = new BurstLoadStrategy( this );
97 private LoadTestLog loadTestLog;
98
99 private LoadStrategyConfigurationChangeListener loadStrategyListener = new LoadStrategyConfigurationChangeListener();
100 private List<LoadTestAssertion> assertions = new ArrayList<LoadTestAssertion>();
101 private ConfigurationChangePropertyListener configurationChangeListener = new ConfigurationChangePropertyListener();
102 private Set<LoadTestListener> loadTestListeners = new HashSet<LoadTestListener>();
103 private Set<LoadTestRunListener> loadTestRunListeners = new HashSet<LoadTestRunListener>();
104 private List<LoadTestLogErrorEntry> assertionErrors = new LinkedList<LoadTestLogErrorEntry>();
105 private WsdlLoadTestRunner runner;
106 private StatisticsLogger statisticsLogger = new StatisticsLogger();
107 private SoapUIScriptEngine setupScriptEngine;
108 private SoapUIScriptEngine tearDownScriptEngine;
109 @SuppressWarnings("unused")
110 private SimplePathPropertySupport logFolder;
111 private LoadTestRunListener[] loadTestRunListenersArray;
112
113 public WsdlLoadTest( WsdlTestCase testCase, LoadTestConfig config )
114 {
115 super( config, testCase, "/loadTest.gif" );
116
117 this.testCase = testCase;
118
119 if( getConfig().getThreadCount() < 1 )
120 getConfig().setThreadCount( 5 );
121
122 if( getConfig().getLimitType() == null )
123 {
124 getConfig().setLimitType( LoadTestLimitTypesConfig.TIME );
125 getConfig().setTestLimit( 60 );
126 }
127
128 if( !getConfig().isSetHistoryLimit() )
129 {
130 getConfig().setHistoryLimit( -1 );
131 }
132
133 addLoadTestRunListener( internalTestRunListener );
134
135 LoadStrategyConfig ls = getConfig().getLoadStrategy();
136 if( ls == null )
137 {
138 ls = getConfig().addNewLoadStrategy();
139 ls.setType( SimpleLoadStrategy.STRATEGY_TYPE );
140 }
141
142 LoadStrategyFactory factory = LoadStrategyRegistry.getInstance().getFactory( ls.getType() );
143 if( factory == null )
144 {
145 ls.setType( SimpleLoadStrategy.STRATEGY_TYPE );
146 factory = LoadStrategyRegistry.getInstance().getFactory( ls.getType() );
147 }
148
149 loadStrategy = factory.build( ls.getConfig(), this );
150 loadStrategy.addConfigurationChangeListener( loadStrategyListener );
151
152 addLoadTestRunListener( loadStrategy );
153
154 statisticsModel = new LoadTestStatistics( this );
155
156 if( getConfig().xgetSampleInterval() == null )
157 setSampleInterval( LoadTestStatistics.DEFAULT_SAMPLE_INTERVAL );
158
159 statisticsModel.setUpdateFrequency( getSampleInterval() );
160
161 List<LoadTestAssertionConfig> assertionList = getConfig().getAssertionList();
162 for( LoadTestAssertionConfig assertionConfig : assertionList )
163 {
164 AbstractLoadTestAssertion assertion = LoadTestAssertionRegistry.buildAssertion( assertionConfig, this );
165 if( assertion != null )
166 {
167 assertions.add( assertion );
168 assertion.addPropertyChangeListener( LoadTestAssertion.CONFIGURATION_PROPERTY, configurationChangeListener );
169 }
170 else
171 {
172 logger.warn( "Failed to build LoadTestAssertion from getConfig() [" + assertionConfig + "]" );
173 }
174 }
175
176 if( getConfig().xgetResetStatisticsOnThreadCountChange() == null )
177 getConfig().setResetStatisticsOnThreadCountChange( true );
178
179 if( getConfig().xgetCalculateTPSOnTimePassed() == null )
180 getConfig().setCalculateTPSOnTimePassed( true );
181
182 if( !getConfig().isSetMaxAssertionErrors() )
183 getConfig().setMaxAssertionErrors( 100 );
184
185 if( getConfig().xgetCancelExcessiveThreads() == null )
186 getConfig().setCancelExcessiveThreads( true );
187
188 if( getConfig().xgetStrategyInterval() == null )
189 getConfig().setStrategyInterval( DEFAULT_STRATEGY_INTERVAL );
190
191 loadTestLog = new LoadTestLog( this );
192
193 for( LoadTestRunListener listener : SoapUI.getListenerRegistry().getListeners( LoadTestRunListener.class ) )
194 {
195 addLoadTestRunListener( listener );
196 }
197
198
199 if( !getSettings().isSet( HttpSettings.CLOSE_CONNECTIONS ) )
200 getSettings().setBoolean( HttpSettings.CLOSE_CONNECTIONS,
201 SoapUI.getSettings().getBoolean( HttpSettings.CLOSE_CONNECTIONS ) );
202 }
203
204 public LoadTestStatistics getStatisticsModel()
205 {
206 return statisticsModel;
207 }
208
209 public StatisticsLogger getStatisticsLogger()
210 {
211 return statisticsLogger;
212 }
213
214 public long getThreadCount()
215 {
216 return getConfig().getThreadCount();
217 }
218
219 public void setThreadCount( long threadCount )
220 {
221 long oldCount = getThreadCount();
222 if( threadCount == oldCount )
223 return;
224
225 if( getLogStatisticsOnThreadChange() && isRunning() )
226 statisticsLogger.logStatistics( "ThreadCount change from " + oldCount + " to " + threadCount );
227
228 getConfig().setThreadCount( ( int )threadCount );
229 notifyPropertyChanged( THREADCOUNT_PROPERTY, oldCount, threadCount );
230 }
231
232 public boolean getResetStatisticsOnThreadCountChange()
233 {
234 return getConfig().getResetStatisticsOnThreadCountChange();
235 }
236
237 public void setResetStatisticsOnThreadCountChange( boolean value )
238 {
239 getConfig().setResetStatisticsOnThreadCountChange( value );
240 }
241
242 public boolean getCancelOnReachedLimit()
243 {
244 return getConfig().getCancelOnReachedLimit();
245 }
246
247 public void setCancelOnReachedLimit( boolean value )
248 {
249 getConfig().setCancelOnReachedLimit( value );
250 }
251
252 public boolean getCancelExcessiveThreads()
253 {
254 return getConfig().getCancelExcessiveThreads();
255 }
256
257 public void setCancelExcessiveThreads( boolean value )
258 {
259 getConfig().setCancelExcessiveThreads( value );
260 }
261
262 public boolean getLogStatisticsOnThreadChange()
263 {
264 return getConfig().getLogStatisticsOnThreadChange();
265 }
266
267 public void setLogStatisticsOnThreadChange( boolean value )
268 {
269 getConfig().setLogStatisticsOnThreadChange( value );
270 }
271
272 public String getStatisticsLogFolder()
273 {
274 return getConfig().getStatisticsLogFolder();
275 }
276
277 public void setStatisticsLogFolder( String value )
278 {
279 getConfig().setStatisticsLogFolder( value );
280 }
281
282 public boolean getCalculateTPSOnTimePassed()
283 {
284 return getConfig().getCalculateTPSOnTimePassed();
285 }
286
287 public void setCalculateTPSOnTimePassed( boolean value )
288 {
289 getConfig().setCalculateTPSOnTimePassed( value );
290 }
291
292 public int getStartDelay()
293 {
294 return getConfig().getStartDelay();
295 }
296
297 public void setStartDelay( int startDelay )
298 {
299 if( startDelay < 0 )
300 return;
301
302 int oldDelay = getStartDelay();
303 getConfig().setStartDelay( startDelay );
304 notifyPropertyChanged( STARTDELAY_PROPERTY, oldDelay, startDelay );
305 }
306
307 public long getHistoryLimit()
308 {
309 return getConfig().getHistoryLimit();
310 }
311
312 public void setHistoryLimit( long historyLimit )
313 {
314 long oldLimit = getHistoryLimit();
315 getConfig().setHistoryLimit( historyLimit );
316 if( historyLimit == 0 )
317
318 notifyPropertyChanged( HISTORYLIMIT_PROPERTY, oldLimit, historyLimit );
319 }
320
321 public long getTestLimit()
322 {
323 return getConfig().getTestLimit();
324 }
325
326 public void setTestLimit( long testLimit )
327 {
328 if( testLimit < 0 )
329 return;
330
331 long oldLimit = getTestLimit();
332 getConfig().setTestLimit( testLimit );
333 notifyPropertyChanged( TESTLIMIT_PROPERTY, oldLimit, testLimit );
334 }
335
336 public long getMaxAssertionErrors()
337 {
338 return getConfig().getMaxAssertionErrors();
339 }
340
341 public void setMaxAssertionErrors( long testLimit )
342 {
343 if( testLimit < 0 )
344 return;
345
346 long oldLimit = getMaxAssertionErrors();
347 getConfig().setMaxAssertionErrors( testLimit );
348 notifyPropertyChanged( MAXASSERTIONERRORS_PROPERTY, oldLimit, testLimit );
349 }
350
351 public long getStatisticsLogInterval()
352 {
353 return getConfig().getStatisticsLogInterval();
354 }
355
356 public void setStatisticsLogInterval( int sampleInterval )
357 {
358 if( sampleInterval < 0 )
359 return;
360
361 long oldInterval = getStatisticsLogInterval();
362 getConfig().setStatisticsLogInterval( sampleInterval );
363
364 notifyPropertyChanged( SAMPLEINTERVAL_PROPERRY, oldInterval, sampleInterval );
365
366 if( oldInterval == 0 && sampleInterval > 0 && isRunning() )
367 statisticsLogger.start();
368 }
369
370 public long getSampleInterval()
371 {
372 return getConfig().getSampleInterval();
373 }
374
375 public void setSampleInterval( int sampleInterval )
376 {
377 if( sampleInterval < 0 )
378 return;
379
380 long oldInterval = getSampleInterval();
381 getConfig().setSampleInterval( sampleInterval );
382
383 statisticsModel.setUpdateFrequency( sampleInterval );
384 notifyPropertyChanged( SAMPLEINTERVAL_PROPERRY, oldInterval, sampleInterval );
385 }
386
387 public Enum getLimitType()
388 {
389 return getConfig().getLimitType();
390 }
391
392 public void setLimitType( Enum limitType )
393 {
394 if( limitType == null )
395 return;
396
397 Enum oldType = getLimitType();
398 getConfig().setLimitType( limitType );
399 notifyPropertyChanged( LIMITTYPE_PROPERRY, oldType, limitType );
400 }
401
402 public WsdlTestCase getTestCase()
403 {
404 return testCase;
405 }
406
407 public synchronized WsdlLoadTestRunner run()
408 {
409 getStatisticsModel().reset();
410 if( runner != null && runner.getStatus() == Status.RUNNING )
411 return null;
412
413 assertionErrors.clear();
414 runner = new WsdlLoadTestRunner( this );
415 runner.start();
416 return runner;
417 }
418
419 private class InternalTestRunListener extends LoadTestRunListenerAdapter
420 {
421 @Override
422 public void afterLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
423 {
424 statisticsLogger.finish();
425 }
426
427 @Override
428 public void beforeLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
429 {
430 statisticsLogger.init( context );
431
432 if( getStatisticsLogInterval() > 0 )
433 statisticsLogger.start();
434 }
435
436 @Override
437 public void afterTestCase( LoadTestRunner loadTestRunner, LoadTestRunContext context, TestCaseRunner testRunner,
438 TestCaseRunContext runContext )
439 {
440 if( !assertions.isEmpty() )
441 {
442 for( LoadTestAssertion assertion : assertions )
443 {
444 String error = assertion.assertResults( loadTestRunner, context, testRunner, runContext );
445 if( error != null )
446 {
447 int threadIndex = 0;
448
449 try
450 {
451 threadIndex = Integer.parseInt( runContext.getProperty( "ThreadIndex" ).toString() );
452 }
453 catch( Throwable t )
454 {
455 }
456
457 loadTestLog.addEntry( new LoadTestLogErrorEntry( assertion.getName(), error, assertion.getIcon(),
458 threadIndex ) );
459 statisticsModel.addError( LoadTestStatistics.TOTAL );
460 }
461 }
462 }
463 }
464
465 @Override
466 public void afterTestStep( LoadTestRunner loadTestRunner, LoadTestRunContext context, TestCaseRunner testRunner,
467 TestCaseRunContext runContext, TestStepResult result )
468 {
469 if( !assertions.isEmpty() )
470 {
471 boolean added = false;
472
473 for( LoadTestAssertion assertion : assertions )
474 {
475 String error = assertion.assertResult( loadTestRunner, context, result, testRunner, runContext );
476 if( error != null )
477 {
478 int indexOfTestStep = testRunner.getTestCase().getIndexOfTestStep( result.getTestStep() );
479 int threadIndex = 0;
480
481 try
482 {
483 threadIndex = Integer.parseInt( runContext.getProperty( "ThreadIndex" ).toString() );
484 }
485 catch( Throwable t )
486 {
487 }
488
489 LoadTestLogErrorEntry errorEntry = new LoadTestLogErrorEntry( assertion.getName(), error, result,
490 assertion.getIcon(), threadIndex );
491
492 loadTestLog.addEntry( errorEntry );
493 statisticsModel.addError( indexOfTestStep );
494
495 long maxAssertionErrors = getMaxAssertionErrors();
496 if( maxAssertionErrors > 0 )
497 {
498 synchronized( assertionErrors )
499 {
500 assertionErrors.add( errorEntry );
501 while( assertionErrors.size() > maxAssertionErrors )
502 {
503 assertionErrors.remove( 0 ).discard();
504 }
505 }
506 }
507
508 added = true;
509 }
510 }
511
512
513 if( !added )
514 {
515 if( getTestCase().getDiscardOkResults() || getTestCase().getMaxResults() == 0 )
516 {
517 result.discard();
518 }
519 else if( getTestCase().getMaxResults() > 0 && testRunner instanceof WsdlTestCaseRunner )
520 {
521 ( ( WsdlTestCaseRunner )testRunner ).enforceMaxResults( getTestCase().getMaxResults() );
522 }
523 }
524 }
525 else
526 result.discard();
527 }
528 }
529
530 public LoadStrategy getLoadStrategy()
531 {
532 return loadStrategy;
533 }
534
535 public void setLoadStrategy( LoadStrategy loadStrategy )
536 {
537 this.loadStrategy.removeConfigurationChangeListener( loadStrategyListener );
538 removeLoadTestRunListener( this.loadStrategy );
539
540 this.loadStrategy = loadStrategy;
541 this.loadStrategy.addConfigurationChangeListener( loadStrategyListener );
542 addLoadTestRunListener( this.loadStrategy );
543
544 getConfig().getLoadStrategy().setType( loadStrategy.getType() );
545 getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
546 }
547
548 private class LoadStrategyConfigurationChangeListener implements PropertyChangeListener
549 {
550 public void propertyChange( PropertyChangeEvent evt )
551 {
552 getConfig().getLoadStrategy().setConfig( loadStrategy.getConfig() );
553 }
554 }
555
556 public LoadTestAssertion addAssertion( String type, String targetStep, boolean showConfig )
557 {
558 LoadTestAssertion assertion = LoadTestAssertionRegistry.createAssertion( type, this );
559 assertion.setTargetStep( targetStep );
560
561 if( assertion instanceof Configurable && showConfig )
562 {
563 if( !( ( Configurable )assertion ).configure() )
564 return null;
565 }
566
567 assertions.add( assertion );
568
569 getConfig().addNewAssertion().set( assertion.getConfiguration() );
570 assertion.addPropertyChangeListener( LoadTestAssertion.CONFIGURATION_PROPERTY, configurationChangeListener );
571 fireAssertionAdded( assertion );
572
573 return assertion;
574 }
575
576 public void removeAssertion( LoadTestAssertion assertion )
577 {
578 int ix = assertions.indexOf( assertion );
579 if( ix >= 0 )
580 {
581 try
582 {
583 assertions.remove( ix );
584 fireAssertionRemoved( assertion );
585 }
586 finally
587 {
588 assertion.removePropertyChangeListener( configurationChangeListener );
589 assertion.release();
590 getConfig().removeAssertion( ix );
591 }
592 }
593 }
594
595 private void fireAssertionRemoved( LoadTestAssertion assertion )
596 {
597 if( !loadTestListeners.isEmpty() )
598 {
599 LoadTestListener[] l = loadTestListeners.toArray( new LoadTestListener[loadTestListeners.size()] );
600 for( LoadTestListener listener : l )
601 {
602 listener.assertionRemoved( assertion );
603 }
604 }
605 }
606
607 private void fireAssertionAdded( LoadTestAssertion assertion )
608 {
609 if( !loadTestListeners.isEmpty() )
610 {
611 LoadTestListener[] l = loadTestListeners.toArray( new LoadTestListener[loadTestListeners.size()] );
612 for( LoadTestListener listener : l )
613 {
614 listener.assertionAdded( assertion );
615 }
616 }
617 }
618
619 public int getAssertionCount()
620 {
621 return assertions.size();
622 }
623
624 public LoadTestAssertion getAssertionAt( int index )
625 {
626 return index < 0 || index >= assertions.size() ? null : assertions.get( index );
627 }
628
629 private class ConfigurationChangePropertyListener implements PropertyChangeListener
630 {
631 public void propertyChange( PropertyChangeEvent evt )
632 {
633 int ix = assertions.indexOf( evt.getSource() );
634 if( ix >= 0 )
635 {
636 getConfig().getAssertionArray( ix ).set( assertions.get( ix ).getConfiguration() );
637 }
638 }
639 }
640
641 public LoadTestLog getLoadTestLog()
642 {
643 return loadTestLog;
644 }
645
646 public List<LoadTestAssertion> getAssertionList()
647 {
648 return assertions;
649 }
650
651 public void addLoadTestListener( LoadTestListener listener )
652 {
653 loadTestListeners.add( listener );
654 }
655
656 public void removeLoadTestListener( LoadTestListener listener )
657 {
658 loadTestListeners.remove( listener );
659 }
660
661 public void addLoadTestRunListener( LoadTestRunListener listener )
662 {
663 loadTestRunListeners.add( listener );
664 loadTestRunListenersArray = null;
665 }
666
667 public void removeLoadTestRunListener( LoadTestRunListener listener )
668 {
669 loadTestRunListeners.remove( listener );
670 loadTestRunListenersArray = null;
671 }
672
673 public LoadTestRunListener[] getLoadTestRunListeners()
674 {
675 if( loadTestRunListenersArray == null )
676 {
677 loadTestRunListenersArray = loadTestRunListeners
678 .toArray( new LoadTestRunListener[loadTestRunListeners.size()] );
679 }
680
681 return loadTestRunListenersArray;
682 }
683
684 /***
685 * Release internal objects so they can remove listeners
686 */
687
688 @Override
689 public void release()
690 {
691 super.release();
692
693 statisticsModel.release();
694 loadTestLog.release();
695
696 for( LoadTestAssertion assertion : assertions )
697 assertion.release();
698
699 loadTestRunListeners.clear();
700 loadTestListeners.clear();
701 }
702
703 public boolean isRunning()
704 {
705 return runner != null && runner.getStatus() == LoadTestRunner.Status.RUNNING;
706 }
707
708 public WsdlLoadTestRunner getRunner()
709 {
710 return runner;
711 }
712
713 public void resetConfigOnMove( LoadTestConfig config )
714 {
715 setConfig( config );
716
717 loadStrategy.updateConfig( config.getLoadStrategy().getConfig() );
718
719 List<LoadTestAssertionConfig> assertionList = config.getAssertionList();
720 for( int c = 0; c < assertionList.size(); c++ )
721 {
722 assertions.get( c ).updateConfiguration( assertionList.get( c ) );
723 }
724 }
725
726 public class StatisticsLogger implements Runnable
727 {
728 private boolean stopped;
729 private List<PrintWriter> writers = new ArrayList<PrintWriter>();
730 private long startTime;
731
732 public void run()
733 {
734 stopped = false;
735
736 while( !stopped && getStatisticsLogInterval() > 0 )
737 {
738 try
739 {
740 long statisticsInterval = getStatisticsLogInterval();
741 Thread.sleep( statisticsInterval );
742 if( !stopped )
743 {
744 logStatistics( "Interval" );
745 }
746 }
747 catch( InterruptedException e )
748 {
749 e.printStackTrace();
750 }
751 }
752 }
753
754 public void start()
755 {
756 new Thread( this, "Statistics Logger for LoadTest [" + getName() + "]" ).start();
757 }
758
759 public void init( LoadTestRunContext context )
760 {
761 writers.clear();
762
763 String statisticsLogFolder = context.expand( getStatisticsLogFolder() );
764 if( StringUtils.isNullOrEmpty( statisticsLogFolder ) )
765 return;
766
767 File folder = new File( statisticsLogFolder );
768 if( !folder.exists() )
769 {
770 if( !folder.mkdirs() )
771 {
772 SoapUI
773 .logError( new Exception( "Failed to create statistics log folder [" + statisticsLogFolder + "]" ) );
774 return;
775 }
776 }
777
778 for( int c = 0; c < testCase.getTestStepCount(); c++ )
779 {
780 try
781 {
782 WsdlTestStep testStep = testCase.getTestStepAt( c );
783 String fileName = StringUtils.createFileName( testStep.getName(), '_' ) + ".log";
784 PrintWriter writer = new PrintWriter( new File( folder, fileName ) );
785 writers.add( writer );
786 addHeaders( writer );
787 }
788 catch( FileNotFoundException e )
789 {
790 e.printStackTrace();
791 writers.add( null );
792 }
793 }
794
795
796 try
797 {
798 String fileName = StringUtils.createFileName( testCase.getName(), '_' ) + ".log";
799 writers.add( new PrintWriter( new File( folder, fileName ) ) );
800 }
801 catch( FileNotFoundException e )
802 {
803 e.printStackTrace();
804 }
805
806 startTime = System.nanoTime();
807 }
808
809 private void addHeaders( PrintWriter writer )
810 {
811 writer.print( "date,threads,elapsed,min,max,avg,last,cnt,tps,bytes,bps,err,reason\n" );
812 }
813
814 public void finish()
815 {
816 stopped = true;
817
818 logStatistics( "Finished" );
819 for( PrintWriter writer : writers )
820 {
821 if( writer != null )
822 writer.close();
823 }
824 }
825
826 private synchronized void logStatistics( String trigger )
827 {
828 if( writers.isEmpty() )
829 return;
830
831 long timestamp = System.nanoTime();
832 String elapsedString = String.valueOf( ( timestamp - startTime ) / 100000 );
833 String dateString = new Date().toString();
834 String threadCountString = String.valueOf( getThreadCount() );
835
836 StringList[] snapshot = statisticsModel.getSnapshot();
837 for( int c = 0; c < snapshot.length; c++ )
838 {
839 PrintWriter writer = writers.get( c );
840 if( writer == null )
841 continue;
842
843 StringList values = snapshot[c];
844 writer.append( dateString ).append( ',' );
845 writer.append( threadCountString ).append( ',' );
846 writer.append( elapsedString );
847
848 for( String value : values )
849 {
850 writer.append( ',' ).append( value );
851 }
852
853 writer.append( ',' ).append( trigger ).append( '\n' );
854 writer.flush();
855 }
856 }
857 }
858
859 public void setSetupScript( String script )
860 {
861 String oldScript = getSetupScript();
862
863 if( !getConfig().isSetSetupScript() )
864 getConfig().addNewSetupScript();
865
866 getConfig().getSetupScript().setStringValue( script );
867 if( setupScriptEngine != null )
868 setupScriptEngine.setScript( script );
869
870 notifyPropertyChanged( SETUP_SCRIPT_PROPERTY, oldScript, script );
871 }
872
873 public String getSetupScript()
874 {
875 return getConfig().isSetSetupScript() ? getConfig().getSetupScript().getStringValue() : null;
876 }
877
878 public void setTearDownScript( String script )
879 {
880 String oldScript = getTearDownScript();
881
882 if( !getConfig().isSetTearDownScript() )
883 getConfig().addNewTearDownScript();
884
885 getConfig().getTearDownScript().setStringValue( script );
886 if( tearDownScriptEngine != null )
887 tearDownScriptEngine.setScript( script );
888
889 notifyPropertyChanged( TEARDOWN_SCRIPT_PROPERTY, oldScript, script );
890 }
891
892 public String getTearDownScript()
893 {
894 return getConfig().isSetTearDownScript() ? getConfig().getTearDownScript().getStringValue() : null;
895 }
896
897 public Object runSetupScript( LoadTestRunContext runContext, LoadTestRunner runner ) throws Exception
898 {
899 String script = getSetupScript();
900 if( StringUtils.isNullOrEmpty( script ) )
901 return null;
902
903 if( setupScriptEngine == null )
904 {
905 setupScriptEngine = SoapUIScriptEngineRegistry.create( this );
906 setupScriptEngine.setScript( script );
907 }
908
909 setupScriptEngine.setVariable( "context", runContext );
910 setupScriptEngine.setVariable( "loadTestRunner", runner );
911 setupScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
912 return setupScriptEngine.run();
913 }
914
915 public Object runTearDownScript( LoadTestRunContext runContext, LoadTestRunner runner ) throws Exception
916 {
917 String script = getTearDownScript();
918 if( StringUtils.isNullOrEmpty( script ) )
919 return null;
920
921 if( tearDownScriptEngine == null )
922 {
923 tearDownScriptEngine = SoapUIScriptEngineRegistry.create( this );
924 tearDownScriptEngine.setScript( script );
925 }
926
927 tearDownScriptEngine.setVariable( "context", runContext );
928 tearDownScriptEngine.setVariable( "loadTestRunner", runner );
929 tearDownScriptEngine.setVariable( "log", SoapUI.ensureGroovyLog() );
930 return tearDownScriptEngine.run();
931 }
932
933 public int getStrategyInterval()
934 {
935 return getConfig().getStrategyInterval();
936 }
937
938 public void setStrategyInterval( int interval )
939 {
940 getConfig().setStrategyInterval( interval );
941 }
942
943 public boolean getUpdateStatisticsPerTestStep()
944 {
945 return getConfig().getUpdateStatisticsPerTestStep();
946 }
947
948 public void setUpdateStatisticsPerTestStep( boolean updateStatisticsPerTestStep )
949 {
950 getConfig().setUpdateStatisticsPerTestStep( updateStatisticsPerTestStep );
951 }
952
953 public TestRunner run( StringToObjectMap context, boolean async )
954 {
955
956 return null;
957 }
958 }