View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.panels.loadtest;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Dimension;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.ItemEvent;
19  import java.awt.event.ItemListener;
20  import java.beans.PropertyChangeEvent;
21  import java.beans.PropertyChangeListener;
22  
23  import javax.swing.AbstractAction;
24  import javax.swing.Action;
25  import javax.swing.BorderFactory;
26  import javax.swing.Box;
27  import javax.swing.JButton;
28  import javax.swing.JComboBox;
29  import javax.swing.JComponent;
30  import javax.swing.JLabel;
31  import javax.swing.JPanel;
32  import javax.swing.JProgressBar;
33  import javax.swing.JSpinner;
34  import javax.swing.JSplitPane;
35  import javax.swing.JTabbedPane;
36  import javax.swing.SpinnerNumberModel;
37  import javax.swing.event.ChangeEvent;
38  import javax.swing.event.ChangeListener;
39  
40  import com.eviware.soapui.SoapUI;
41  import com.eviware.soapui.config.LoadTestLimitTypesConfig;
42  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
43  import com.eviware.soapui.impl.wsdl.actions.loadtest.LoadTestOptionsAction;
44  import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
45  import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTestRunner;
46  import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics;
47  import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
48  import com.eviware.soapui.impl.wsdl.loadtest.data.actions.ExportStatisticsAction;
49  import com.eviware.soapui.impl.wsdl.loadtest.log.LoadTestLog;
50  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategy;
51  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyFactory;
52  import com.eviware.soapui.impl.wsdl.loadtest.strategy.LoadStrategyRegistry;
53  import com.eviware.soapui.impl.wsdl.panels.support.MockLoadTestRunContext;
54  import com.eviware.soapui.impl.wsdl.panels.support.MockLoadTestRunner;
55  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.AbstractGroovyEditorModel;
56  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
57  import com.eviware.soapui.model.ModelItem;
58  import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
59  import com.eviware.soapui.model.testsuite.LoadTestRunContext;
60  import com.eviware.soapui.model.testsuite.LoadTestRunListener;
61  import com.eviware.soapui.model.testsuite.LoadTestRunner;
62  import com.eviware.soapui.model.testsuite.TestRunner.Status;
63  import com.eviware.soapui.support.UISupport;
64  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
65  import com.eviware.soapui.support.components.GroovyEditorComponent;
66  import com.eviware.soapui.support.components.GroovyEditorInspector;
67  import com.eviware.soapui.support.components.JComponentInspector;
68  import com.eviware.soapui.support.components.JInspectorPanel;
69  import com.eviware.soapui.support.components.JInspectorPanelFactory;
70  import com.eviware.soapui.support.components.JXToolBar;
71  import com.eviware.soapui.ui.desktop.DesktopPanel;
72  import com.eviware.soapui.ui.support.DesktopListenerAdapter;
73  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
74  import com.jgoodies.forms.builder.ButtonBarBuilder;
75  
76  /***
77   * Desktop panel for LoadTests
78   * 
79   * @author Ole.Matzura
80   */
81  
82  public class WsdlLoadTestDesktopPanel extends ModelItemDesktopPanel<WsdlLoadTest> implements PropertyChangeListener
83  {
84  	private static final String SECONDS_LIMIT = "Seconds";
85  	private static final String RUNS_LIMIT = "Total Runs";
86  	private static final String RUNS_PER_THREAD_LIMIT = "Runs per Thread";
87  	private JPanel contentPanel;
88  	@SuppressWarnings( "unused" )
89  	private JSplitPane mainSplit;
90  	@SuppressWarnings( "unused" )
91  	private JTabbedPane mainTabs;
92  	@SuppressWarnings( "unused" )
93  	private JPanel graphPanel;
94  	protected JButton runButton;
95  	protected JButton cancelButton;
96  	protected JButton statisticsGraphButton;
97  	private WsdlLoadTestRunner runner;
98  	protected JSpinner threadsSpinner;
99  	private LoadTestRunListener internalLoadTestListener = new InternalLoadTestListener();
100 	protected JComboBox strategyCombo;
101 	protected JPanel loadStrategyConfigurationPanel;
102 	protected JButton resetButton;
103 	private LoadTestLog loadTestLog;
104 	protected JButton optionsButton;
105 	protected JButton testTimesGraphButton;
106 	@SuppressWarnings( "unused" )
107 	private Object limit;
108 	private JSpinner limitSpinner;
109 	private JComboBox limitTypeCombo;
110 	private SpinnerNumberModel limitSpinnerModel;
111 	protected JProgressBar progressBar;
112 	private long loadTestStartTime;
113 	private StatisticsDesktopPanel statisticsDesktopPanel;
114 	private StatisticsHistoryDesktopPanel statisticsHistoryDesktopPanel;
115 
116 	public boolean loadTestIsRunning;
117 	private InternalDesktopListener desktopListener;
118 	protected JButton exportButton;
119 	private JLoadTestAssertionsTable assertionsTable;
120 	private JStatisticsTable statisticsTable;
121 	private GroovyEditorComponent tearDownGroovyEditor;
122 	private GroovyEditorComponent setupGroovyEditor;
123 	private JInspectorPanel inspectorPanel;
124 
125 	public WsdlLoadTestDesktopPanel( WsdlLoadTest loadTest )
126 	{
127 		super( loadTest );
128 
129 		loadTestLog = loadTest.getLoadTestLog();
130 		loadTest.addPropertyChangeListener( this );
131 		loadTest.addLoadTestRunListener( internalLoadTestListener );
132 
133 		desktopListener = new InternalDesktopListener();
134 		SoapUI.getDesktop().addDesktopListener( desktopListener );
135 
136 		buildUI();
137 	}
138 
139 	private void buildUI()
140 	{
141 		contentPanel = new JPanel( new BorderLayout() );
142 
143 		contentPanel.add( buildToolbar(), BorderLayout.NORTH );
144 		contentPanel.add( buildContent(), BorderLayout.CENTER );
145 
146 		contentPanel.setPreferredSize( new Dimension( 600, 500 ) );
147 	}
148 
149 	private JComponent buildContent()
150 	{
151 		inspectorPanel = JInspectorPanelFactory.build( buildStatistics() );
152 		addInspectors( inspectorPanel );
153 		inspectorPanel.setDefaultDividerLocation( 0.6F );
154 		inspectorPanel.setCurrentInspector( "LoadTest Log" );
155 
156 		return inspectorPanel.getComponent();
157 	}
158 
159 	protected void addInspectors(JInspectorPanel inspectorPanel)
160 	{
161 		inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildLog(), "LoadTest Log",
162 				"The current LoadTest execution log", true ) );
163 		inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildAssertions(), "LoadTest Assertions",
164 				"The assertions for this LoadTest", true ) );
165 		inspectorPanel.addInspector( new GroovyEditorInspector( buildSetupScriptPanel(), "Setup Script",
166 				"Script to run before tunning a TestCase" ) );
167 		inspectorPanel.addInspector( new GroovyEditorInspector( buildTearDownScriptPanel(), "TearDown Script",
168 				"Script to run after a TestCase Run" ) );
169 	}
170 
171 	protected GroovyEditorComponent buildTearDownScriptPanel()
172 	{
173 		tearDownGroovyEditor = new GroovyEditorComponent( new TearDownScriptGroovyEditorModel(), null );
174 		return tearDownGroovyEditor;
175 	}
176 
177 	protected GroovyEditorComponent buildSetupScriptPanel()
178 	{
179 		setupGroovyEditor = new GroovyEditorComponent( new SetupScriptGroovyEditorModel(), null );
180 		return setupGroovyEditor;
181 	}
182 
183 	protected JComponent buildStatistics()
184 	{
185 		statisticsTable = new JStatisticsTable( getModelItem() );
186 		return statisticsTable;
187 	}
188 
189 	protected JComponent buildLog()
190 	{
191 		JLoadTestLogTable loadTestLogTable = new JLoadTestLogTable( loadTestLog );
192 		return loadTestLogTable;
193 	}
194 
195 	protected JComponent buildAssertions()
196 	{
197 		assertionsTable = new JLoadTestAssertionsTable( getModelItem() );
198 		return assertionsTable;
199 	}
200 
201 	protected JComponent buildToolbar()
202 	{
203 		WsdlLoadTest loadTest = getModelItem();
204 
205 		JXToolBar toolbar = UISupport.createToolbar();
206 
207 		// ButtonBarBuilder builder = new ButtonBarBuilder();
208 		runButton = UISupport.createToolbarButton( new RunLoadTestAction() );
209 		cancelButton = UISupport.createToolbarButton( new CancelRunTestCaseAction(), false );
210 		resetButton = UISupport.createToolbarButton( new ResetAction() );
211 		exportButton = UISupport.createToolbarButton( new ExportStatisticsAction( loadTest.getStatisticsModel() ) );
212 
213 		statisticsGraphButton = UISupport.createToolbarButton( new ShowStatisticsGraphAction() );
214 		testTimesGraphButton = UISupport.createToolbarButton( new ShowTestTimesGraphAction() );
215 
216 		statisticsGraphButton.setEnabled( getModelItem().getHistoryLimit() != 0 );
217 		testTimesGraphButton.setEnabled( getModelItem().getHistoryLimit() != 0 );
218 
219 		AbstractAction optionsDelegate = SwingActionDelegate.createDelegate( LoadTestOptionsAction.SOAPUI_ACTION_ID,
220 				loadTest );
221 		optionsDelegate.putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ) );
222 		optionsButton = UISupport.createToolbarButton( optionsDelegate );
223 
224 		strategyCombo = new JComboBox( LoadStrategyRegistry.getInstance().getStrategies() );
225 		strategyCombo.setToolTipText( "Selects which LoadTest Strategy to use" );
226 		UISupport.setPreferredHeight( strategyCombo, 18 );
227 		strategyCombo.setSelectedItem( loadTest.getLoadStrategy().getType() );
228 		strategyCombo.addItemListener( new ItemListener()
229 		{
230 			public void itemStateChanged( ItemEvent e )
231 			{
232 				Object item = e.getItem();
233 				if( item == null )
234 					return;
235 
236 				setLoadStrategy( item.toString() );
237 			}
238 		} );
239 
240 		toolbar.add( runButton );
241 		toolbar.add( cancelButton );
242 		toolbar.add( statisticsGraphButton );
243 		toolbar.add( testTimesGraphButton );
244 		toolbar.add( resetButton );
245 		toolbar.add( exportButton );
246 
247 		toolbar.add( optionsButton );
248 		toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.LOADTESTEDITOR_HELP_URL ) ) );
249 		toolbar.add( Box.createHorizontalGlue() );
250 		buildLimitBar( toolbar );
251 		toolbar.addSeparator();
252 
253 		progressBar = new JProgressBar( 0, 100 );
254 		progressBar.setPreferredSize( new Dimension( 70, 20 ) );
255 
256 		toolbar.addFixed( progressBar );
257 
258 		ButtonBarBuilder builder = new ButtonBarBuilder();
259 
260 		builder.addFixed( new JLabel( "Threads:" ) );
261 		builder.addRelatedGap();
262 
263 		threadsSpinner = new JSpinner( new SpinnerNumberModel( getModelItem().getThreadCount(), 1, 9999, 1 ) );
264 		threadsSpinner.setToolTipText( "Sets the number of threads (\"Virtual Users\") to run this TestCase" );
265 		UISupport.setPreferredHeight( threadsSpinner, 18 );
266 		threadsSpinner.getModel().addChangeListener( new ChangeListener()
267 		{
268 
269 			public void stateChanged( ChangeEvent e )
270 			{
271 				getModelItem().setThreadCount( ( ( SpinnerNumberModel )threadsSpinner.getModel() ).getNumber().intValue() );
272 			}
273 		} );
274 
275 		builder.addFixed( threadsSpinner );
276 		builder.addUnrelatedGap();
277 
278 		LoadStrategy loadStrategy = loadTest.getLoadStrategy();
279 
280 		builder.addFixed( new JLabel( "Strategy" ) );
281 		builder.addRelatedGap();
282 		builder.addFixed( strategyCombo );
283 		builder.addUnrelatedGap();
284 
285 		loadStrategyConfigurationPanel = new JPanel( new BorderLayout() );
286 		loadStrategyConfigurationPanel.add( loadStrategy.getConfigurationPanel(), BorderLayout.CENTER );
287 
288 		builder.addFixed( loadStrategyConfigurationPanel );
289 		builder.setBorder( BorderFactory.createEmptyBorder( 2, 3, 3, 3 ) );
290 
291 		return UISupport.buildPanelWithToolbar( toolbar, builder.getPanel() );
292 	}
293 
294 	public void buildLimitBar( JXToolBar toolbar )
295 	{
296 		limitSpinnerModel = new SpinnerNumberModel( getModelItem().getTestLimit(), 0, Long.MAX_VALUE, 100 );
297 
298 		limitSpinner = new JSpinner( limitSpinnerModel );
299 		limitSpinner.setPreferredSize( new Dimension( 70, 20 ) );
300 		limitSpinner.setToolTipText( "Sets the limit for this test; total number of requests or seconds to run" );
301 		limitSpinner.getModel().addChangeListener( new ChangeListener()
302 		{
303 
304 			public void stateChanged( ChangeEvent e )
305 			{
306 				int intValue = ( ( SpinnerNumberModel )limitSpinner.getModel() ).getNumber().intValue();
307 				getModelItem().setTestLimit( intValue );
308 			}
309 		} );
310 
311 		toolbar.addSeparator();
312 		toolbar.addFixed( new JLabel( "Limit:" ) );
313 		toolbar.addSeparator();
314 		toolbar.addFixed( limitSpinner );
315 		toolbar.addSeparator();
316 
317 		limitTypeCombo = new JComboBox( new String[] { WsdlLoadTestDesktopPanel.RUNS_LIMIT,
318 				WsdlLoadTestDesktopPanel.SECONDS_LIMIT, WsdlLoadTestDesktopPanel.RUNS_PER_THREAD_LIMIT } );
319 
320 		if( getModelItem().getLimitType() == LoadTestLimitTypesConfig.TIME )
321 			limitTypeCombo.setSelectedIndex( 1 );
322 
323 		toolbar.addFixed( limitTypeCombo );
324 		toolbar.addSeparator();
325 
326 		limitTypeCombo.addItemListener( new ItemListener()
327 		{
328 			public void itemStateChanged( ItemEvent e )
329 			{
330 				Object item = e.getItem();
331 				if( WsdlLoadTestDesktopPanel.RUNS_LIMIT.equals( item ) )
332 				{
333 					getModelItem().setLimitType( LoadTestLimitTypesConfig.COUNT );
334 				}
335 				else if( WsdlLoadTestDesktopPanel.SECONDS_LIMIT.equals( item ) )
336 				{
337 					getModelItem().setLimitType( LoadTestLimitTypesConfig.TIME );
338 				}
339 				else if( WsdlLoadTestDesktopPanel.RUNS_PER_THREAD_LIMIT.equals( item ) )
340 				{
341 					getModelItem().setLimitType( LoadTestLimitTypesConfig.COUNT_PER_THREAD );
342 				}
343 			}
344 		} );
345 	}
346 
347 	public boolean onClose( boolean canCancel )
348 	{
349 		if( runner != null && runner.getStatus() == Status.RUNNING )
350 		{
351 			if( !UISupport.confirm( "Running test will be canceled when closing window. Close anyway?", "Close LoadTest" ) )
352 				return false;
353 		}
354 
355 		getModelItem().removeLoadTestRunListener( internalLoadTestListener );
356 		getModelItem().removePropertyChangeListener( this );
357 		getModelItem().getStatisticsModel().reset();
358 
359 		if( runner != null && runner.getStatus() == Status.RUNNING )
360 			runner.cancel( "closing window" );
361 
362 		if( statisticsDesktopPanel != null )
363 			SoapUI.getDesktop().closeDesktopPanel( statisticsDesktopPanel );
364 
365 		if( statisticsHistoryDesktopPanel != null )
366 			SoapUI.getDesktop().closeDesktopPanel( statisticsHistoryDesktopPanel );
367 
368 		assertionsTable.release();
369 		loadStrategyConfigurationPanel.removeAll();
370 		SoapUI.getDesktop().removeDesktopListener( desktopListener );
371 
372 		statisticsTable.release();
373 		inspectorPanel.release();
374 
375 		return release();
376 	}
377 
378 	public JComponent getComponent()
379 	{
380 		return contentPanel;
381 	}
382 
383 	private final class InternalDesktopListener extends DesktopListenerAdapter
384 	{
385 		public void desktopPanelClosed( DesktopPanel desktopPanel )
386 		{
387 			if( desktopPanel == statisticsDesktopPanel )
388 				statisticsDesktopPanel = null;
389 			else if( desktopPanel == statisticsHistoryDesktopPanel )
390 				statisticsHistoryDesktopPanel = null;
391 		}
392 	}
393 
394 	public class RunLoadTestAction extends AbstractAction
395 	{
396 		public RunLoadTestAction()
397 		{
398 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_testcase.gif" ) );
399 			putValue( Action.SHORT_DESCRIPTION, "Runs this LoadTest" );
400 		}
401 
402 		public void actionPerformed( ActionEvent e )
403 		{
404 			WsdlLoadTest loadtest = getModelItem();
405 			if( loadtest.getTestCase().getTestStepCount() == 0 )
406 			{
407 				UISupport.showErrorMessage( "Missing TestSteps for testing!" );
408 				return;
409 			}
410 
411 			if( loadtest.getLimitType() != LoadTestLimitTypesConfig.TIME
412 					&& loadtest.getTestLimit() < loadtest.getThreadCount() )
413 			{
414 				if( !UISupport.confirm( "The run limit is set to a lower count than number of threads\nRun Anyway?",
415 						"Run LoadTest" ) )
416 				{
417 					return;
418 				}
419 			}
420 
421 			runButton.setEnabled( false );
422 			runner = loadtest.run();
423 		}
424 	}
425 
426 	public class ResetAction extends AbstractAction
427 	{
428 		public ResetAction()
429 		{
430 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/reset_loadtest_statistics.gif" ) );
431 			putValue( Action.SHORT_DESCRIPTION, "Resets statistics for this LoadTest" );
432 		}
433 
434 		public void actionPerformed( ActionEvent e )
435 		{
436 			getModelItem().getStatisticsModel().reset();
437 		}
438 	}
439 
440 	public class ShowStatisticsGraphAction extends AbstractAction
441 	{
442 		public ShowStatisticsGraphAction()
443 		{
444 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/stats_graph.gif" ) );
445 			putValue( Action.SHORT_DESCRIPTION, "Shows the statistics graph" );
446 		}
447 
448 		public void actionPerformed( ActionEvent e )
449 		{
450 			if( statisticsDesktopPanel == null )
451 				statisticsDesktopPanel = new StatisticsDesktopPanel( getModelItem() );
452 
453 			UISupport.showDesktopPanel( statisticsDesktopPanel );
454 		}
455 	}
456 
457 	public class ShowTestTimesGraphAction extends AbstractAction
458 	{
459 		public ShowTestTimesGraphAction()
460 		{
461 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/samples_graph.gif" ) );
462 			putValue( Action.SHORT_DESCRIPTION, "Shows the Statistics History graph" );
463 		}
464 
465 		public void actionPerformed( ActionEvent e )
466 		{
467 			if( statisticsHistoryDesktopPanel == null )
468 				statisticsHistoryDesktopPanel = new StatisticsHistoryDesktopPanel( getModelItem() );
469 
470 			UISupport.showDesktopPanel( statisticsHistoryDesktopPanel );
471 		}
472 	}
473 
474 	public class CancelRunTestCaseAction extends AbstractAction
475 	{
476 
477 		public CancelRunTestCaseAction()
478 		{
479 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/stop_testcase.gif" ) );
480 			putValue( Action.SHORT_DESCRIPTION, "Stops running this LoadTest" );
481 		}
482 
483 		public void actionPerformed( ActionEvent e )
484 		{
485 			if( runner != null )
486 			{
487 				runner.cancel( "Canceled" );
488 				cancelButton.setEnabled( false );
489 			}
490 		}
491 	}
492 
493 	public boolean dependsOn( ModelItem modelItem )
494 	{
495 		WsdlLoadTest loadTest = getModelItem();
496 
497 		return modelItem == loadTest || modelItem == loadTest.getTestCase()
498 				|| modelItem == loadTest.getTestCase().getTestSuite()
499 				|| modelItem == loadTest.getTestCase().getTestSuite().getProject();
500 	}
501 
502 	public void setLoadStrategy( String type )
503 	{
504 		LoadStrategyFactory factory = LoadStrategyRegistry.getInstance().getFactory( type );
505 		LoadStrategy loadStrategy = factory.create( getModelItem() );
506 		getModelItem().setLoadStrategy( loadStrategy );
507 		loadStrategyConfigurationPanel.removeAll();
508 		loadStrategyConfigurationPanel.add( loadStrategy.getConfigurationPanel(), BorderLayout.CENTER );
509 		loadStrategyConfigurationPanel.revalidate();
510 	}
511 
512 	private class InternalLoadTestListener extends LoadTestRunListenerAdapter
513 	{
514 		public void beforeLoadTest( LoadTestRunner testRunner, LoadTestRunContext context )
515 		{
516 			loadTestLog.clear();
517 
518 			loadTestStartTime = System.currentTimeMillis();
519 			loadTestIsRunning = true;
520 			if( getModelItem().getTestLimit() > 0 )
521 			{
522 				progressBar.setValue( 0 );
523 				progressBar.setString( null );
524 			}
525 			else
526 			{
527 				progressBar.setString( "..." );
528 			}
529 
530 			progressBar.setStringPainted( true );
531 
532 			runButton.setEnabled( false );
533 			cancelButton.setEnabled( true );
534 			strategyCombo.setEnabled( false );
535 			limitTypeCombo.setEnabled( false );
536 			optionsButton.setEnabled( false );
537 			threadsSpinner.setEnabled( getModelItem().getLoadStrategy().allowThreadCountChangeDuringRun() );
538 
539 			new Thread( new ProgressBarUpdater(), getModelItem().getName() + " ProgressBarUpdater" ).start();
540 		}
541 
542 		public void afterLoadTest( LoadTestRunner testRunner, LoadTestRunContext context )
543 		{
544 			runButton.setEnabled( true );
545 
546 			cancelButton.setEnabled( false );
547 			strategyCombo.setEnabled( true );
548 			limitTypeCombo.setEnabled( true );
549 			threadsSpinner.setEnabled( true );
550 			optionsButton.setEnabled( true );
551 
552 			runner = null;
553 			loadTestIsRunning = false;
554 
555 			if( progressBar.isIndeterminate() )
556 			{
557 				progressBar.setIndeterminate( false );
558 				progressBar.setValue( 0 );
559 			}
560 			else if( testRunner.getStatus() == Status.FINISHED )
561 			{
562 				progressBar.setValue( 100 );
563 			}
564 
565 			if( testRunner.getStatus() == Status.FAILED )
566 			{
567 				UISupport.showErrorMessage( "LoadTest failed; " + testRunner.getReason() );
568 			}
569 		}
570 
571 	}
572 
573 	private class ProgressBarUpdater implements Runnable
574 	{
575 		public void run()
576 		{
577 			while( true )
578 			{
579 				if( !loadTestIsRunning )
580 					break;
581 
582 				if( getModelItem().getTestLimit() == 0 )
583 				{
584 					if( loadTestIsRunning && !progressBar.isIndeterminate() )
585 					{
586 						progressBar.setIndeterminate( true );
587 						progressBar.setString( "..." );
588 					}
589 				}
590 				else if( getModelItem().getLimitType() == LoadTestLimitTypesConfig.TIME )
591 				{
592 					if( loadTestIsRunning && progressBar.isIndeterminate() )
593 					{
594 						progressBar.setIndeterminate( false );
595 						progressBar.setString( null );
596 					}
597 
598 					long timePassed = System.currentTimeMillis() - loadTestStartTime;
599 					int value = ( int )( ( timePassed * 100 ) / ( getModelItem().getTestLimit() * 1000 ) );
600 					progressBar.setValue( value );
601 				}
602 				else if( getModelItem().getLimitType() == LoadTestLimitTypesConfig.COUNT || 
603 						getModelItem().getLimitType() == LoadTestLimitTypesConfig.COUNT_PER_THREAD )
604 				{
605 					if( loadTestIsRunning && progressBar.isIndeterminate() )
606 					{
607 						progressBar.setIndeterminate( false );
608 						progressBar.setString( null );
609 					}
610 
611 					long counts = getModelItem().getStatisticsModel().getStatistic( LoadTestStatistics.TOTAL,
612 							Statistic.COUNT );
613 					if( counts > 0 )
614 						progressBar.setValue( ( int )( ( counts * 100 ) / getModelItem().getTestLimit() ) );
615 				}
616 
617 				try
618 				{
619 					Thread.sleep( 500 );
620 				}
621 				catch( InterruptedException e )
622 				{
623 					SoapUI.logError( e );
624 				}
625 			}
626 		}
627 	}
628 
629 	public void propertyChange( PropertyChangeEvent evt )
630 	{
631 		if( evt.getPropertyName().equals( WsdlLoadTest.THREADCOUNT_PROPERTY ) )
632 		{
633 			threadsSpinner.setValue( evt.getNewValue() );
634 		}
635 		else if( evt.getPropertyName().equals( WsdlLoadTest.HISTORYLIMIT_PROPERTY ) )
636 		{
637 			long lng = ( Long )evt.getNewValue();
638 
639 			statisticsGraphButton.setEnabled( lng != 0 );
640 			testTimesGraphButton.setEnabled( lng != 0 );
641 		}
642 	}
643 
644 	private class SetupScriptGroovyEditorModel extends AbstractGroovyEditorModel
645 	{
646 		@Override
647 		public Action createRunAction()
648 		{
649 			return new AbstractAction()
650 			{
651 
652 				public void actionPerformed( ActionEvent e )
653 				{
654 					try
655 					{
656 						MockLoadTestRunner mockTestRunner = new MockLoadTestRunner( getModelItem(), SoapUI.ensureGroovyLog() );
657 						getModelItem().runSetupScript( new MockLoadTestRunContext( mockTestRunner ), mockTestRunner );
658 					}
659 					catch( Exception e1 )
660 					{
661 						UISupport.showErrorMessage( e1 );
662 					}
663 				}
664 			};
665 		}
666 
667 		public SetupScriptGroovyEditorModel()
668 		{
669 			super( new String[] { "log", "context", "loadTestRunner" }, getModelItem().getSettings(), "Setup" );
670 		}
671 
672 		public String getScript()
673 		{
674 			return getModelItem().getSetupScript();
675 		}
676 
677 		public void setScript( String text )
678 		{
679 			getModelItem().setSetupScript( text );
680 		}
681 	}
682 
683 	private class TearDownScriptGroovyEditorModel extends AbstractGroovyEditorModel
684 	{
685 		@Override
686 		public Action createRunAction()
687 		{
688 			return new AbstractAction()
689 			{
690 
691 				public void actionPerformed( ActionEvent e )
692 				{
693 					try
694 					{
695 						MockLoadTestRunner mockTestRunner = new MockLoadTestRunner( getModelItem(), SoapUI.ensureGroovyLog() );
696 						getModelItem().runTearDownScript( new MockLoadTestRunContext( mockTestRunner ), mockTestRunner );
697 					}
698 					catch( Exception e1 )
699 					{
700 						UISupport.showErrorMessage( e1 );
701 					}
702 				}
703 			};
704 		}
705 
706 		public TearDownScriptGroovyEditorModel()
707 		{
708 			super( new String[] { "log", "context", "loadTestRunner" }, getModelItem().getSettings(), "TearDown" );
709 		}
710 
711 		public String getScript()
712 		{
713 			return getModelItem().getTearDownScript();
714 		}
715 
716 		public void setScript( String text )
717 		{
718 			getModelItem().setTearDownScript( text );
719 		}
720 	}
721 }