View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 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.testcase;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.config.TestStepConfig;
17  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
18  import com.eviware.soapui.impl.wsdl.actions.testcase.AddNewLoadTestAction;
19  import com.eviware.soapui.impl.wsdl.actions.testcase.TestCaseOptionsAction;
20  import com.eviware.soapui.impl.wsdl.panels.support.MockTestRunContext;
21  import com.eviware.soapui.impl.wsdl.panels.support.MockTestRunner;
22  import com.eviware.soapui.impl.wsdl.panels.support.ProgressBarTestCaseAdapter;
23  import com.eviware.soapui.impl.wsdl.panels.testcase.actions.SetCredentialsAction;
24  import com.eviware.soapui.impl.wsdl.panels.testcase.actions.SetEndpointAction;
25  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.AbstractGroovyEditorModel;
26  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.PropertyHolderTable;
27  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
28  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
29  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner;
30  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep;
31  import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestStepFactory;
32  import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestStepRegistry;
33  import com.eviware.soapui.model.ModelItem;
34  import com.eviware.soapui.model.support.TestRunListenerAdapter;
35  import com.eviware.soapui.model.testsuite.*;
36  import com.eviware.soapui.monitor.support.TestMonitorListenerAdapter;
37  import com.eviware.soapui.settings.UISettings;
38  import com.eviware.soapui.support.DocumentListenerAdapter;
39  import com.eviware.soapui.support.StringUtils;
40  import com.eviware.soapui.support.UISupport;
41  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
42  import com.eviware.soapui.support.components.*;
43  import com.eviware.soapui.support.dnd.DropType;
44  import com.eviware.soapui.support.dnd.JListDragAndDropable;
45  import com.eviware.soapui.support.dnd.SoapUIDragAndDropHandler;
46  import com.eviware.soapui.support.swing.ComponentBag;
47  import com.eviware.soapui.support.types.StringToObjectMap;
48  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
49  
50  import javax.swing.*;
51  import javax.swing.text.Document;
52  import java.awt.*;
53  import java.awt.dnd.DnDConstants;
54  import java.awt.dnd.DragSource;
55  import java.awt.event.ActionEvent;
56  import java.text.SimpleDateFormat;
57  import java.util.Date;
58  
59  /***
60   * WsdlTestCase desktop panel
61   *
62   * @author Ole.Matzura
63   */
64  
65  public class WsdlTestCaseDesktopPanel extends ModelItemDesktopPanel<WsdlTestCase>
66  {
67     private JProgressBar progressBar;
68     private TestStepList testStepList;
69     private InternalTestRunListener testRunListener = new InternalTestRunListener();
70     private JButton runButton;
71     private JButton cancelButton;
72     private TestRunner runner;
73     private JButton setEndpointButton;
74     private JButton setCredentialsButton;
75     private JButton optionsButton;
76     private ComponentBag stateDependantComponents = new ComponentBag();
77     private TestRunLog testCaseLog;
78     private JToggleButton loopButton;
79     @SuppressWarnings( "unused" )
80     private ProgressBarTestCaseAdapter progressBarAdapter;
81     private InternalTestMonitorListener testMonitorListener;
82     public boolean canceled;
83     private JTextArea descriptionArea;
84     private PropertyHolderTable propertiesTable;
85     private GroovyEditorComponent tearDownGroovyEditor;
86     private GroovyEditorComponent setupGroovyEditor;
87     private JInspectorPanel testStepListInspectorPanel;
88     private JButton createLoadTestButton;
89  
90     public WsdlTestCaseDesktopPanel( WsdlTestCase testCase )
91     {
92        super( testCase );
93  
94        buildUI();
95  
96        setPreferredSize( new Dimension( 400, 550 ) );
97        setRunningState();
98  
99        testCase.addTestRunListener( testRunListener );
100       progressBarAdapter = new ProgressBarTestCaseAdapter( progressBar, testCase );
101       testMonitorListener = new InternalTestMonitorListener();
102 
103       SoapUI.getTestMonitor().addTestMonitorListener( testMonitorListener );
104 
105       DragSource dragSource = DragSource.getDefaultDragSource();
106       SoapUIDragAndDropHandler dragAndDropHandler = new SoapUIDragAndDropHandler(
107               new ModelItemListDragAndDropable( getTestStepList().getTestStepList(), testCase ), DropType.BEFORE_AND_AFTER );
108 
109       dragSource.createDefaultDragGestureRecognizer( getTestStepList().getTestStepList(), DnDConstants.ACTION_COPY_OR_MOVE,
110               dragAndDropHandler );
111    }
112 
113    /***
114     * There are three states: - enabled, no testcases or testschedules running -
115     * enabled, standalone testcase running - disabled, testschedule is running
116     */
117 
118    private void setRunningState()
119    {
120       stateDependantComponents.setEnabled( !SoapUI.getTestMonitor().hasRunningLoadTest( getModelItem() ) );
121    }
122 
123    private void buildUI()
124    {
125       JPanel panel = new JPanel( new BorderLayout() );
126 
127       panel.add( buildToolbar(), BorderLayout.PAGE_START );
128       panel.add( buildRunnerBar(), BorderLayout.CENTER );
129 
130       add( panel, BorderLayout.NORTH );
131 
132       JInspectorPanel inspectorPanel = JInspectorPanelFactory.build( buildContent() );
133       inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildTestLog(), "TestCase Log", "TestCase Execution Log", true ) );
134       inspectorPanel.setDefaultDividerLocation( 0.7F );
135       inspectorPanel.setCurrentInspector( "TestCase Log" );
136 
137       if( StringUtils.hasContent( getModelItem().getDescription() ) && getModelItem().getSettings().getBoolean( UISettings.SHOW_DESCRIPTIONS ) )
138       {
139          testStepListInspectorPanel.setCurrentInspector( "Description" );
140       }
141 
142       add( inspectorPanel.getComponent(), BorderLayout.CENTER );
143    }
144 
145    protected TestStepList getTestStepList()
146    {
147       return testStepList;
148    }
149 
150    private JComponent buildTestLog()
151    {
152       testCaseLog = new TestCaseTestRunLog( getModelItem() );
153       stateDependantComponents.add( testCaseLog );
154       return testCaseLog;
155    }
156 
157    private JComponent buildContent()
158    {
159       JTabbedPane tabs = new JTabbedPane( JTabbedPane.TOP );
160       testStepListInspectorPanel = JInspectorPanelFactory.build( buildTestStepList(),
161               SwingConstants.BOTTOM );
162 
163       tabs.addTab( "TestSteps", testStepListInspectorPanel.getComponent() );
164 
165       addTabs( tabs, testStepListInspectorPanel );
166       tabs.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
167 
168       return UISupport.createTabPanel( tabs, true );
169    }
170 
171    protected JComponent buildTestStepList()
172    {
173       JPanel p = new JPanel( new BorderLayout() );
174       JXToolBar toolbar = UISupport.createToolbar();
175 
176       WsdlTestStepFactory[] factories = WsdlTestStepRegistry.getInstance().getFactories();
177       for( WsdlTestStepFactory factory : factories )
178       {
179          toolbar.addFixed( UISupport.createToolbarButton( new AddWsdlTestStepAction( factory ) ) );
180       }
181 
182       p.add( toolbar, BorderLayout.NORTH );
183       testStepList = new TestStepList( getModelItem() );
184       stateDependantComponents.add( testStepList );
185 
186       p.add( new JScrollPane( testStepList ), BorderLayout.CENTER );
187 
188       return p;
189    }
190 
191    protected void addTabs( JTabbedPane tabs, JInspectorPanel inspectorPanel )
192    {
193       inspectorPanel.addInspector( new JFocusableComponentInspector<JPanel>( buildDescriptionPanel(),
194               descriptionArea, "Description", "TestCase Description", true ) );
195       inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildPropertiesPanel(), "Properties", "TestCase level properties", true ) );
196       inspectorPanel.addInspector( new GroovyEditorInspector( buildSetupScriptPanel(), "Setup Script", "Script to run before tunning a TestCase" ) );
197       inspectorPanel.addInspector( new GroovyEditorInspector( buildTearDownScriptPanel(), "TearDown Script", "Script to run after a TestCase Run" ) );
198    }
199 
200    protected GroovyEditorComponent buildTearDownScriptPanel()
201    {
202       tearDownGroovyEditor = new GroovyEditorComponent( new TearDownScriptGroovyEditorModel(), null );
203       return tearDownGroovyEditor;
204    }
205 
206    protected GroovyEditorComponent buildSetupScriptPanel()
207    {
208       setupGroovyEditor = new GroovyEditorComponent( new SetupScriptGroovyEditorModel(), null );
209       return setupGroovyEditor;
210    }
211 
212    protected JComponent buildPropertiesPanel()
213    {
214       JPanel panel = new JPanel( new BorderLayout() );
215       propertiesTable = buildPropertiesTable();
216       panel.add( new JScrollPane( propertiesTable ), BorderLayout.CENTER );
217       return panel;
218    }
219 
220    protected PropertyHolderTable buildPropertiesTable()
221    {
222       return new PropertyHolderTable( getModelItem() );
223    }
224 
225    private JPanel buildDescriptionPanel()
226    {
227       JPanel panel = new JPanel( new BorderLayout() );
228       descriptionArea = new JUndoableTextArea( getModelItem().getDescription() );
229       descriptionArea.getDocument().addDocumentListener( new DocumentListenerAdapter()
230       {
231          public void update( Document document )
232          {
233             getModelItem().setDescription( descriptionArea.getText() );
234          }
235       } );
236 
237       panel.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
238       panel.add( new JScrollPane( descriptionArea ), BorderLayout.CENTER );
239       UISupport.addTitledBorder( panel, "TestCase Description" );
240 
241       return panel;
242    }
243 
244    private Component buildToolbar()
245    {
246       JToolBar toolbar = UISupport.createToolbar();
247 
248       runButton = UISupport.createToolbarButton( new RunTestCaseAction() );
249       optionsButton = UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
250               TestCaseOptionsAction.SOAPUI_ACTION_ID, getModelItem(), null, "/options.gif" ) );
251       optionsButton.setText( null );
252       cancelButton = UISupport.createToolbarButton( new CancelRunTestCaseAction(), false );
253 
254       loopButton = new JToggleButton( UISupport.createImageIcon( "/loop.gif" ) );
255       loopButton.setPreferredSize( UISupport.getPreferredButtonSize() );
256       loopButton.setToolTipText( "Loop TestCase continuously" );
257 
258       setCredentialsButton = UISupport.createToolbarButton( new SetCredentialsAction( getModelItem() ) );
259       setEndpointButton = UISupport.createToolbarButton( new SetEndpointAction( getModelItem() ) );
260 
261       stateDependantComponents.add( runButton );
262       stateDependantComponents.add( optionsButton );
263       stateDependantComponents.add( cancelButton );
264       stateDependantComponents.add( setCredentialsButton );
265       stateDependantComponents.add( setEndpointButton );
266 
267       createLoadTestButton = UISupport.createToolbarButton( SwingActionDelegate.createDelegate(
268               AddNewLoadTestAction.SOAPUI_ACTION_ID, getModelItem(), null, "/loadtest.gif" ) );
269 
270       addToolbarActions( toolbar );
271 
272       toolbar.add( Box.createHorizontalGlue() );
273       toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TESTCASEEDITOR_HELP_URL ) ) );
274 
275       return toolbar;
276    }
277 
278    protected void addToolbarActions( JToolBar toolbar )
279    {
280       toolbar.add( runButton );
281       toolbar.add( cancelButton );
282       toolbar.add( loopButton );
283       toolbar.addSeparator( );
284       toolbar.add( setCredentialsButton );
285       toolbar.add( setEndpointButton );
286       toolbar.addSeparator( );
287       toolbar.add( createLoadTestButton );
288       toolbar.addSeparator( );
289       toolbar.add( optionsButton );
290    }
291 
292    private Component buildRunnerBar()
293    {
294       progressBar = new JProgressBar( 0, getModelItem().getTestStepCount() );
295       return UISupport.createProgressBarPanel( progressBar, 10, false );
296    }
297 
298    private final class InternalTestMonitorListener extends TestMonitorListenerAdapter
299    {
300       public void loadTestStarted( LoadTestRunner runner )
301       {
302          setRunningState();
303       }
304 
305       public void loadTestFinished( LoadTestRunner runner )
306       {
307          setRunningState();
308       }
309    }
310 
311    public class InternalTestRunListener extends TestRunListenerAdapter
312    {
313       private SimpleDateFormat dateFormat;
314 
315       public InternalTestRunListener()
316       {
317          dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS" );
318       }
319 
320       public void beforeRun( TestRunner testRunner, TestRunContext runContext )
321       {
322          if( SoapUI.getTestMonitor().hasRunningLoadTest( getModelItem() ) )
323             return;
324 
325          runButton.setEnabled( false );
326          cancelButton.setEnabled( true );
327          testStepList.setEnabled( false );
328          testStepList.setSelectedIndex( -1 );
329          testCaseLog.clear();
330 
331          testCaseLog.addText( "Test started at " + dateFormat.format( new Date() ) );
332 
333          WsdlTestCaseDesktopPanel.this.beforeRun();
334 
335          if( runner == null )
336             runner = testRunner;
337       }
338 
339       public void beforeStep( TestRunner testRunner, TestRunContext runContext )
340       {
341          if( SoapUI.getTestMonitor().hasRunningLoadTest( getModelItem() ) )
342             return;
343 
344          TestStep testStep = runContext.getCurrentStep();
345          testStepList.setSelectedValue( testStep, true );
346       }
347 
348       public void afterRun( TestRunner testRunner, TestRunContext runContext )
349       {
350          if( SoapUI.getTestMonitor().hasRunningLoadTest( getModelItem() ) )
351             return;
352 
353          WsdlTestCaseRunner wsdlRunner = (WsdlTestCaseRunner) testRunner;
354 
355          if( testRunner.getStatus() == TestRunner.Status.CANCELED )
356             testCaseLog.addText( "TestCase canceled [" + testRunner.getReason() + "], time taken = "
357                     + wsdlRunner.getTimeTaken() );
358          else if( testRunner.getStatus() == TestRunner.Status.FAILED )
359          {
360             String msg = wsdlRunner.getReason();
361             if( wsdlRunner.getError() != null )
362             {
363                if( msg != null )
364                   msg += ":";
365 
366                msg += wsdlRunner.getError();
367             }
368 
369             testCaseLog.addText( "TestCase failed [" + msg + "], time taken = "
370                     + wsdlRunner.getTimeTaken() );
371          }
372          else
373             testCaseLog.addText( "TestCase finished with status [" + testRunner.getStatus() + "], time taken = " + wsdlRunner.getTimeTaken() );
374 
375          runner = null;
376 
377          JToggleButton loopButton = (JToggleButton) runContext.getProperty( "loopButton" );
378          if( loopButton != null && loopButton.isSelected() && testRunner.getStatus() == TestRunner.Status.FINISHED )
379          {
380             SwingUtilities.invokeLater( new Runnable()
381             {
382                public void run()
383                {
384                   runTestCase();
385                }
386             } );
387          }
388          else
389          {
390             WsdlTestCaseDesktopPanel.this.afterRun();
391          }
392       }
393 
394       public void afterStep( TestRunner testRunner, TestRunContext runContext, TestStepResult stepResult )
395       {
396          if( SoapUI.getTestMonitor().hasRunningLoadTest( getModelItem() ) )
397             return;
398 
399          testCaseLog.addTestStepResult( stepResult );
400       }
401    }
402 
403    protected void runTestCase()
404    {
405       if( canceled )
406       {
407          // make sure state is correct
408          runButton.setEnabled( true );
409          cancelButton.setEnabled( false );
410          testStepList.setEnabled( true );
411          return;
412       }
413 
414       StringToObjectMap properties = new StringToObjectMap();
415       properties.put( "loopButton", loopButton );
416       runner = getModelItem().run( properties, true );
417    }
418 
419    public class RunTestCaseAction extends AbstractAction
420    {
421       public RunTestCaseAction()
422       {
423          putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_testcase.gif" ) );
424          putValue( Action.SHORT_DESCRIPTION, "Runs this testcase" );
425       }
426 
427       public void actionPerformed( ActionEvent e )
428       {
429          canceled = false;
430          runTestCase();
431       }
432    }
433 
434    public class CancelRunTestCaseAction extends AbstractAction
435    {
436       public CancelRunTestCaseAction()
437       {
438          putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/stop_testcase.gif" ) );
439          putValue( Action.SHORT_DESCRIPTION, "Stops running this testcase" );
440       }
441 
442       public void actionPerformed( ActionEvent e )
443       {
444          if( runner != null )
445             runner.cancel( "canceled in UI" );
446 
447          canceled = true;
448       }
449    }
450 
451    public boolean onClose( boolean canCancel )
452    {
453       if( canCancel )
454       {
455          if( runner != null && runner.getStatus() == TestRunner.Status.RUNNING )
456          {
457             Boolean retval = UISupport.confirmOrCancel( "Cancel running TestCase?", "Cancel Run" );
458 
459             if( retval == null )
460                return false;
461             if( retval.booleanValue() )
462             {
463                runner.cancel( null );
464             }
465          }
466       }
467       else
468       {
469          if( runner != null && runner.getStatus() == TestRunner.Status.RUNNING )
470          {
471             runner.cancel( null );
472          }
473       }
474 
475       SoapUI.getTestMonitor().removeTestMonitorListener( testMonitorListener );
476       getModelItem().removeTestRunListener( testRunListener );
477       testStepList.release();
478       progressBarAdapter.release();
479       propertiesTable.release();
480 
481       setupGroovyEditor.getEditor().release();
482       tearDownGroovyEditor.getEditor().release();
483 
484       testCaseLog.release();
485 
486       return release();
487    }
488 
489    public boolean dependsOn( ModelItem modelItem )
490    {
491       return modelItem == getModelItem() || modelItem == getModelItem().getTestSuite()
492               || modelItem == getModelItem().getTestSuite().getProject();
493    }
494 
495    protected void beforeRun()
496    {
497    }
498 
499    protected void afterRun()
500    {
501       runButton.setEnabled( true );
502       cancelButton.setEnabled( false );
503       testStepList.setEnabled( true );
504    }
505 
506    private class SetupScriptGroovyEditorModel extends AbstractGroovyEditorModel
507    {
508       @Override
509       public Action createRunAction()
510       {
511          return new AbstractAction()
512          {
513 
514             public void actionPerformed( ActionEvent e )
515             {
516                try
517                {
518                   MockTestRunner mockTestRunner = new MockTestRunner( getModelItem(), SoapUI.ensureGroovyLog() );
519                   getModelItem().runSetupScript( new MockTestRunContext( mockTestRunner, null ), mockTestRunner );
520                }
521                catch( Exception e1 )
522                {
523                   UISupport.showErrorMessage( e1 );
524                }
525             }
526          };
527       }
528 
529       public SetupScriptGroovyEditorModel()
530       {
531          super( new String[]{"log", "context", "testRunner"}, getModelItem().getSettings(), "Setup" );
532       }
533 
534       public String getScript()
535       {
536          return getModelItem().getSetupScript();
537       }
538 
539       public void setScript( String text )
540       {
541          getModelItem().setSetupScript( text );
542       }
543    }
544 
545    private class TearDownScriptGroovyEditorModel extends AbstractGroovyEditorModel
546    {
547       @Override
548       public Action createRunAction()
549       {
550          return new AbstractAction()
551          {
552 
553             public void actionPerformed( ActionEvent e )
554             {
555                try
556                {
557                   MockTestRunner mockTestRunner = new MockTestRunner( getModelItem(), SoapUI.ensureGroovyLog() );
558                   getModelItem().runTearDownScript( new MockTestRunContext( mockTestRunner, null ), mockTestRunner );
559                }
560                catch( Exception e1 )
561                {
562                   UISupport.showErrorMessage( e1 );
563                }
564             }
565          };
566       }
567 
568       public TearDownScriptGroovyEditorModel()
569       {
570          super( new String[]{"log", "context", "testRunner"}, getModelItem().getSettings(), "TearDown" );
571       }
572 
573       public String getScript()
574       {
575          return getModelItem().getTearDownScript();
576       }
577 
578       public void setScript( String text )
579       {
580          getModelItem().setTearDownScript( text );
581       }
582    }
583 
584    private class AddWsdlTestStepAction extends AbstractAction
585    {
586       private final WsdlTestStepFactory factory;
587 
588       public AddWsdlTestStepAction( WsdlTestStepFactory factory )
589       {
590          this.factory = factory;
591          putValue( SMALL_ICON, UISupport.createImageIcon( factory.getTestStepIconPath() ) );
592          putValue( SHORT_DESCRIPTION, "Create a new " + factory.getTestStepName() + " TestStep" );
593       }
594 
595       public void actionPerformed( ActionEvent e )
596       {
597          int ix = testStepList.getTestStepList().getSelectedIndex();
598 
599          String name = UISupport.prompt( "Specify name for new step", ix == -1 ? "Add Step" : "Insert Step", factory.getTestStepName() );
600          if( name != null )
601          {
602             TestStepConfig newTestStepConfig = factory.createNewTestStep( getModelItem(), name );
603             if( newTestStepConfig != null )
604             {
605                WsdlTestStep testStep = getModelItem().insertTestStep( newTestStepConfig, ix );
606                UISupport.selectAndShow( testStep );
607             }
608          }
609 
610       }
611    }
612 
613    public static class ModelItemListDragAndDropable extends JListDragAndDropable<JList>
614    {
615       public ModelItemListDragAndDropable( JList list, WsdlTestCase testCase )
616       {
617          super( list, testCase );
618       }
619 
620       @Override
621       public ModelItem getModelItemAtRow( int row )
622       {
623          return (ModelItem) getList().getModel().getElementAt( row );
624       }
625 
626       @Override
627       public int getModelItemRow( ModelItem modelItem )
628       {
629          ListModel model = getList().getModel();
630 
631          for( int c = 0; c < model.getSize(); c++ )
632          {
633             if( model.getElementAt( c ) == modelItem )
634                return c;
635          }
636 
637          return -1;
638       }
639 
640       public Component getRenderer( ModelItem modelItem )
641       {
642          return getList().getCellRenderer().getListCellRendererComponent( getList(), modelItem,
643                  getModelItemRow( modelItem ), true, true );
644       }
645 
646       @Override
647       public void setDragInfo( String dropInfo )
648       {
649          super.setDragInfo( dropInfo == null || dropInfo.length() == 0 ? null : dropInfo );
650       }
651    }
652 }