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