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  import java.util.ArrayList;
22  import java.util.List;
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.ButtonGroup;
29  import javax.swing.JComponent;
30  import javax.swing.JPanel;
31  import javax.swing.JProgressBar;
32  import javax.swing.JScrollPane;
33  import javax.swing.JTabbedPane;
34  import javax.swing.JTextArea;
35  import javax.swing.JToggleButton;
36  import javax.swing.text.Document;
37  
38  import com.eviware.soapui.SoapUI;
39  import com.eviware.soapui.impl.wsdl.WsdlTestSuite;
40  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
41  import com.eviware.soapui.impl.wsdl.actions.testsuite.AddNewTestCaseAction;
42  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
43  import com.eviware.soapui.model.ModelItem;
44  import com.eviware.soapui.model.support.PropertiesMap;
45  import com.eviware.soapui.model.support.TestRunListenerAdapter;
46  import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
47  import com.eviware.soapui.model.testsuite.TestCase;
48  import com.eviware.soapui.model.testsuite.TestRunContext;
49  import com.eviware.soapui.model.testsuite.TestRunner;
50  import com.eviware.soapui.model.testsuite.TestSuite.TestSuiteRunType;
51  import com.eviware.soapui.support.DocumentListenerAdapter;
52  import com.eviware.soapui.support.UISupport;
53  import com.eviware.soapui.support.action.swing.SwingActionDelegate;
54  import com.eviware.soapui.support.components.JUndoableTextArea;
55  import com.eviware.soapui.support.components.JXToolBar;
56  import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
57  
58  /***
59   * DesktopPanel for WsdlTestSuite
60   * 
61   * @author Ole.Matzura
62   */
63  
64  @SuppressWarnings("serial")
65  public class WsdlTestSuiteDesktopPanel extends ModelItemDesktopPanel<WsdlTestSuite>
66  {
67  	private final WsdlTestSuite testSuite;
68  	private JProgressBar progressBar;
69  	private JTestCaseList testCaseList;
70  	private RunAction runAction = new RunAction();
71  	private CancelAction cancelAction = new CancelAction();
72  	private TestSuiteRunner testSuiteRunner = new TestSuiteRunner();
73  	private JToggleButton sequentialButton;
74  	private JToggleButton parallellButton;
75  	private final InternalTestSuiteListener testSuiteListener = new InternalTestSuiteListener();
76  	private JTextArea descriptionArea;
77  	private boolean failedTests;
78  
79  	public WsdlTestSuiteDesktopPanel(WsdlTestSuite testSuite)
80  	{
81  		super( testSuite );
82  		this.testSuite = testSuite;
83  		
84  		buildUI();
85  		testSuite.addTestSuiteListener( testSuiteListener );
86  	}
87  
88  	private void buildUI()
89  	{
90  		add( buildToolbar(), BorderLayout.NORTH );
91  		add( buildContent(), BorderLayout.CENTER );
92  		
93  		setPreferredSize( new Dimension( 300, 400 ));
94  	}
95  	
96  	protected JTestCaseList getTestCaseList()
97  	{
98  		return testCaseList;
99  	}
100 
101 	@Override
102 	public void addNotify()
103 	{
104 		super.addNotify();
105 		testSuite.addTestSuiteListener( testSuiteListener );
106 	}
107 
108 	@Override
109 	public void removeNotify()
110 	{
111 		super.removeNotify();
112 		testSuite.removeTestSuiteListener( testSuiteListener );
113 	}
114 
115 	private JComponent buildToolbar()
116 	{
117 		cancelAction.setEnabled( false );
118 		runAction.setEnabled( testSuite.getTestCaseCount() > 0 );
119 		
120 		JXToolBar toolbar = UISupport.createToolbar();
121 		
122 		addToolbarActions( toolbar );
123 		toolbar.add( Box.createHorizontalGlue() );
124 		toolbar.add(  UISupport.createToolbarButton( new ShowOnlineHelpAction( HelpUrls.TESTSUITEEDITOR_HELP_URL )));
125 		
126 		progressBar = new JProgressBar( 0, testSuite.getTestCaseCount() );
127 		JPanel progressPanel = UISupport.createProgressBarPanel(progressBar, 10, false );
128 		
129 		JPanel panel = new JPanel( new BorderLayout() );
130 	   
131       panel.add( toolbar, BorderLayout.PAGE_START );
132       panel.add( progressPanel, BorderLayout.CENTER );
133       
134 		return panel;
135 	}
136 
137 	protected void addToolbarActions( JXToolBar toolbar )
138 	{
139 		toolbar.add( UISupport.createToolbarButton( runAction ));
140 		toolbar.add( UISupport.createToolbarButton( cancelAction ));
141 		
142 		toolbar.addRelatedGap();
143 		toolbar.add( UISupport.createToolbarButton( 
144 					SwingActionDelegate.createDelegate( AddNewTestCaseAction.SOAPUI_ACTION_ID, testSuite, null, "/testCase.gif" )));
145 		
146 		ButtonGroup buttonGroup = new ButtonGroup();
147 		
148 		sequentialButton = new JToggleButton( UISupport.createImageIcon( "/sequential.gif" ), true );
149 		sequentialButton.setToolTipText( "The selected TestCases are run in sequence" );
150 		sequentialButton.setPreferredSize( UISupport.getPreferredButtonSize());
151 		sequentialButton.setSelected( testSuite.getRunType() == TestSuiteRunType.SEQUENTIAL );
152 		sequentialButton.addActionListener( new ActionListener() {
153 
154 			public void actionPerformed(ActionEvent e)
155 			{
156 				testSuite.setRunType( TestSuiteRunType.SEQUENTIAL );
157 			}} );
158 		
159 		buttonGroup.add( sequentialButton );
160 		
161 		parallellButton = new JToggleButton( UISupport.createImageIcon( "/parallell.gif" ));
162 		parallellButton.setToolTipText( "The selected TestCases are run in parallel" );
163 		parallellButton.setPreferredSize( UISupport.getPreferredButtonSize());
164 		parallellButton.setSelected( testSuite.getRunType() == TestSuiteRunType.PARALLEL );
165 		parallellButton.addActionListener( new ActionListener() {
166 
167 			public void actionPerformed(ActionEvent e)
168 			{
169 				testSuite.setRunType( TestSuiteRunType.PARALLEL );
170 			}} );
171 		
172 		buttonGroup.add( parallellButton );
173 		
174 		toolbar.addUnrelatedGap();
175 		toolbar.add( sequentialButton );
176 		toolbar.addRelatedGap();
177 		toolbar.add( parallellButton );
178 		
179 	}
180 	
181 	private JComponent buildContent()
182 	{
183 		JTabbedPane tabs = new JTabbedPane( JTabbedPane.TOP );
184 		
185 		testCaseList = buildTestCaseList( testSuite );
186 		
187       tabs.addTab( "TestCases",  new JScrollPane( testCaseList ));
188       tabs.addTab( "Description", buildDescriptionPanel() );
189       
190       return UISupport.createTabPanel( tabs, true );
191 	}
192 
193 	private Component buildDescriptionPanel()
194 	{
195    	JPanel panel = new JPanel( new BorderLayout() );
196    	descriptionArea = new JUndoableTextArea( testSuite.getDescription() );
197    	descriptionArea.getDocument().addDocumentListener( new DocumentListenerAdapter() 
198    	{
199 			public void update(Document document)
200 			{
201 				testSuite.setDescription( descriptionArea.getText() );
202 			}} );
203    	
204    	panel.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2));
205    	panel.add( new JScrollPane( descriptionArea ), BorderLayout.CENTER );
206    	
207 		return panel;
208 	}
209 	
210 	protected JTestCaseList buildTestCaseList(WsdlTestSuite testSuite)
211 	{
212 		return new JTestCaseList( testSuite );
213 	}
214 
215 	public boolean onClose( boolean canCancel )
216 	{
217 		super.release();
218 		return true;
219 	}
220 
221 	public JComponent getComponent()
222 	{
223 		return this;
224 	}
225 
226 	public boolean dependsOn(ModelItem modelItem)
227 	{
228 		return modelItem == testSuite || modelItem == testSuite.getProject();
229 	}
230 
231 	protected void runTestSuite()
232 	{
233 		new Thread( testSuiteRunner, testSuite.getName() + " TestSuiteRunner" ).start();
234 	}
235 
236 	protected void beforeRun()
237 	{
238 		runAction.setEnabled( false );
239 		cancelAction.setEnabled( true );
240 		testCaseList.setEnabled( false );
241 		
242 		failedTests = false;
243 	}
244 
245 	protected void afterRun()
246 	{
247 		runAction.setEnabled( true );
248 		cancelAction.setEnabled( false );
249 		testCaseList.setEnabled( true );
250 		
251 		progressBar.setString( failedTests ? "Failed" : "Passed" );
252 		progressBar.setForeground( failedTests ? Color.RED : Color.GREEN.darker() );
253 	}
254 	
255 	private final class InternalTestSuiteListener extends TestSuiteListenerAdapter
256 	{
257 		public void testCaseAdded(TestCase testCase)
258 		{
259 			runAction.setEnabled( testSuite.getTestCaseCount() > 0 );
260 		}
261 
262 		public void testCaseRemoved(TestCase testCase)
263 		{
264 			runAction.setEnabled( testSuite.getTestCaseCount() > 0 );
265 		}
266 	}
267 
268 	private class RunAction extends AbstractAction
269 	{
270 		public RunAction()
271 		{
272 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/run_testcase.gif" ));
273 			putValue( Action.SHORT_DESCRIPTION, "Runs the selected TestCases" );
274 		}
275 		
276 		public void actionPerformed(ActionEvent e)
277 		{
278 			runTestSuite();
279 		}
280 	}
281 	
282 	private class CancelAction extends AbstractAction
283 	{
284 		public CancelAction()
285 		{
286 			putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/stop_testcase.gif" ));
287 			putValue( Action.SHORT_DESCRIPTION, "Cancels ongoing TestCase runs" );
288 		}
289 		
290 		public void actionPerformed(ActionEvent e)
291 		{
292 		   testSuiteRunner.cancel();
293 		}
294 	}
295 	
296 	/***
297 	 * Runs the selected testsuites..
298 	 * 
299 	 * @author Ole.Matzura
300 	 */
301 	
302 	public class TestSuiteRunner implements Runnable
303 	{
304 		private boolean canceled;
305 		private List<TestRunner> runners = new ArrayList<TestRunner>();
306 		private InternalTestRunListener internalTestRunListener = new InternalTestRunListener();
307 		
308 		public void cancel()
309 		{
310 			canceled = true;
311 			
312 			for( TestRunner runner : runners )
313 			{
314 				runner.cancel( "Canceled from TestSuite" );
315 			}
316 		}
317 		
318 		public void run()
319 		{
320 			canceled = false;
321 			beforeRun();
322 			
323 			int[] indices = testCaseList.getSelectedIndices();
324 			if( indices.length == 0 )
325 			{
326 				indices = new int[testSuite.getTestCaseCount()];
327 				for( int c = 0; c < indices.length; c++ )
328 					indices[c] = c;
329 			}
330 			
331 			progressBar.setValue( 0 );
332 			progressBar.setString( "" ); 
333 			progressBar.setMaximum( indices.length );
334 			
335 			TestSuiteRunType runType = testSuite.getRunType();
336 			
337 			for( int c = 0; c < indices.length; c++ )
338 			{
339 				TestCase testCase = (TestCase) testSuite.getTestCaseAt( indices[c] );
340 				if( SoapUI.getTestMonitor().hasRunningLoadTest( testCase ))
341 				{
342 					progressBar.setString( "Skipping " + testCase.getName() );
343 					progressBar.setValue( c+1 );
344 					continue;
345 				}
346 				
347 				if( runType == TestSuiteRunType.PARALLEL )
348 				{
349 					testCase.addTestRunListener( internalTestRunListener );
350 					progressBar.setString( "Starting " + testCase.getName() );
351 				}
352 				else
353 				{
354 					progressBar.setString( "Running " + testCase.getName() );
355 				}
356 				
357 				TestRunner runner = testCase.run( PropertiesMap.EMPTY_MAP, true );
358 				runners.add( runner );
359 				
360 				if( runType == TestSuiteRunType.SEQUENTIAL )
361 				{
362 					runner.waitUntilFinished();
363 					progressBar.setValue( c+1 );
364 					runners.remove( runner );
365 				}
366 				
367 				if( canceled )
368 					break;
369 			}
370 
371 			if( runners.isEmpty() )
372 				afterRun();
373 		}
374 		
375 		/***
376 		 * Waits for running tests to finish when running in parallel
377 		 */
378 		
379 		private class InternalTestRunListener extends TestRunListenerAdapter
380 		{
381 			public void afterRun(TestRunner testRunner, TestRunContext runContext)
382 			{
383 				runners.remove( testRunner );
384 				testRunner.getTestCase().removeTestRunListener( this );
385 				
386 				progressBar.setValue( progressBar.getValue()+1 );
387 				
388 				if( runners.isEmpty() )
389 					WsdlTestSuiteDesktopPanel.this.afterRun();
390 				
391 				if( testRunner.getStatus() == TestRunner.Status.FAILED )
392 					failedTests = true;
393 			}
394 		}
395 	}
396 }