001 /****************************************************************************** 002 * Copyright (C) MActor Developers. All rights reserved. * 003 * ---------------------------------------------------------------------------* 004 * This file is part of MActor. * 005 * * 006 * MActor is free software; you can redistribute it and/or modify * 007 * it under the terms of the GNU General Public License as published by * 008 * the Free Software Foundation; either version 2 of the License, or * 009 * (at your option) any later version. * 010 * * 011 * MActor is distributed in the hope that it will be useful, * 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 014 * GNU General Public License for more details. * 015 * * 016 * You should have received a copy of the GNU General Public License * 017 * along with MActor; if not, write to the Free Software * 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * 019 ******************************************************************************/ 020 package org.mactor.ui.gui.testrunner; 021 022 import java.awt.BorderLayout; 023 import java.awt.Color; 024 import java.awt.Component; 025 import java.awt.FlowLayout; 026 import java.awt.Font; 027 import java.util.HashMap; 028 import java.util.Map; 029 030 import javax.swing.JButton; 031 import javax.swing.JLabel; 032 import javax.swing.JPanel; 033 import javax.swing.JScrollPane; 034 import javax.swing.JSplitPane; 035 import javax.swing.JTable; 036 import javax.swing.ListSelectionModel; 037 import javax.swing.SwingUtilities; 038 import javax.swing.event.ListSelectionEvent; 039 import javax.swing.event.ListSelectionListener; 040 import javax.swing.table.AbstractTableModel; 041 import javax.swing.table.TableCellRenderer; 042 043 import org.mactor.framework.MactorException; 044 import org.mactor.framework.TestEvent; 045 import org.mactor.framework.TestFeedbackListener; 046 import org.mactor.framework.TestRunner; 047 import org.mactor.framework.TestEvent.EventType; 048 import org.mactor.framework.data.DataProviderFactory; 049 import org.mactor.framework.data.DataTable; 050 import org.mactor.framework.spec.SpecNode; 051 import org.mactor.framework.spec.TestRunSpec; 052 import org.mactor.framework.spec.TestSpec; 053 import org.mactor.ui.gui.AsyncAction; 054 import org.mactor.ui.gui.GuiUtil; 055 import org.mactor.ui.gui.Stoppable; 056 import org.mactor.ui.gui.project.ProjectNodeType; 057 import org.mactor.ui.gui.project.ProjectTreeNode; 058 import org.mactor.ui.gui.project.ProjectTreeUtil; 059 import org.mactor.ui.gui.project.editors.SimpleFormPanel; 060 import org.mactor.ui.gui.testrunner.RunningTestTreePanel.RunningTestModel; 061 062 public class TestRunPanel extends JPanel implements Stoppable { 063 RunningTestTreePanel rtPanel; 064 TestRunner tr; 065 TestResultTableModel tableModel = new TestResultTableModel(new DataTable()); 066 JTable table = new JTable(tableModel); 067 Map<String, RunningTestModel> modelMap = new HashMap<String, RunningTestModel>(); 068 TestFeedbackListener tfl = new TestFeedbackListener() { 069 public void onNodeEvent(final org.mactor.framework.TestEvent event, org.mactor.framework.TestContext context) { 070 if (event.isStartEventType() || event.isTestCompleteEvent()) { 071 SwingUtilities.invokeLater(new Runnable() { 072 public void run() { 073 RunningTestModel rtModel = modelMap.get(event.getDataId() + ""); 074 if (rtModel != null) { 075 rtModel.addEvent(event); 076 tableModel.setLastEvent(event); 077 } else { 078 System.out.println("Receivned unexpected event with data id " + event.getDataId()); 079 } 080 }; 081 }); 082 } 083 }; 084 public void onTestRunCompleted(String testRunInstanceId, int succededCount, int failedCount) { 085 runTest.setEnabled(true); 086 loadDataButton.setEnabled(true); 087 stopTest.setEnabled(false); 088 } 089 }; 090 JButton runTest = new JButton(new AsyncAction("Run Test", false, new AsyncAction.AsyncRunnable() { 091 public void run() { 092 try { 093 tr = new TestRunner(testRun.getThreadCount(), test, loadData(), tfl); 094 tr.start(); 095 data = null; 096 runTest.setEnabled(false); 097 loadDataButton.setEnabled(false); 098 stopTest.setEnabled(true); 099 } catch (MactorException me) { 100 GuiUtil.showGuiError(TestRunPanel.this, me); 101 } 102 } 103 })); 104 JButton stopTest = new JButton(new AsyncAction("Stop Test", true, new AsyncAction.AsyncRunnable() { 105 public void run() { 106 stop(); 107 } 108 })); 109 JButton loadDataButton = new JButton(new AsyncAction("Load Data", false, new AsyncAction.AsyncRunnable() { 110 public void run() { 111 try { 112 data = null; 113 loadData(); 114 } catch (MactorException me) { 115 GuiUtil.showGuiError(TestRunPanel.this, me); 116 } 117 } 118 })); 119 DataTable data; 120 DataTable loadData() throws MactorException { 121 if (data == null) { 122 System.out.println("loading"); 123 data = DataProviderFactory.getDataProvider(testRun.getDataSource()).loadData(); 124 int rowCount = data.getRowCount(); 125 for (int i = 0; i < rowCount; i++) { // init models 126 modelMap.put(i + "", new RunningTestModel()); 127 } 128 tableModel = new TestResultTableModel(data); 129 table.setModel(tableModel); 130 } 131 return data; 132 } 133 private ProjectTreeNode findTestNode(ProjectTreeNode node, String testName) throws MactorException { 134 ProjectTreeNode testRoot = ProjectTreeUtil.navigateToFirstFileNodeOfType(ProjectNodeType.T_TEST, node).getParentNode(); 135 if (testRoot == null) 136 throw new MactorException("Test node not found:" + testName); 137 for (ProjectTreeNode test : testRoot.getChildNodes()) 138 if (test.getName().equals(testName)) 139 return test; 140 throw new MactorException("Test node not found:" + testName); 141 } 142 TestSpec test; 143 TestRunSpec testRun; 144 int numberOfTestThreads; 145 public TestRunPanel(ProjectTreeNode node) throws MactorException { 146 super(new BorderLayout()); 147 this.testRun = TestRunSpec.loadFromFile(node.getName()); 148 this.test = TestSpec.loadFromFile(this.testRun.getTest()); 149 ProjectTreeNode testNode = findTestNode(node, test.getName()); 150 rtPanel = new RunningTestTreePanel(testNode); 151 JPanel bp = new JPanel(new FlowLayout()); 152 bp.add(loadDataButton); 153 SimpleFormPanel sf = new SimpleFormPanel(); 154 sf.add(bp); 155 sf.add(new JLabel("Test Data:")); 156 JPanel leftPanel = new JPanel(new BorderLayout()); 157 leftPanel.add(sf, BorderLayout.NORTH); 158 leftPanel.add(new JScrollPane(table), BorderLayout.CENTER); 159 JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rtPanel); 160 sp.setDividerLocation(400); 161 add(sp, BorderLayout.CENTER); 162 JPanel buttonPanel = new JPanel(new FlowLayout()); 163 buttonPanel.add(runTest); 164 buttonPanel.add(stopTest); 165 stopTest.setEnabled(false); 166 add(buttonPanel, BorderLayout.NORTH); 167 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 168 // table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 169 table.setDefaultRenderer(String.class, new TestResultTableRenderer()); 170 table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 171 public void valueChanged(ListSelectionEvent event) { 172 SwingUtilities.invokeLater(new Runnable() { 173 public void run() { 174 int row = table.getSelectedRow(); 175 RunningTestModel rtModel = modelMap.get(row + ""); 176 if (rtModel != null) { 177 rtPanel.setModel(rtModel); 178 } else { 179 System.out.println("Model does not exist. Row:" + row); 180 } 181 } 182 }); 183 } 184 }); 185 } 186 public void stop() { 187 if (tr != null) { 188 tr.stop(); 189 tr = null; 190 } 191 stopTest.setEnabled(false); 192 runTest.setEnabled(true); 193 } 194 private class TestResultTableModel extends AbstractTableModel { 195 private int columnCount = 0; 196 private DataTable data; 197 private TestEvent[] lastEventArray; 198 public TestResultTableModel(DataTable data) { 199 this.columnCount = data.getColumnCount() + 2; 200 this.data = data; 201 this.lastEventArray = new TestEvent[data.getRowCount()]; 202 } 203 @Override 204 public String getColumnName(int index) { 205 if (index == columnCount - 2) 206 return "Status"; 207 if (index == columnCount - 1) 208 return "Last event"; 209 return data.getColumn(index); 210 } 211 public int getColumnCount() { 212 return columnCount; 213 } 214 public int getRowCount() { 215 return data.getRowCount(); 216 } 217 @Override 218 public Class<?> getColumnClass(int arg0) { 219 return String.class; 220 } 221 public Object getValueAt(int row, int col) { 222 if (col == columnCount - 2) 223 return getStatus(row); 224 if (col == columnCount - 1) 225 return getEventInfo(row); 226 return data.getValue(row, col); 227 } 228 public void setLastEvent(TestEvent event) { 229 lastEventArray[event.getDataId()] = event; 230 super.fireTableRowsUpdated(event.getDataId(), event.getDataId()); 231 } 232 private String getStatus(int row) { 233 if (lastEventArray[row] == null) 234 return "Not started"; 235 SpecNode node = lastEventArray[row].getNode(); 236 if ((node instanceof TestSpec) && lastEventArray[row].getEventType() == EventType.End) { 237 if (lastEventArray[row].isSuccessful()) 238 return "Successful"; 239 return "Failed"; 240 } 241 return "Running"; 242 } 243 private String getEventInfo(int row) { 244 if (lastEventArray[row] == null) 245 return ""; 246 SpecNode node = lastEventArray[row].getNode(); 247 if (lastEventArray[row].isStartEventType()) 248 return "Performing:" + node.getShortDescription(); 249 else if (lastEventArray[row].isSuccessful()) { 250 if (node instanceof TestSpec) 251 return "Test successfully completed"; 252 return "Succesfully completed:" + node.getShortDescription(); 253 } else 254 return "Test completed with failure"; 255 } 256 public void clearResults() { 257 this.lastEventArray = new TestEvent[data.getRowCount()]; 258 super.fireTableDataChanged(); 259 } 260 } 261 public class TestResultTableRenderer extends JLabel implements TableCellRenderer { 262 boolean isBordered = true; 263 Font RUNNING_FONT; 264 Font NOT_STARTED_FONT; 265 Font COMPLETED_FONT; 266 public TestResultTableRenderer() { 267 setOpaque(true); 268 RUNNING_FONT = getFont().deriveFont(Font.BOLD | Font.ITALIC); 269 NOT_STARTED_FONT = getFont().deriveFont(Font.PLAIN); 270 COMPLETED_FONT = getFont().deriveFont(Font.PLAIN); 271 } 272 public Component getTableCellRendererComponent(JTable table, Object object, boolean isSelected, boolean hasFocus, int row, int column) { 273 setText(object + ""); 274 setForeground(Color.BLACK); 275 TestEvent te = ((TestResultTableModel) table.getModel()).lastEventArray[row]; 276 if (te == null) { 277 setFont(NOT_STARTED_FONT); 278 setBackground(Color.WHITE); 279 } else if (te.isSuccessfulTestCompleteEvent()) { 280 setFont(COMPLETED_FONT); 281 setBackground(Color.GREEN); 282 } else if (te.isFaultTestCompleteEvent()) { 283 setFont(COMPLETED_FONT); 284 setBackground(Color.RED); 285 } else { 286 setFont(RUNNING_FONT); 287 setBackground(Color.WHITE); 288 } 289 if (isSelected) { 290 setBackground(Color.BLUE); 291 setForeground(Color.WHITE); 292 } 293 return this; 294 } 295 } 296 }