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