View Javadoc

1   /*
2    *  soapui, copyright (C) 2005 Ole Matzura / eviware.com 
3    *
4    *  SoapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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 java.awt.BorderLayout;
16  import java.awt.Component;
17  import java.awt.Dimension;
18  import java.awt.event.ActionEvent;
19  import java.awt.event.MouseAdapter;
20  import java.awt.event.MouseEvent;
21  import java.beans.PropertyChangeEvent;
22  import java.beans.PropertyChangeListener;
23  import java.text.SimpleDateFormat;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Date;
27  import java.util.List;
28  
29  import javax.swing.AbstractAction;
30  import javax.swing.AbstractListModel;
31  import javax.swing.Action;
32  import javax.swing.BorderFactory;
33  import javax.swing.JButton;
34  import javax.swing.JComponent;
35  import javax.swing.JInternalFrame;
36  import javax.swing.JLabel;
37  import javax.swing.JList;
38  import javax.swing.JMenu;
39  import javax.swing.JOptionPane;
40  import javax.swing.JPanel;
41  import javax.swing.JPopupMenu;
42  import javax.swing.JProgressBar;
43  import javax.swing.JScrollPane;
44  import javax.swing.JSplitPane;
45  import javax.swing.JTabbedPane;
46  import javax.swing.ListCellRenderer;
47  import javax.swing.ListSelectionModel;
48  import javax.swing.event.PopupMenuEvent;
49  import javax.swing.event.PopupMenuListener;
50  
51  import com.eviware.soapui.SoapUI;
52  import com.eviware.soapui.impl.wsdl.WsdlTestCase;
53  import com.eviware.soapui.impl.wsdl.WsdlTestStep;
54  import com.eviware.soapui.impl.wsdl.panels.testcase.actions.SetCredentialsAction;
55  import com.eviware.soapui.impl.wsdl.panels.testcase.actions.SetEndpointAction;
56  import com.eviware.soapui.impl.wsdl.teststeps.WsdlAssertion;
57  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
58  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
59  import com.eviware.soapui.model.DesktopPanel;
60  import com.eviware.soapui.model.ModelItem;
61  import com.eviware.soapui.model.support.TestRunListenerAdapter;
62  import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
63  import com.eviware.soapui.model.testsuite.TestRunner;
64  import com.eviware.soapui.model.testsuite.TestStep;
65  import com.eviware.soapui.support.UISupport;
66  import com.jgoodies.forms.builder.ButtonBarBuilder;
67  
68  /***
69   * WsdlTestCase desktop panel
70   * 
71   * @author Ole.Matzura
72   */
73  
74  public class WsdlTestCaseDesktopPanel extends JPanel implements DesktopPanel
75  {
76  	private JTabbedPane tabbedPane;
77     final WsdlTestCase testCase;
78     private JProgressBar progressBar;
79     private TestStepListModel testStepListModel;
80     private JList testStepList;
81     private JList testLogList;
82     private LogListModel logListModel;
83     private InternalTestRunListener testRunListener = new InternalTestRunListener();
84  	private JButton runButton;
85  	private JPopupMenu testListPopup;
86  	private MoveStepDownAction moveStepDownAction;
87  	private MoveStepUpAction moveStepUpAction;
88  	private JButton cancelButton;
89     private TestRunner runner;
90  	private JButton setEndpointButton;
91  	private JMenu insertStepMenu;
92  	private JButton setCredentialsButton;
93  
94     public WsdlTestCaseDesktopPanel(WsdlTestCase testCase)
95     {
96        super(new BorderLayout());
97        this.testCase = testCase;
98        
99        testCase.addTestRunListener( testRunListener );
100       buildUI();
101       setPreferredSize( new Dimension( 250, 500 ));
102    }
103 
104 	private void buildUI()
105    {
106 	   JPanel panel = new JPanel( new BorderLayout() );
107 	   
108       panel.add( buildToolbar(), BorderLayout.PAGE_START );
109       panel.add( buildRunnerBar(), BorderLayout.CENTER );
110       
111       add( panel, BorderLayout.NORTH );
112       
113       JSplitPane splitPane = UISupport.createVerticalSplit();
114       JScrollPane scrollPane = new JScrollPane( buildTestStepList() );
115       scrollPane.setBorder( BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(), "Test Steps"));
116 		splitPane.setTopComponent( scrollPane);
117       splitPane.setBottomComponent( buildTestLog() );
118       splitPane.setDividerLocation( 0.5 );
119       splitPane.setDividerLocation( 200 );
120 
121       add( splitPane, BorderLayout.CENTER );
122       add( new JLabel( "--"), BorderLayout.PAGE_END );
123    }
124 
125    private Component buildTestLog()
126    {
127    	logListModel = new LogListModel();
128    	testLogList = new JList( logListModel );
129    	testLogList.setCellRenderer( new TestLogCellRenderer() );
130       
131       JScrollPane scrollPane = new JScrollPane( testLogList );
132       scrollPane.setBorder( BorderFactory.createTitledBorder( BorderFactory.createEmptyBorder(), "Test Log"));
133 		return scrollPane;
134    }
135 
136    private Component buildTestStepList()
137    {
138       testStepListModel = new TestStepListModel();
139       testStepList = new JList( testStepListModel );
140       testStepList.setCellRenderer( new TestStepCellRenderer() );
141       testStepList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
142       
143       testStepList.addMouseListener( new StepListMouseListener() );
144       testListPopup = new JPopupMenu();
145       
146       testListPopup.addSeparator();
147       insertStepMenu = new JMenu( "Insert step");
148 		insertStepMenu.add( new InsertTransferValuesStepAction() );
149 
150       testListPopup.add( insertStepMenu );
151       testListPopup.addSeparator();
152       moveStepDownAction = new MoveStepDownAction();
153 		testListPopup.add( moveStepDownAction );
154       moveStepUpAction = new MoveStepUpAction();
155 		testListPopup.add( moveStepUpAction );
156       
157       testListPopup.addPopupMenuListener( new StepListPopupMenuListener(testCase));
158       testStepList.setComponentPopupMenu( testListPopup );
159       
160       return testStepList;
161    }
162 
163    private Component buildToolbar()
164    {
165    	ButtonBarBuilder builder = new ButtonBarBuilder();
166       runButton = new JButton( new RunTestCaseAction());
167       runButton.setPreferredSize( new Dimension(24, 24 ));
168       cancelButton = new JButton( new CancelRunTestCaseAction() );
169       cancelButton.setPreferredSize( new Dimension(24, 24 ));
170       cancelButton.setEnabled( false );
171       setCredentialsButton = new JButton( new SetCredentialsAction( testCase ));
172       setCredentialsButton.setPreferredSize( new Dimension(24, 24 ));
173       setEndpointButton = new JButton( new SetEndpointAction( testCase ));
174       setEndpointButton.setPreferredSize( new Dimension(24, 24 ));
175 
176       builder.addFixed( runButton );
177       builder.addRelatedGap();
178       builder.addFixed( cancelButton );
179       builder.addGlue();
180       builder.addFixed( setCredentialsButton );
181       builder.addRelatedGap();
182       builder.addFixed( setEndpointButton );
183       
184       builder.setBorder( BorderFactory.createEmptyBorder( 5, 5, 5, 5 ));
185       
186       return builder.getPanel();
187    }
188 
189    private Component buildRunnerBar()
190    {
191       progressBar = new JProgressBar( 0, testCase.getTestStepCount() );
192       progressBar.setValue( 0 );
193       progressBar.setStringPainted( true );
194       progressBar.setBorder( BorderFactory.createEmptyBorder( 10, 10, 10, 10 ));
195       
196       return progressBar;
197    }
198    
199    private final class StepListPopupMenuListener implements PopupMenuListener
200 	{
201 		private StepListPopupMenuListener(WsdlTestCase case1)
202 		{
203 			super();
204 		}
205 
206 		public void popupMenuWillBecomeVisible(PopupMenuEvent e)
207 		{
208 		   while( testListPopup.getComponentCount() > 5 ) 
209 		      testListPopup.remove( 0 );
210 		   
211 		   int ix = testStepList.getSelectedIndex();
212 		   
213 		   if( ix == -1 ) 
214 		   {
215 		   	insertStepMenu.setEnabled( false );
216 		   	moveStepDownAction.setEnabled( false );
217 		   	moveStepUpAction.setEnabled( false );
218 		   	return;
219 		   }
220 		   
221 		   insertStepMenu.setEnabled( true );
222 		   moveStepUpAction.setEnabled( ix > 0 );
223 		   moveStepDownAction.setEnabled( ix > -1 && ix < testCase.getTestStepCount()-1 );
224 		   
225 		   TestStep testStep = (TestStep) testCase.getTestStepAt( ix );
226 		   Action[] actions = testStep.getActions();
227 		   
228 		   for (int i = 0; i < actions.length; i++)
229 		   {
230 		      testListPopup.insert( actions[i],i );
231 		   }
232 		}
233 
234 		public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
235 		{
236 		   // TODO Auto-generated method stub
237 		   
238 		}
239 
240 		public void popupMenuCanceled(PopupMenuEvent e)
241 		{
242 		   // TODO Auto-generated method stub
243 		   
244 		}
245 	}
246 
247 	private final class StepListMouseListener extends MouseAdapter
248 	{
249 		public void mouseClicked(MouseEvent e)
250 		{
251 		   if( e.getClickCount() < 2 ) return;
252 		   ModelItem modelItem = (ModelItem) testStepList.getSelectedValue();
253 		   if( modelItem == null ) return;
254 		    
255 		   JInternalFrame frame = SoapUI.getInstance().showTab( testCase );
256 		    
257 		   JInternalFrame requestFrame = SoapUI.getInstance().showTab( modelItem );
258 		   if( requestFrame != null )
259 			{
260 				requestFrame.reshape(frame.getX() + frame.getWidth(), frame.getY(),
261 								requestFrame.getWidth(), requestFrame.getHeight());
262 			}
263 		 }
264 	}
265 
266 	private class TestStepCellRenderer extends JLabel implements ListCellRenderer 
267    {
268       public Component getListCellRendererComponent(
269         JList list,
270         Object value,           
271         int index,               
272         boolean isSelected,      
273         boolean cellHasFocus)    
274       {
275           WsdlTestStep testStep = (WsdlTestStep) value;
276              setText( testStep.getName() );
277           
278           setIcon( testStep.getIcon() );
279           
280           if (isSelected) 
281           {
282              setBackground(list.getSelectionBackground());
283              setForeground(list.getSelectionForeground());
284           }
285           else 
286           {
287              setBackground(list.getBackground());
288              setForeground(list.getForeground());
289           }
290           
291           setEnabled(list.isEnabled());
292           setFont(list.getFont());
293           setOpaque(true);
294           setBorder( BorderFactory.createEmptyBorder(3, 3, 3, 3));
295           
296           
297           return this;
298       }
299   }
300    
301    private class TestStepListModel extends AbstractListModel implements PropertyChangeListener
302    {
303       private TestStepListTestSuiteListener testStepListTestSuiteListener = new TestStepListTestSuiteListener();
304 
305 		public TestStepListModel()
306       {
307       	for( int c = 0; c < getSize(); c++ )
308       		testCase.getTestStepAt( c ).addPropertyChangeListener( this );
309       	
310 			testCase.getTestSuite().addTestSuiteListener( testStepListTestSuiteListener );
311       }
312       
313       public int getSize()
314       {
315          return testCase.getTestStepCount();
316       }
317 
318       public Object getElementAt(int index)
319       {
320          return testCase.getTestStepAt( index );
321       }
322 
323 		public void propertyChange(PropertyChangeEvent arg0)
324 		{
325 		   int ix = testCase.getIndexOfTestStep( (TestStep)arg0.getSource() );
326 		   if( ix == -1 ) return;
327 		   
328 		   fireContentsChanged( this, ix, ix );
329 		}
330 		
331 		public void release()
332 		{
333 			testCase.getTestSuite().removeTestSuiteListener( testStepListTestSuiteListener );
334 			
335 			for( int c = 0; c < getSize(); c++ )
336       		testCase.getTestStepAt( c ).removePropertyChangeListener( this );
337 		}
338 		
339 		private class TestStepListTestSuiteListener extends TestSuiteListenerAdapter
340 		{
341 			public void testStepAdded(TestStep testStep, int ix)
342 			{
343 			   testStep.addPropertyChangeListener( TestStepListModel.this );
344 			   fireIntervalAdded( TestStepListModel.this, ix, ix );
345 			}
346 
347 			public void testStepRemoved(TestStep testStep, int ix)
348 			{
349 				testStep.removePropertyChangeListener( TestStepListModel.this );
350 			   fireIntervalRemoved( TestStepListModel.this, ix, ix );
351 			}
352 		}
353    }
354 
355    public class InternalTestRunListener extends TestRunListenerAdapter 
356    {
357 		private long stepStart;
358 		private long testStartTime;
359 		private SimpleDateFormat dateFormat;
360 
361 		public InternalTestRunListener()
362 		{
363 			dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
364 		}
365 
366 		public boolean beforeRun(TestRunner testRunner) 
367 		{
368 			runButton.setEnabled( false );
369 			cancelButton.setEnabled( true );
370 			testStepList.setEnabled( false );
371 			testStepList.setSelectedIndex( -1 );
372 			progressBar.getModel().setMaximum( testRunner.getTestCase().getTestStepCount() );
373 			logListModel.clear();
374 			
375 			for( int c = 0; c < testCase.getTestStepCount(); c++ )
376 			{
377 				testCase.getTestStepAt( c ).prepare( testRunner );
378 			}				
379 			
380 			testStartTime = System.currentTimeMillis();
381 			logListModel.addText( "Test started at " + dateFormat.format( new Date( testStartTime )) );
382 			return true;
383 		}
384 
385 		public boolean beforeStep(TestRunner testRunner) 
386 		{
387 			TestStep testStep = testRunner.getCurrentStep();
388 			testStepList.setSelectedValue( testStep, true );
389 			progressBar.setString( testStep.getName() );
390 			progressBar.setValue( testRunner.getCurrentStepIndex() );
391 			
392 			stepStart = System.currentTimeMillis();
393 			return true;
394 		}
395 		
396 		public void afterRun(TestRunner testRunner) 
397 		{
398 			long endTime = System.currentTimeMillis();
399 			
400 			progressBar.setValue( testRunner.getCurrentStepIndex() );
401 		   runButton.setEnabled( true );	
402 			cancelButton.setEnabled( false );
403 			testStepList.setEnabled( true );
404 			
405 			if( testRunner.getStatus() == TestRunner.Status.CANCELED )
406 				logListModel.addText( "Test canceled, time taken = " + (endTime-testStartTime));
407 			else
408 				logListModel.addText( "Test finished, time taken = " + (endTime-testStartTime));
409 			runner = null;
410 		}
411 
412 		public boolean afterStep(TestRunner testRunner) 
413 		{
414 			TestStep testStep = testRunner.getCurrentStep();
415 			logListModel.addTestStep( "Step " + (1+testRunner.getCurrentStepIndex()) + " : " +
416 					testStep.getName() + " took " + (System.currentTimeMillis()-stepStart) + " ms", testStep );
417 			
418 			if( testStep instanceof WsdlTestRequestStep )
419 			{
420 				WsdlTestRequest testRequest = ((WsdlTestRequestStep)testStep).getTestRequest();
421 				for( int c = 0; c < testRequest.getAssertionCount(); c++ )
422 				{
423 					WsdlAssertion assertion = testRequest.getAssertionAt( c );
424 					if( assertion.getStatus() == WsdlAssertion.AssertionStatus.FAILED )
425 					{
426 						logListModel.addAssertion( assertion );
427 					}
428 				}
429 			}
430 			
431 			return true;
432 		}
433 	}
434    
435    private class LogListModel extends AbstractListModel
436    {
437    	private List<Object> items = new ArrayList<Object>();
438    	
439    	public void addText( String msg )
440    	{
441    		items.add( msg );
442    		fireIntervalAdded( this, items.size()-1, items.size() );
443    	}
444    	
445    	public void addTestStep( String msg, TestStep testStep )
446    	{
447    		items.add( new TestStepLogItem( testStep, msg ));
448    		fireIntervalAdded( this, items.size()-1, items.size() );
449    	}
450    	
451    	public void addAssertion( WsdlAssertion assertion )
452    	{
453    		int sz = items.size();
454    		items.add( assertion );
455    		items.addAll( Arrays.asList(assertion.getErrors()) );
456    		
457    		fireIntervalAdded( this, sz, items.size() );
458    	}
459    	
460    	public void clear()
461    	{
462    		int sz = getSize();
463    		items.clear();
464    		fireIntervalRemoved( this, 0, sz );
465    	}
466    	
467 		public int getSize()
468 		{
469 			return items.size();
470 		}
471 
472 		public Object getElementAt(int arg0)
473 		{
474 			return items.get( arg0 );
475 		}}
476 
477    private class TestLogCellRenderer extends JLabel implements ListCellRenderer 
478    {
479       public Component getListCellRendererComponent(
480         JList list,
481         Object value,           
482         int index,               
483         boolean isSelected,      
484         boolean cellHasFocus)    
485       {
486       	 setIcon( null );
487       	 
488           if( value instanceof String )
489           {
490          	 setText( value.toString() );
491           }
492           else if( value instanceof WsdlAssertion )
493           {
494          	 WsdlAssertion assertion = (WsdlAssertion) value;
495          	 setIcon( assertion.getIcon() );
496          	 setText( assertion.getName() + "; " + assertion.getStatus().toString() );
497           }
498           else if( value instanceof AssertionError )
499           {
500          	 setText( " -> " + ((AssertionError)value).toString() );
501           }
502           else if( value instanceof TestStepLogItem )
503           {
504          	 TestStepLogItem logItem = (TestStepLogItem) value;
505          	 setIcon( null );
506          	 setText( logItem.getMsg() );
507           }
508           
509           if (isSelected) 
510           {
511              setBackground(list.getSelectionBackground());
512              setForeground(list.getSelectionForeground());
513           }
514           else 
515           {
516              setBackground(list.getBackground());
517              setForeground(list.getForeground());
518           }
519           
520           setEnabled(list.isEnabled());
521           setFont(list.getFont());
522           setOpaque(true);
523           setBorder( BorderFactory.createEmptyBorder(3, 3, 3, 3));
524           
525           
526           return this;
527       }
528    }
529    
530    private class TestStepLogItem
531    {
532    	private final TestStep testStep;
533 		private final String msg;
534 
535 		public TestStepLogItem( TestStep testStep, String msg )
536    	{
537 			this.testStep = testStep;
538 			this.msg = msg;
539 		}
540 
541 		public String getMsg()
542 		{
543 			return msg;
544 		}
545 
546 		public TestStep getTestStep()
547 		{
548 			return testStep;
549 		}
550    }
551 
552    private class MoveStepDownAction extends AbstractAction
553    {
554    	public MoveStepDownAction()
555    	{
556    		super( "Move down" );
557    	}
558    	
559 		public void actionPerformed(ActionEvent e)
560 		{
561 			int ix = testStepList.getSelectedIndex();
562 			if( ix == -1 || ix >= testCase.getTestStepCount()-1 ) return;
563 			
564 			testCase.moveStep( ix, 1 );
565 		}
566    }
567 
568    private class MoveStepUpAction extends AbstractAction
569    {
570    	public MoveStepUpAction()
571    	{
572    		super( "Move up" );
573    	}
574 
575 		public void actionPerformed(ActionEvent e)
576 		{
577 			int ix = testStepList.getSelectedIndex();
578 			if( ix < 1 ) return;
579 			
580 			testCase.moveStep( ix, -1 );
581 		}
582    }
583    
584    public class RunTestCaseAction extends AbstractAction
585    {
586 		public RunTestCaseAction()
587       {
588          putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/run_testcase.gif"));
589          putValue( Action.SHORT_DESCRIPTION, "Runs this testcase" );
590       }
591 
592 		public void actionPerformed(ActionEvent e)
593 		{
594          runner = testCase.run();
595 		}
596    }
597 
598    public class CancelRunTestCaseAction extends AbstractAction
599    {
600 		public CancelRunTestCaseAction()
601       {
602          putValue( Action.SMALL_ICON, SoapUI.createImageIcon( "/stop_testcase.gif"));
603          putValue( Action.SHORT_DESCRIPTION, "Stops running this testcase" );
604       }
605       
606 		public void actionPerformed(ActionEvent e)
607 		{
608       	if( runner != null )
609       		runner.cancel();
610       }
611    }
612    
613    public class InsertTransferValuesStepAction extends AbstractAction
614 	{
615    	public InsertTransferValuesStepAction()
616 		{
617    		super( "Transfer Reponse->Request values" );
618 		}
619    	
620 		public void actionPerformed(ActionEvent e)
621 		{
622 			int ix = testStepList.getSelectedIndex();
623 			testCase.addTransferResponseValuesStep( ix );
624 		}
625 
626 	}
627    
628    public ModelItem getModelItem()
629 	{
630 		return testCase;
631 	}
632 
633 	public boolean onClose()
634 	{
635 		if( runner != null && runner.getStatus() == TestRunner.Status.RUNNING )
636 		{
637 			int retval = JOptionPane.showConfirmDialog( UISupport.getMainFrame(), "Cancel running TestCase?", 
638 					"Cancel Run", JOptionPane.YES_NO_CANCEL_OPTION );
639 			
640 			if( retval == JOptionPane.CANCEL_OPTION) return false;
641 			if( retval == JOptionPane.YES_OPTION )
642 			{
643 				runner.cancel();
644 			}
645 		}
646 		
647       testCase.removeTestRunListener( testRunListener );
648       testStepListModel.release();
649 
650       return true;
651 	}
652 
653 	public JComponent getComponent()
654 	{
655 		return this;
656 	}
657 }