1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.testcase;
14
15 import java.awt.BorderLayout;
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Font;
19 import java.awt.event.ActionEvent;
20 import java.awt.event.MouseAdapter;
21 import java.awt.event.MouseEvent;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.PrintWriter;
25 import java.text.SimpleDateFormat;
26 import java.util.Date;
27 import java.util.HashSet;
28 import java.util.Set;
29
30 import javax.swing.AbstractAction;
31 import javax.swing.Action;
32 import javax.swing.BorderFactory;
33 import javax.swing.JLabel;
34 import javax.swing.JList;
35 import javax.swing.JPanel;
36 import javax.swing.JPopupMenu;
37 import javax.swing.JScrollPane;
38 import javax.swing.ListCellRenderer;
39
40 import com.eviware.soapui.SoapUI;
41 import com.eviware.soapui.impl.wsdl.testcase.TestCaseLogItem;
42 import com.eviware.soapui.impl.wsdl.testcase.TestCaseLogModel;
43 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner;
44 import com.eviware.soapui.model.settings.Settings;
45 import com.eviware.soapui.model.support.TestRunListenerAdapter;
46 import com.eviware.soapui.model.testsuite.TestRunContext;
47 import com.eviware.soapui.model.testsuite.TestRunner;
48 import com.eviware.soapui.model.testsuite.TestStepResult;
49 import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
50 import com.eviware.soapui.support.StringUtils;
51 import com.eviware.soapui.support.UISupport;
52 import com.eviware.soapui.support.action.swing.ActionList;
53 import com.eviware.soapui.support.action.swing.ActionSupport;
54 import com.eviware.soapui.support.components.JHyperlinkLabel;
55 import com.eviware.soapui.support.components.JXToolBar;
56 import com.eviware.x.form.XFormDialog;
57 import com.eviware.x.form.support.ADialogBuilder;
58 import com.eviware.x.form.support.AField;
59 import com.eviware.x.form.support.AForm;
60 import com.eviware.x.form.support.AField.AFieldType;
61
62 /***
63 * Panel for displaying TestStepResults
64 *
65 * @author Ole.Matzura
66 */
67
68 public class TestRunLog extends JPanel
69 {
70 private TestCaseLogModel logListModel;
71 private JList testLogList;
72 private boolean errorsOnly = false;
73 private final Settings settings;
74 private Set<String> boldTexts = new HashSet<String>();
75 private boolean follow = true;
76 protected int selectedIndex;
77 private XFormDialog optionsDialog;
78
79 public TestRunLog( Settings settings )
80 {
81 super(new BorderLayout());
82 this.settings = settings;
83
84 errorsOnly = settings.getBoolean( OptionsForm.class.getName() + "@errors_only" );
85
86 buildUI();
87 }
88
89 private void buildUI()
90 {
91 logListModel = new TestCaseLogModel();
92 logListModel.setMaxSize( ( int ) settings.getLong(OptionsForm.class.getName() + "@max_rows", 1000 ) );
93
94 testLogList = new JList(logListModel);
95 testLogList.setCellRenderer(new TestLogCellRenderer());
96 testLogList.setPrototypeCellValue( "Testing 123" );
97 testLogList.setFixedCellWidth( -1 );
98 testLogList.addMouseListener(new LogListMouseListener());
99
100 JScrollPane scrollPane = new JScrollPane(testLogList);
101 add(scrollPane, BorderLayout.CENTER);
102 add( buildToolbar(), BorderLayout.NORTH );
103 }
104
105 private Component buildToolbar( )
106 {
107 JXToolBar toolbar = UISupport.createSmallToolbar();
108
109 addToolbarButtons( toolbar );
110
111 return toolbar;
112 }
113
114 protected JList getTestLogList()
115 {
116 return testLogList;
117 }
118
119 protected void addToolbarButtons( JXToolBar toolbar )
120 {
121 toolbar.addFixed( UISupport.createToolbarButton( new ClearLogAction() ) );
122 toolbar.addFixed( UISupport.createToolbarButton( new SetLogOptionsAction() ) );
123 toolbar.addFixed( UISupport.createToolbarButton( new ExportLogAction() ) );
124 }
125
126 private final class TestLogCellRenderer extends JLabel implements ListCellRenderer
127 {
128 private Font boldFont;
129 private Font normalFont;
130 private JHyperlinkLabel hyperlinkLabel = new JHyperlinkLabel("");
131
132 public TestLogCellRenderer()
133 {
134 setOpaque(true);
135 setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
136 setIcon(null);
137 boldFont = getFont().deriveFont( Font.BOLD );
138 normalFont = getFont();
139
140 hyperlinkLabel.setOpaque( true );
141 hyperlinkLabel.setForeground( Color.BLUE.darker().darker().darker() );
142 hyperlinkLabel.setUnderlineColor( Color.GRAY );
143 hyperlinkLabel.setBorder( BorderFactory.createEmptyBorder( 0, 4, 3, 3 ) );
144 }
145
146 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
147 boolean cellHasFocus)
148 {
149 if (isSelected)
150 {
151 setBackground(list.getSelectionBackground());
152 setForeground(list.getSelectionForeground());
153 }
154 else
155 {
156 setBackground(list.getBackground());
157 setForeground(list.getForeground());
158 }
159
160 if (value instanceof String)
161 {
162 setText(value.toString());
163 }
164 else if (value instanceof TestCaseLogItem)
165 {
166 TestCaseLogItem logItem = (TestCaseLogItem) value;
167 String msg = logItem.getMsg();
168 setText(msg == null ? "" : msg);
169 }
170
171 TestStepResult result = logListModel.getResultAt(index);
172 if( result != null && !result.isDiscarded() && result.getActions() != null && !getText().startsWith( " ->" ))
173 {
174 hyperlinkLabel.setText( getText() );
175 hyperlinkLabel.setBackground( getBackground() );
176 hyperlinkLabel.setEnabled( list.isEnabled() );
177
178 if( result.getStatus() == TestStepStatus.OK )
179 {
180 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/valid_assertion.gif" ) );
181 }
182 else if( result.getStatus() == TestStepStatus.FAILED )
183 {
184 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/failed_assertion.gif" ) );
185 }
186 else
187 {
188 hyperlinkLabel.setIcon( UISupport.createImageIcon( "/unknown_assertion.gif" ) );
189 }
190
191 return hyperlinkLabel;
192 }
193
194 setEnabled(list.isEnabled());
195
196 if( boldTexts.contains( getText() ))
197 {
198 setFont( boldFont);
199 }
200 else
201 {
202 setFont( normalFont );
203 }
204
205 return this;
206 }
207 }
208
209 /***
210 * Mouse Listener for triggering default action and showing popup for log list items
211 *
212 * @author Ole.Matzura
213 */
214
215 private final class LogListMouseListener extends MouseAdapter
216 {
217 public void mouseClicked(MouseEvent e)
218 {
219 int index = testLogList.getSelectedIndex();
220 if ( index != -1 && (index == selectedIndex || e.getClickCount() > 1))
221 {
222 TestStepResult result = logListModel.getResultAt(index);
223 if (result != null && result.getActions() != null)
224 result.getActions().performDefaultAction(new ActionEvent(this, 0, null));
225 }
226
227 selectedIndex = index;
228 }
229
230 public void mousePressed(MouseEvent e)
231 {
232 if (e.isPopupTrigger())
233 showPopup(e);
234 }
235
236 public void mouseReleased(MouseEvent e)
237 {
238 if (e.isPopupTrigger())
239 showPopup(e);
240 }
241
242 public void showPopup(MouseEvent e)
243 {
244 int row = testLogList.locationToIndex(e.getPoint());
245 if (row == -1)
246 return;
247
248 if (testLogList.getSelectedIndex() != row)
249 {
250 testLogList.setSelectedIndex(row);
251 }
252
253 TestStepResult result = logListModel.getResultAt(row);
254 if (result == null)
255 return;
256
257 ActionList actions = result.getActions();
258
259 if (actions == null || actions.getActionCount() == 0)
260 return;
261
262 JPopupMenu popup = ActionSupport.buildPopup(actions);
263 UISupport.showPopup(popup, testLogList, e.getPoint());
264 }
265 }
266
267 public void clear()
268 {
269 logListModel.clear();
270 boldTexts.clear();
271 }
272
273 public void addText(String string)
274 {
275 logListModel.addText( string );
276 if( follow )
277 testLogList.ensureIndexIsVisible( logListModel.getSize()-1 );
278 }
279
280 public void addTestStepResult(TestStepResult stepResult)
281 {
282 if( errorsOnly && stepResult.getStatus() != TestStepResult.TestStepStatus.FAILED )
283 return;
284
285 logListModel.addTestStepResult( stepResult );
286 if( follow )
287 testLogList.ensureIndexIsVisible( logListModel.getSize()-1 );
288 }
289
290 public TestCaseLogModel getLogListModel()
291 {
292 return logListModel;
293 }
294
295 public void setLogListModel(TestCaseLogModel logListModel)
296 {
297 this.logListModel = logListModel;
298 testLogList.setModel( logListModel );
299 }
300
301 private class SetLogOptionsAction extends AbstractAction
302 {
303 public SetLogOptionsAction()
304 {
305 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/options.gif" ));
306 putValue( Action.SHORT_DESCRIPTION, "Sets TestCase Log Options");
307 }
308
309 public void actionPerformed( ActionEvent e )
310 {
311 if( optionsDialog == null )
312 optionsDialog = ADialogBuilder.buildDialog( OptionsForm.class );
313
314 optionsDialog.setIntValue( OptionsForm.MAXROWS, ( int ) settings.getLong(
315 OptionsForm.class.getName() + "@max_rows", 1000 ));
316 optionsDialog.setBooleanValue( OptionsForm.DISCARDREMOVED, settings.getBoolean(
317 OptionsForm.class.getName() + "@discard_removed" ));
318 optionsDialog.setBooleanValue( OptionsForm.ERRORSONLY, settings.getBoolean(
319 OptionsForm.class.getName() + "@errors_only" ));
320 optionsDialog.setBooleanValue( OptionsForm.FOLLOW, follow );
321
322 if( optionsDialog.show() )
323 {
324 int maxRows = optionsDialog.getIntValue( OptionsForm.MAXROWS, 1000 );
325 logListModel.setMaxSize( maxRows );
326 settings.setLong( OptionsForm.class.getName() + "@max_rows", maxRows );
327 errorsOnly = optionsDialog.getBooleanValue( OptionsForm.ERRORSONLY );
328 settings.setBoolean( OptionsForm.class.getName() + "@errors_only",
329 errorsOnly );
330
331 boolean discardRemoved = optionsDialog.getBooleanValue( OptionsForm.DISCARDREMOVED );
332 settings.setBoolean( OptionsForm.class.getName() + "@discard_removed", discardRemoved );
333 logListModel.setDiscardRemoved( discardRemoved );
334
335 follow = optionsDialog.getBooleanValue( OptionsForm.FOLLOW );
336 }
337 }
338 }
339
340 @AForm( name="Log Options", description="Set options for the run log below" )
341 private static interface OptionsForm
342 {
343 @AField( name="Max Rows", description="Sets the maximum number of rows to keep in the log", type=AFieldType.INT)
344 public static final String MAXROWS = "Max Rows";
345
346 @AField( name="Discard Removed", description="Discards TestStep results rolled out from log", type=AFieldType.BOOLEAN)
347 public static final String DISCARDREMOVED = "Discard Removed";
348
349 @AField( name="Errors Only", description="Logs only TestStep errors in the log", type=AFieldType.BOOLEAN)
350 public static final String ERRORSONLY = "Errors Only";
351
352 @AField( name="Follow", description="Follow log content", type=AFieldType.BOOLEAN)
353 public static final String FOLLOW = "Follow";
354 }
355
356 private class ClearLogAction extends AbstractAction
357 {
358 public ClearLogAction()
359 {
360 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/clear_loadtest.gif" ));
361 putValue( Action.SHORT_DESCRIPTION, "Clears the log");
362 }
363
364 public void actionPerformed( ActionEvent e )
365 {
366 logListModel.clear();
367 }
368 }
369
370 private class ExportLogAction extends AbstractAction
371 {
372 public ExportLogAction()
373 {
374 putValue( Action.SMALL_ICON, UISupport.createImageIcon( "/export.gif" ));
375 putValue( Action.SHORT_DESCRIPTION, "Exports this log to a file");
376 }
377
378 public void actionPerformed( ActionEvent e )
379 {
380 File file = UISupport.getFileDialogs().saveAs( this, "Save Log" );
381 if( file != null )
382 {
383 try
384 {
385 PrintWriter out = new PrintWriter( file );
386 for( int c = 0; c < logListModel.getSize(); c++ )
387 {
388 Object value = logListModel.getElementAt( c );
389 if (value instanceof String)
390 {
391 out.println(value.toString());
392 }
393 else if (value instanceof TestCaseLogItem)
394 {
395 TestCaseLogItem logItem = (TestCaseLogItem) value;
396 String msg = logItem.getMsg();
397 if( StringUtils.hasContent( msg ))
398 out.println( msg);
399 }
400 }
401
402 out.close();
403 }
404 catch( FileNotFoundException e1 )
405 {
406 UISupport.showErrorMessage( e1 );
407 }
408 }
409 }
410 }
411
412 public static class TestRunLogTestRunListener extends TestRunListenerAdapter
413 {
414 private SimpleDateFormat dateFormat;
415 private final TestRunLog runLog;
416 private final boolean clearOnRun;
417
418 public TestRunLogTestRunListener( TestRunLog runLog, boolean clearOnRun )
419 {
420 this.runLog = runLog;
421 this.clearOnRun = clearOnRun;
422 dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS" );
423 }
424
425 public void beforeRun( TestRunner testRunner, TestRunContext runContext )
426 {
427 if( SoapUI.getTestMonitor().hasRunningLoadTest( testRunner.getTestCase() ) )
428 return;
429
430 if( clearOnRun )
431 runLog.clear();
432
433 String testCaseName = testRunner.getTestCase().getName();
434 runLog.addBoldText( "TestCase [" + testCaseName + "] started at " + dateFormat.format( new Date() ) );
435 runLog.setStepIndex( 0 );
436 }
437
438 public void afterRun( TestRunner testRunner, TestRunContext runContext )
439 {
440 if( SoapUI.getTestMonitor().hasRunningLoadTest( testRunner.getTestCase() ) )
441 return;
442
443 WsdlTestCaseRunner wsdlRunner = ( WsdlTestCaseRunner ) testRunner;
444
445 String testCaseName = testRunner.getTestCase().getName();
446 if( testRunner.getStatus() == TestRunner.Status.CANCELED )
447 runLog.addText( "TestCase [" + testCaseName + "] canceled [" + testRunner.getReason() + "], time taken = "
448 + wsdlRunner.getTimeTaken() );
449 else if( testRunner.getStatus() == TestRunner.Status.FAILED )
450 {
451 String msg = wsdlRunner.getReason();
452 if( wsdlRunner.getError() != null )
453 {
454 if( msg != null )
455 msg += ":";
456
457 msg += wsdlRunner.getError();
458 }
459
460 runLog.addText( "TestCase [" + testCaseName + "] failed [" + msg + "], time taken = "
461 + wsdlRunner.getTimeTaken() );
462 }
463 else
464 runLog.addText( "TestCase [" + testCaseName + "] finished with status [" + testRunner.getStatus() + "], time taken = " + wsdlRunner.getTimeTaken() );
465 }
466
467 public void afterStep( TestRunner testRunner, TestRunContext runContext, TestStepResult stepResult )
468 {
469 if( SoapUI.getTestMonitor().hasRunningLoadTest( testRunner.getTestCase() ) )
470 return;
471
472 runLog.addTestStepResult( stepResult );
473 }
474 }
475
476 public void setStepIndex( int i )
477 {
478 logListModel.setStepIndex( i );
479
480 }
481
482 public void addBoldText( String string )
483 {
484 boldTexts.add( string );
485 addText( string );
486 }
487
488 public void release()
489 {
490 if( optionsDialog != null )
491 {
492 optionsDialog.release();
493 optionsDialog = null;
494 }
495 }
496 }