View Javadoc

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