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 }