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.testsuite;
14  
15  import com.eviware.soapui.SoapUI;
16  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
17  import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
18  import com.eviware.soapui.impl.wsdl.actions.testsuite.AddNewTestCaseAction;
19  import com.eviware.soapui.impl.wsdl.panels.testcase.TestRunLog;
20  import com.eviware.soapui.impl.wsdl.panels.testcase.TestRunLog.TestRunLogTestRunListener;
21  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.AbstractGroovyEditorModel;
22  import com.eviware.soapui.impl.wsdl.panels.teststeps.support.PropertyHolderTable;
23  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
24  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestScenario;
25  import com.eviware.soapui.model.ModelItem;
26  import com.eviware.soapui.model.propertyexpansion.DefaultPropertyExpansionContext;
27  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
28  import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
29  import com.eviware.soapui.model.testsuite.TestCase;
30  import com.eviware.soapui.model.testsuite.TestRunner;
31  import com.eviware.soapui.model.testsuite.TestSuite.TestSuiteRunType;
32  import com.eviware.soapui.settings.UISettings;
33  import com.eviware.soapui.support.DocumentListenerAdapter;
34  import com.eviware.soapui.support.StringUtils;
35  import com.eviware.soapui.support.UISupport;
36  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
37  import com.eviware.soapui.support.components.*;
38  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
39  
40  import javax.swing.*;
41  import javax.swing.text.Document;
42  import java.awt.*;
43  import java.awt.event.ActionEvent;
44  import java.awt.event.ActionListener;
45  
46  /***
47   * DesktopPanel for WsdlTestSuite
48   * 
49   * @author Ole.Matzura
50   */
51  
52  @SuppressWarnings("serial")
53  public class WsdlTestSuiteDesktopPanel extends ModelItemDesktopPanel<WsdlTestSuite>
54  {
55  	private JProgressBar progressBar;
56  	private JTestSuiteTestCaseList testCaseList;
57  	private RunAction runAction = new RunAction();
58  	private CancelAction cancelAction = new CancelAction();
59  	private TestSuiteRunner testSuiteRunner = new TestSuiteRunner();
60  	private JToggleButton sequentialButton;
61  	private JToggleButton parallellButton;
62  	private final InternalTestSuiteListener testSuiteListener = new InternalTestSuiteListener();
63  	private JTextArea descriptionArea;
64  	private boolean failedTests;
65  	private PropertyHolderTable propertiesTable;
66  	private TestRunLog testRunLog;
67  	private GroovyEditorComponent tearDownGroovyEditor;
68  	private GroovyEditorComponent setupGroovyEditor;
69     private JInspectorPanel testCaseListInspectorPanel;
70  
71     public WsdlTestSuiteDesktopPanel(WsdlTestSuite testSuite)
72  	{
73  		super( testSuite );
74  
75  		buildUI();
76  		testSuite.addTestSuiteListener( testSuiteListener );
77  	}
78  
79  	private void buildUI()
80  	{
81  		add( buildToolbar(), BorderLayout.NORTH );
82  		add( buildContent(), BorderLayout.CENTER );
83  		
84  		setPreferredSize( new Dimension( 500, 500 ));
85  	}
86  
87  	private JComponent buildContent()
88  	{
89  		JInspectorPanel inspectorPanel = JInspectorPanelFactory.build( buildTabs() );
90  		inspectorPanel.addInspector( new JComponentInspector( buildRunLog(), "TestSuite Log", 
91  					"Log of executed TestCases and TestSteps", true ));
92  
93        if( StringUtils.hasContent( getModelItem().getDescription() ) && getModelItem().getSettings().getBoolean( UISettings.SHOW_DESCRIPTIONS ))
94        {
95           testCaseListInspectorPanel.setCurrentInspector( "Description" );
96        }
97  
98  		return inspectorPanel.getComponent();
99  	}
100 	
101 	private JComponent buildRunLog()
102 	{
103 		testRunLog = new TestRunLog( getModelItem().getSettings() );
104 		return testRunLog;
105 	}
106 
107 	protected JTestSuiteTestCaseList getTestCaseList()
108 	{
109 		return testCaseList;
110 	}
111 
112 	@Override
113 	public void addNotify()
114 	{
115 		super.addNotify();
116 		getModelItem().addTestSuiteListener( testSuiteListener );
117 	}
118 
119 	@Override
120 	public void removeNotify()
121 	{
122 		super.removeNotify();
123 		getModelItem().removeTestSuiteListener( testSuiteListener );
124 	}
125 
126 	private JComponent buildToolbar()
127 	{
128 		cancelAction.setEnabled( false );
129 		runAction.setEnabled( getModelItem().getTestCaseCount() > 0 );
130 		
131 		JXToolBar toolbar = UISupport.createToolbar();
132 		
133 		addToolbarActions( toolbar );
134 		toolbar.addGlue();
135 		toolbar.add( UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TESTSUITEEDITOR_HELP_URL )));
136 		
137 		progressBar = new JProgressBar( 0, getModelItem().getTestCaseCount() );
138 		JPanel progressPanel = UISupport.createProgressBarPanel(progressBar, 10, false );
139 		
140 		JPanel panel = new JPanel( new BorderLayout() );
141 	   
142       panel.add( toolbar, BorderLayout.PAGE_START );
143       panel.add( progressPanel, BorderLayout.CENTER );
144       
145 		return panel;
146 	}
147 
148 	protected void addToolbarActions( JXToolBar toolbar )
149 	{
150 		toolbar.add( UISupport.createToolbarButton( runAction ));
151 		toolbar.add( UISupport.createToolbarButton( cancelAction ));
152 		
153 		toolbar.addRelatedGap();
154 		
155 		ButtonGroup buttonGroup = new ButtonGroup();
156 		
157 		sequentialButton = new JToggleButton( UISupport.createImageIcon( "/sequential.gif" ), true );
158 		sequentialButton.setToolTipText( "The selected TestCases are run in sequence" );
159 		sequentialButton.setPreferredSize( UISupport.getPreferredButtonSize());
160 		sequentialButton.setSelected( getModelItem().getRunType() == TestSuiteRunType.SEQUENTIAL );
161 		sequentialButton.addActionListener( new ActionListener() {
162 
163 			public void actionPerformed(ActionEvent e)
164 			{
165 				getModelItem().setRunType( TestSuiteRunType.SEQUENTIAL );
166 			}} );
167 		
168 		buttonGroup.add( sequentialButton );
169 		
170 		parallellButton = new JToggleButton( UISupport.createImageIcon( "/parallell.gif" ));
171 		parallellButton.setToolTipText( "The selected TestCases are run in parallel" );
172 		parallellButton.setPreferredSize( UISupport.getPreferredButtonSize());
173 		parallellButton.setSelected( getModelItem().getRunType() == TestSuiteRunType.PARALLEL );
174 		parallellButton.addActionListener( new ActionListener() {
175 
176 			public void actionPerformed(ActionEvent e)
177 			{
178 				getModelItem().setRunType( TestSuiteRunType.PARALLEL );
179 			}} );
180 		
181 		buttonGroup.add( parallellButton );
182 		
183 		toolbar.addUnrelatedGap();
184 		toolbar.add( sequentialButton );
185 		toolbar.addRelatedGap();
186 		toolbar.add( parallellButton );
187 	}
188 	
189 	private JComponent buildTabs()
190 	{
191 		JTabbedPane tabs = new JTabbedPane( JTabbedPane.TOP );
192       testCaseListInspectorPanel = JInspectorPanelFactory.build( buildTestCaseList( getModelItem() ) );
193 		
194 		tabs.addTab( "TestCases", testCaseListInspectorPanel.getComponent() );
195 		
196       addTabs( tabs, testCaseListInspectorPanel );
197       tabs.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
198       
199       return UISupport.createTabPanel( tabs, true );
200 	}
201 
202 	protected void addTabs( JTabbedPane tabs, JInspectorPanel inspectorPanel )
203 	{
204 		inspectorPanel.addInspector( new JFocusableComponentInspector<JPanel>( buildDescriptionPanel(), 
205 					descriptionArea, "Description", "Description for this TestSuite", true ));
206 		
207 		inspectorPanel.addInspector( new JComponentInspector( buildPropertiesPanel(), "Properties", "TestSuite level properties", true ) );
208 		inspectorPanel.addInspector( new GroovyEditorInspector( buildSetupScriptPanel(), "Setup Script", "Script to run before running TestSuite") );
209 		inspectorPanel.addInspector( new GroovyEditorInspector( buildTearDownScriptPanel(), "TearDown Script", "Script to run after running TestSuite" ) );
210 	}
211 	
212 	protected GroovyEditorComponent buildTearDownScriptPanel()
213 	{
214 		tearDownGroovyEditor = new GroovyEditorComponent( new TearDownScriptGroovyEditorModel(), null );
215 		return tearDownGroovyEditor;
216 	}
217 
218 	protected GroovyEditorComponent buildSetupScriptPanel()
219 	{
220 		setupGroovyEditor = new GroovyEditorComponent( new SetupScriptGroovyEditorModel(), null );
221 		return setupGroovyEditor;
222 	}
223 
224 	private JComponent buildPropertiesPanel()
225 	{
226 		JPanel panel = new JPanel( new BorderLayout() );
227 		propertiesTable = createPropertyHolderTable();
228 		panel.add( new JScrollPane( propertiesTable ), BorderLayout.CENTER );
229 		return panel;
230 	}
231 
232 	protected PropertyHolderTable createPropertyHolderTable()
233 	{
234 		return new PropertyHolderTable( getModelItem() );
235 	}
236 
237 	private JPanel buildDescriptionPanel()
238 	{
239    	JPanel panel = new JPanel( new BorderLayout() );
240    	descriptionArea = new JUndoableTextArea( getModelItem().getDescription() );
241    	descriptionArea.getDocument().addDocumentListener( new DocumentListenerAdapter() 
242    	{
243 			public void update(Document document)
244 			{
245 				getModelItem().setDescription( descriptionArea.getText() );
246 			}} );
247    	
248    	panel.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2));
249    	panel.add( new JScrollPane( descriptionArea ), BorderLayout.CENTER );
250    	UISupport.addTitledBorder( panel, "TestSuite Description" );
251    	
252 		return panel;
253 	}
254 	
255 	protected JComponent buildTestCaseList(WsdlTestSuite testSuite)
256 	{
257 		testCaseList = new JTestSuiteTestCaseList( testSuite );
258 		
259 		JPanel p = new JPanel( new BorderLayout() );
260 		
261 		p.add( buildTestCaseListToolbar(), BorderLayout.NORTH );
262 		p.add( new JScrollPane( testCaseList), BorderLayout.CENTER );
263 		
264 		return p;
265 	}
266 
267 	private Component buildTestCaseListToolbar()
268 	{
269 		JXToolBar toolbar = UISupport.createToolbar();
270 		toolbar.add( UISupport.createToolbarButton( 
271 					SwingActionDelegate.createDelegate( AddNewTestCaseAction.SOAPUI_ACTION_ID, getModelItem(), null, "/testCase.gif" )));
272 
273 		return toolbar;
274 	}
275 
276 	public boolean onClose( boolean canCancel )
277 	{
278 		propertiesTable.release();
279 		
280 		setupGroovyEditor.getEditor().release();
281 		tearDownGroovyEditor.getEditor().release();
282 		
283 		testRunLog.release();
284 		
285 		return super.release();
286 	}
287 
288 	public JComponent getComponent()
289 	{
290 		return this;
291 	}
292 
293 	public boolean dependsOn(ModelItem modelItem)
294 	{
295 		return modelItem == getModelItem() || modelItem == getModelItem().getProject();
296 	}
297 
298 	protected void runTestSuite()
299 	{
300 		new Thread( testSuiteRunner, getModelItem().getName() + " TestSuiteRunner" ).start();
301 	}
302 
303 	protected void beforeRun()
304 	{
305 		runAction.setEnabled( false );
306 		cancelAction.setEnabled( true );
307 		testCaseList.setEnabled( false );
308 		progressBar.setForeground( Color.GREEN.darker() );
309 		
310 		failedTests = false;
311 	}
312 
313 	protected void afterRun()
314 	{
315 		runAction.setEnabled( true );
316 		cancelAction.setEnabled( false );
317 		testCaseList.setEnabled( true );
318 		
319 		progressBar.setString( failedTests ? "Failed" : testSuiteRunner.isCanceled() ? "Canceled" : "Passed" );
320 		progressBar.setForeground( failedTests ? Color.RED : Color.GREEN.darker() );
321 	}
322 	
323 	private final class InternalTestSuiteListener extends TestSuiteListenerAdapter
324 	{
325 		public void testCaseAdded(TestCase testCase)
326 		{
327 			runAction.setEnabled( getModelItem().getTestCaseCount() > 0 );
328 		}
329 
330 		public void testCaseRemoved(TestCase testCase)
331 		{
332 			runAction.setEnabled( getModelItem().getTestCaseCount() > 0 );
333 		}
334 	}
335 
336 	private class RunAction extends AbstractAction
337 	{
338 		public RunAction()
339 		{
340 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_testcase.gif" ));
341 			putValue( Action.SHORT_DESCRIPTION, "Runs the selected TestCases" );
342 		}
343 		
344 		public void actionPerformed(ActionEvent e)
345 		{
346 			runTestSuite();
347 		}
348 	}
349 	
350 	private class CancelAction extends AbstractAction
351 	{
352 		public CancelAction()
353 		{
354 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/stop_testcase.gif" ));
355 			putValue( Action.SHORT_DESCRIPTION, "Cancels ongoing TestCase runs" );
356 		}
357 		
358 		public void actionPerformed(ActionEvent e)
359 		{
360 		   testSuiteRunner.cancel();
361 		}
362 	}
363 	
364 	/***
365 	 * Runs the selected testsuites..
366 	 * 
367 	 * @author Ole.Matzura
368 	 */
369 	
370 	public class TestSuiteRunner extends WsdlTestScenario
371 	{
372 		private TestRunLogTestRunListener runLogListener;
373 		private int finishCount;
374 
375 		public TestSuiteRunner()
376 		{
377 			super( TestSuiteRunType.SEQUENTIAL );
378 		}
379 		
380 		public void run()
381 		{
382 			setRunType( getModelItem().getRunType() );
383 			
384 			removeAllTestCases();
385 
386 			testCaseList.reset();
387 			
388 			for( TestCase testCase : getModelItem().getTestCaseList() )
389 			{
390 				if( !testCase.isDisabled() )
391 					addTestCase( testCase );
392 			}
393 			
394 			super.run();
395 		}
396 
397 		protected PropertyExpansionContext createContext()
398 		{
399 			return new DefaultPropertyExpansionContext( getModelItem() );
400 		}
401 		
402 		public void beforeRun( PropertyExpansionContext context )
403 		{
404 			super.beforeRun( context );
405 			
406 			WsdlTestSuiteDesktopPanel.this.beforeRun();
407 			
408 			progressBar.setMaximum( getTestCaseCount() );
409 			progressBar.setValue( 0 );
410 			progressBar.setString( "" ); 
411 			finishCount = 0;
412 			
413 			if( runLogListener == null )
414 				runLogListener = new TestRunLog.TestRunLogTestRunListener( testRunLog, false );
415 			
416 			testRunLog.clear();
417 			
418 			if( getRunType() == TestSuiteRunType.PARALLEL )
419 				testRunLog.addText( "<log disabled during parallell execution>" );
420 			
421 			context = new DefaultPropertyExpansionContext( getModelItem() );
422 			try
423 			{
424 				getModelItem().runSetupScript( context );
425 			}
426 			catch( Exception e )
427 			{
428 				SoapUI.logError( e );
429 			}
430 		}
431 
432 		@Override
433 		protected void afterTestCase( TestCase testCase, TestRunner runner )
434 		{
435 			super.afterTestCase( testCase, runner );
436 			progressBar.setValue( ++finishCount );
437 			if( runner.getStatus() == TestRunner.Status.FAILED )
438 				failedTests = true;
439 			
440 			if( getRunType() == TestSuiteRunType.SEQUENTIAL )
441 				testCase.removeTestRunListener( runLogListener );
442 		}
443 
444 		@Override
445 		protected void beforeTestCase( TestCase testCase )
446 		{
447 			super.beforeTestCase( testCase );
448 			progressBar.setString( "Running " + testCase.getName() );
449 			
450 			if( getRunType() == TestSuiteRunType.SEQUENTIAL )
451 				testCase.addTestRunListener( runLogListener );
452 		}
453 
454 		protected void afterRun(PropertyExpansionContext context)
455 		{
456 			super.afterRun( context );
457 			
458 			try
459 			{
460 				getModelItem().runTearDownScript( context );
461 			}
462 			catch( Exception e )
463 			{
464 				SoapUI.logError( e );
465 			}
466 			finally
467 			{
468 				WsdlTestSuiteDesktopPanel.this.afterRun();
469 			}
470 		}
471 	}
472 	
473 	private class SetupScriptGroovyEditorModel extends AbstractGroovyEditorModel
474 	{
475 		public SetupScriptGroovyEditorModel()
476 		{
477 			super( new String[] {"log", "context", "testSuite" }, getModelItem().getSettings(), "Setup" );
478 		}
479 		
480 		public String getScript()
481 		{
482 			return getModelItem().getSetupScript();
483 		}
484 
485 		public void setScript( String text )
486 		{
487 			getModelItem().setSetupScript( text );
488 		}
489 		
490 		@Override
491 		public Action createRunAction()
492 		{
493 			return new AbstractAction(){
494 
495 				public void actionPerformed( ActionEvent e )
496 				{
497 					try
498 					{
499 						getModelItem().runSetupScript( null );
500 					}
501 					catch( Exception e1 )
502 					{
503 						UISupport.showErrorMessage( e1 );
504 					}
505 				}};
506 		}
507 	}
508 	
509 	private class TearDownScriptGroovyEditorModel extends AbstractGroovyEditorModel
510 	{
511 		public TearDownScriptGroovyEditorModel()
512 		{
513 			super( new String[] {"log", "context", "testSuite" }, getModelItem().getSettings(), "TearDown" );
514 		}
515 		
516 		public String getScript()
517 		{
518 			return getModelItem().getTearDownScript();
519 		}
520 
521 		public void setScript( String text )
522 		{
523 			getModelItem().setTearDownScript( text );
524 		}
525 		
526 		@Override
527 		public Action createRunAction()
528 		{
529 			return new AbstractAction(){
530 
531 				public void actionPerformed( ActionEvent e )
532 				{
533 					try
534 					{
535 						getModelItem().runTearDownScript( null );
536 					}
537 					catch( Exception e1 )
538 					{
539 						UISupport.showErrorMessage( e1 );
540 					}
541 				}};
542 		}
543 	}
544 }