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    }