git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271010 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -54,6 +54,9 @@ | |||
| package org.apache.tools.ant.taskdefs.optional.junit; | |||
| import java.util.Properties; | |||
| import java.util.EventListener; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| @@ -67,27 +70,21 @@ import java.util.Properties; | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public interface TestRunListener { | |||
| /** Some tests failed. */ | |||
| public final static int STATUS_FAILURE = 1; | |||
| /** An error occured. */ | |||
| public final static int STATUS_ERROR = 2; | |||
| public interface TestRunListener extends EventListener{ | |||
| /** | |||
| * A test has started. | |||
| * @param a testname made of the testname and testcase classname. | |||
| * in the following format: <tt><testname>(<testcase>)</tt> | |||
| */ | |||
| public void onTestStarted(String testname); | |||
| public void onTestStarted(TestRunEvent evt); | |||
| /** | |||
| * A test ended. | |||
| * @param a testname made of the testname and testcase classname. | |||
| * in the following format: <tt><testname>(<testcase>)</tt> | |||
| */ | |||
| public void onTestEnded(String testname); | |||
| public void onTestEnded(TestRunEvent evt); | |||
| /** | |||
| * A test has failed. | |||
| @@ -97,24 +94,19 @@ public interface TestRunListener { | |||
| * @param trace the error/failure stacktrace. | |||
| * @todo change this to a testFailure / testError ? | |||
| */ | |||
| public void onTestFailed(int status, String testname, String trace); | |||
| /** test logged this line on stdout */ | |||
| public void onTestStdOutLine(String testname, String line); | |||
| /** test logged this line on sterr */ | |||
| public void onTestStdErrLine(String testname, String line); | |||
| public void onTestFailure(TestRunEvent evt); | |||
| /** these system properties are used on the remote client */ | |||
| public void onTestRunSystemProperties(Properties props); | |||
| public void onTestError(TestRunEvent evt); | |||
| /** starting a sequence of <tt>testcount</tt> tests. */ | |||
| public void onTestRunStarted(int testcount); | |||
| public void onRunStarted(TestRunEvent evt); | |||
| /** ending gracefully the sequence after <tt>elapsedtime</tt> ms. */ | |||
| public void onTestRunEnded(long elapsedtime); | |||
| public void onRunEnded(TestRunEvent evt); | |||
| /** stopping the sequence after <tt>elapsedtime</tt> ms. */ | |||
| public void onTestRunStopped(long elapsedtime); | |||
| public void onRunStopped(TestRunEvent evt); | |||
| public void onSuiteStarted(TestRunEvent evt); | |||
| public void onSuiteEnded(TestRunEvent evt); | |||
| } | |||
| @@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||
| import java.util.Properties; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * Provide a common set of attributes and methods to factorize | |||
| @@ -81,42 +82,39 @@ public abstract class BaseFormatter implements Formatter { | |||
| close(); | |||
| } | |||
| public void onTestStdOutLine(String testname, String line) { | |||
| public void onTestStarted(TestRunEvent evt) { | |||
| runCount++; | |||
| } | |||
| public void onTestStdErrLine(String testname, String line) { | |||
| public void onTestEnded(TestRunEvent evt) { | |||
| } | |||
| public void onTestRunSystemProperties(Properties props) { | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| failureCount++; | |||
| } | |||
| public void onTestStarted(String testname) { | |||
| public void onTestError(TestRunEvent evt) { | |||
| errorCount++; | |||
| } | |||
| public void onTestEnded(String testname) { | |||
| public void onSuiteStarted(TestRunEvent evt) { | |||
| } | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| if (status == STATUS_ERROR) { | |||
| errorCount++; | |||
| } else if (status == STATUS_FAILURE) { | |||
| failureCount++; | |||
| } | |||
| public void onSuiteEnded(TestRunEvent evt) { | |||
| } | |||
| public void onTestRunStarted(int testcount) { | |||
| runCount = testcount; | |||
| public void onRunStarted(TestRunEvent evt) { | |||
| } | |||
| public void onTestRunEnded(long elapsedtime) { | |||
| finished(elapsedtime); | |||
| public void onRunEnded(TestRunEvent evt) { | |||
| finished(); | |||
| } | |||
| public void onTestRunStopped(long elapsedtime) { | |||
| finished(elapsedtime); | |||
| public void onRunStopped(TestRunEvent evt) { | |||
| finished(); | |||
| } | |||
| protected void finished(long elapsedtime) { | |||
| protected void finished() { | |||
| close(); | |||
| } | |||
| @@ -55,6 +55,7 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
| import org.apache.avalon.excalibur.i18n.Resources; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * Display additional messages from a <tt>SummaryFormatter</tt> | |||
| @@ -67,15 +68,15 @@ public class BriefFormatter extends SummaryFormatter { | |||
| private final static Resources RES = | |||
| ResourceManager.getPackageResources(BriefFormatter.class); | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| String msg = null; | |||
| if (status == STATUS_ERROR) { | |||
| msg = RES.getString("brief.status-error.msg", testname, trace); | |||
| } else { | |||
| msg = RES.getString("brief.status-failure.msg", testname, trace); | |||
| } | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| String msg = RES.getString("brief.status-failure.msg", evt.getName(), evt.getStackTrace()); | |||
| getWriter().println(msg); | |||
| super.onTestFailed(status, testname, trace); | |||
| super.onTestFailure(evt); | |||
| } | |||
| public void onTestError(TestRunEvent evt) { | |||
| String msg = RES.getString("brief.status-error.msg", evt.getName(), evt.getStackTrace()); | |||
| getWriter().println(msg); | |||
| super.onTestError(evt); | |||
| } | |||
| } | |||
| @@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||
| import java.util.Properties; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * A base class that can be used to filter data. | |||
| @@ -75,40 +76,40 @@ public abstract class FilterFormatter implements Formatter { | |||
| formatter.init(props); | |||
| } | |||
| public void onTestStdOutLine(String testname, String line) { | |||
| formatter.onTestStdOutLine(testname, line); | |||
| public void onSuiteStarted(TestRunEvent evt) { | |||
| formatter.onSuiteStarted(evt); | |||
| } | |||
| public void onTestStdErrLine(String testname, String line) { | |||
| formatter.onTestStdErrLine(testname, line); | |||
| public void onSuiteEnded(TestRunEvent evt) { | |||
| formatter.onSuiteEnded(evt); | |||
| } | |||
| public void onTestStarted(String testname) { | |||
| formatter.onTestStarted(testname); | |||
| public void onTestStarted(TestRunEvent evt) { | |||
| formatter.onTestStarted(evt); | |||
| } | |||
| public void onTestEnded(String testname) { | |||
| formatter.onTestEnded(testname); | |||
| public void onTestEnded(TestRunEvent evt) { | |||
| formatter.onTestEnded(evt); | |||
| } | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| formatter.onTestFailed(status, testname, trace); | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| formatter.onTestFailure(evt); | |||
| } | |||
| public void onTestRunSystemProperties(Properties props) { | |||
| formatter.onTestRunSystemProperties(props); | |||
| public void onTestError(TestRunEvent evt) { | |||
| formatter.onTestError(evt); | |||
| } | |||
| public void onTestRunStarted(int testcount) { | |||
| formatter.onTestRunStarted(testcount); | |||
| public void onRunStarted(TestRunEvent evt) { | |||
| formatter.onRunStarted(evt); | |||
| } | |||
| public void onTestRunEnded(long elapsedtime) { | |||
| formatter.onTestRunEnded(elapsedtime); | |||
| public void onRunEnded(TestRunEvent evt) { | |||
| formatter.onRunEnded(evt); | |||
| } | |||
| public void onTestRunStopped(long elapsedtime) { | |||
| formatter.onTestRunEnded(elapsedtime); | |||
| public void onRunStopped(TestRunEvent evt) { | |||
| formatter.onRunEnded(evt); | |||
| } | |||
| /** set the wrapped formatter */ | |||
| @@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||
| import java.util.StringTokenizer; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * Filtered Formatter that strips out unwanted stack frames from the full | |||
| @@ -99,7 +100,19 @@ public class FilterStackFormatter extends FilterFormatter { | |||
| super(formatter); | |||
| } | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| String filteredTrace = filter(evt.getStackTrace()); | |||
| evt.setStackTrace(filteredTrace); | |||
| super.onTestFailure(evt); | |||
| } | |||
| public void onTestError(TestRunEvent evt) { | |||
| String filteredTrace = filter(evt.getStackTrace()); | |||
| evt.setStackTrace(filteredTrace); | |||
| super.onTestFailure(evt); | |||
| } | |||
| protected String filter(String trace){ | |||
| StringTokenizer st = new StringTokenizer(trace, "\r\n"); | |||
| StringBuffer buf = new StringBuffer(trace.length()); | |||
| while (st.hasMoreTokens()) { | |||
| @@ -108,9 +121,8 @@ public class FilterStackFormatter extends FilterFormatter { | |||
| buf.append(line).append(StringUtils.LINE_SEP); | |||
| } | |||
| } | |||
| super.onTestFailed(status, testname, buf.toString()); | |||
| return buf.toString(); | |||
| } | |||
| /** | |||
| * Check whether or not the line should be accepted. | |||
| * @param the line to be check for acceptance. | |||
| @@ -55,6 +55,8 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||
| import java.util.Properties; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * Default formatter to text. | |||
| * | |||
| @@ -62,38 +64,39 @@ import java.util.Properties; | |||
| */ | |||
| public class PlainFormatter extends BaseStreamFormatter { | |||
| public void onTestStarted(String testname) { | |||
| getWriter().println("Started " + testname); | |||
| } | |||
| public void onTestEnded(String testname) { | |||
| getWriter().println("Ended " + testname); | |||
| public void onSuiteStarted(TestRunEvent evt) { | |||
| getWriter().println(" suite: " + evt.getName()); | |||
| super.onSuiteStarted(evt); | |||
| } | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| getWriter().println(testname + " failed with status " + status); | |||
| getWriter().println(trace); | |||
| public void onSuiteEnded(TestRunEvent evt) { | |||
| getWriter().println(" end suite"); | |||
| super.onSuiteEnded(evt); | |||
| } | |||
| public void onTestRunSystemProperties(Properties props) { | |||
| getWriter().println("properties: " + props); | |||
| public void onTestStarted(TestRunEvent evt) { | |||
| getWriter().println(" running test: " + evt.getName()); | |||
| } | |||
| public void onTestRunStarted(int testcount) { | |||
| getWriter().println("testsuite: " + testcount); | |||
| public void onTestEnded(TestRunEvent evt) { | |||
| getWriter().println(" success: " + evt.getName()); | |||
| } | |||
| public void onTestStdOutLine(String testname, String line) { | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| getWriter().println(" failure: " + evt.getName()); | |||
| getWriter().println(evt.getStackTrace()); | |||
| } | |||
| public void onTestStdErrLine(String testname, String line) { | |||
| public void onTestError(TestRunEvent evt) { | |||
| getWriter().println(" error: " + evt.getName()); | |||
| getWriter().println(evt.getStackTrace()); | |||
| } | |||
| public void onTestRunEnded(long elapsedtime) { | |||
| getWriter().println("testsuite ended after: " + elapsedtime); | |||
| public void onRunEnded(TestRunEvent evt) { | |||
| getWriter().println("run ended"); | |||
| } | |||
| public void onTestRunStopped(long elapsedtime) { | |||
| getWriter().println("testsuite stopped after: " + elapsedtime); | |||
| public void onRunStopped(TestRunEvent evt) { | |||
| getWriter().println("run stopped"); | |||
| } | |||
| } | |||
| @@ -64,6 +64,7 @@ import org.w3c.dom.Text; | |||
| import org.apache.tools.ant.util.DOMElementWriter; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||
| /** | |||
| * XML Formatter. Due to the nature of the XML we are forced to store | |||
| @@ -140,67 +141,63 @@ public class XMLFormatter extends BaseStreamFormatter { | |||
| /** Timing helper. */ | |||
| private Hashtable testStarts = new Hashtable(); | |||
| public void onTestStarted(String testname) { | |||
| public void onTestStarted(TestRunEvent evt) { | |||
| //@fixme, eh, a testname only can obviouslly be a duplicate... | |||
| testStarts.put(testname, new Long(System.currentTimeMillis())); | |||
| testStarts.put(evt.getName(), evt); | |||
| Element currentTest = doc.createElement(TESTCASE); | |||
| currentTest.setAttribute(ATTR_NAME, testname); | |||
| currentTest.setAttribute(ATTR_NAME, evt.getName()); | |||
| rootElement.appendChild(currentTest); | |||
| testElements.put(testname, currentTest); | |||
| super.onTestStarted(testname); | |||
| testElements.put(evt.getName(), currentTest); | |||
| super.onTestStarted(evt); | |||
| removeEvent(evt); | |||
| } | |||
| public void onTestEnded(String testname) { | |||
| Element currentTest = (Element) testElements.get(testname); | |||
| public void onTestEnded(TestRunEvent evt) { | |||
| Element currentTest = (Element) testElements.get(evt); | |||
| // with a TestSetup, startTest and endTest are not called. | |||
| if (currentTest == null) { | |||
| onTestStarted(testname); | |||
| currentTest = (Element) testElements.get(testname); | |||
| onTestStarted(evt); | |||
| currentTest = (Element) testElements.get(evt.getName()); | |||
| } | |||
| Long l = (Long) testStarts.get(testname); | |||
| float time = ((System.currentTimeMillis() - l.longValue()) / 1000.0f); | |||
| TestRunEvent start = (TestRunEvent)testStarts.get(evt); | |||
| float time = ((evt.getTimeStamp() - start.getTimeStamp()) / 1000.0f); | |||
| currentTest.setAttribute(ATTR_TIME, Float.toString(time)); | |||
| super.onTestEnded(testname); | |||
| // remove the test objects | |||
| //testStarts.remove(testname); | |||
| //testElements.remove(testname); | |||
| super.onTestEnded(evt); | |||
| removeEvent(evt); | |||
| } | |||
| public void onTestFailed(int status, String testname, String trace) { | |||
| if (testname != null) { | |||
| onTestEnded(testname); | |||
| } | |||
| String type = status == STATUS_FAILURE ? FAILURE : ERROR; | |||
| public void onTestFailure(TestRunEvent evt) { | |||
| String type = evt == evt.getType() == TestRunEvent.TEST_FAILURE ? FAILURE : ERROR; | |||
| Element nested = doc.createElement(type); | |||
| Element currentTest = null; | |||
| if (testname != null) { | |||
| currentTest = (Element) testElements.get(testname); | |||
| } else { | |||
| currentTest = rootElement; | |||
| } | |||
| Element currentTest = (Element) testElements.get(evt.getName()); | |||
| currentTest.appendChild(nested); | |||
| String[] args = parseFirstLine(trace); | |||
| String[] args = parseFirstLine(evt.getStackTrace()); | |||
| if (args[1] != null && args[1].length() > 0) { | |||
| nested.setAttribute(ATTR_MESSAGE, args[1]); | |||
| } | |||
| nested.setAttribute(ATTR_TYPE, args[0]); | |||
| Text text = doc.createTextNode(trace); | |||
| Text text = doc.createTextNode(evt.getStackTrace()); | |||
| nested.appendChild(text); | |||
| super.onTestFailed(status, testname, trace); | |||
| super.onTestFailure(evt); | |||
| removeEvent(evt); | |||
| } | |||
| protected void removeEvent(TestRunEvent evt){ | |||
| testStarts.remove(evt.getName()); | |||
| testElements.remove(evt.getName()); | |||
| } | |||
| public void onTestRunStarted(int testcount) { | |||
| super.onTestRunStarted(testcount); | |||
| public void onRunStarted(TestRunEvent evt) { | |||
| super.onRunStarted(evt); | |||
| } | |||
| public void onTestRunEnded(long elapsedtime) { | |||
| super.onTestRunEnded(elapsedtime); | |||
| public void onRunEnded(TestRunEvent evt) { | |||
| super.onRunEnded(evt); | |||
| } | |||
| public void onTestRunStopped(long elapsedtime) { | |||
| super.onTestRunStopped(elapsedtime); | |||
| public void onRunStopped(TestRunEvent evt) { | |||
| super.onRunStopped(evt); | |||
| } | |||
| protected void close() { | |||
| @@ -0,0 +1,195 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.junit.remote; | |||
| import java.util.Vector; | |||
| import java.io.InputStream; | |||
| import java.io.IOException; | |||
| import java.io.BufferedReader; | |||
| import java.io.InputStreamReader; | |||
| /** | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public class EventDispatcher { | |||
| /** the set of registered listeners */ | |||
| private Vector listeners = new Vector(); | |||
| /** | |||
| * Add a new listener. | |||
| * @param listener a listener that will receive events from the client. | |||
| */ | |||
| public void addListener(TestRunListener listener) { | |||
| listeners.addElement(listener); | |||
| } | |||
| public void removeListener(org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener listener) { | |||
| listeners.removeElement(listener); | |||
| } | |||
| /** | |||
| * Process a message from the client and dispatch the | |||
| * appropriate message to the listeners. | |||
| */ | |||
| public void dispatchEvent(TestRunEvent evt) { | |||
| // I hate switch/case but no need to design a complex | |||
| // system for limited events. | |||
| switch (evt.getType()){ | |||
| case TestRunEvent.RUN_STARTED: | |||
| fireRunStarted(evt); | |||
| break; | |||
| case TestRunEvent.RUN_ENDED: | |||
| fireRunEnded(evt); | |||
| break; | |||
| case TestRunEvent.RUN_STOPPED: | |||
| fireRunStopped(evt); | |||
| break; | |||
| case TestRunEvent.TEST_STARTED: | |||
| fireTestStarted(evt); | |||
| break; | |||
| case TestRunEvent.TEST_ERROR: | |||
| fireTestError(evt); | |||
| break; | |||
| case TestRunEvent.TEST_FAILURE: | |||
| fireTestFailure(evt); | |||
| break; | |||
| case TestRunEvent.TEST_ENDED: | |||
| fireTestEnded(evt); | |||
| break; | |||
| case TestRunEvent.TESTSUITE_ENDED: | |||
| fireSuiteEnded(evt); | |||
| break; | |||
| case TestRunEvent.TESTSUITE_STARTED: | |||
| fireSuiteStarted(evt); | |||
| break; | |||
| default: | |||
| // should not happen | |||
| } | |||
| } | |||
| protected void fireRunStarted(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onRunStarted(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireRunEnded(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onRunEnded(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireTestStarted(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onTestStarted(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireTestEnded(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onTestEnded(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireTestFailure(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onTestFailure(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireTestError(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onTestError(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireSuiteStarted(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onSuiteStarted(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireSuiteEnded(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onSuiteEnded(evt); | |||
| } | |||
| } | |||
| } | |||
| protected void fireRunStopped(TestRunEvent evt) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunListener) listeners.elementAt(i)).onRunStopped(evt); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -203,7 +203,7 @@ public class MessageReader { | |||
| protected void notifyTestFailed(int kind, String testname, String trace) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((TestRunListener) listeners.elementAt(i)).onTestFailed(kind, testname, trace); | |||
| ((TestRunListener) listeners.elementAt(i)).onTestFailure(kind); | |||
| } | |||
| } | |||
| } | |||
| @@ -211,7 +211,7 @@ public class MessageReader { | |||
| protected void notifyTestSuiteStarted(int count) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((TestRunListener) listeners.elementAt(i)).onTestRunStarted(count); | |||
| ((TestRunListener) listeners.elementAt(i)).onRunStarted(count); | |||
| } | |||
| } | |||
| } | |||
| @@ -219,7 +219,7 @@ public class MessageReader { | |||
| protected void notifyTestSuiteEnded(long elapsedtime) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((TestRunListener) listeners.elementAt(i)).onTestRunEnded(elapsedtime); | |||
| ((TestRunListener) listeners.elementAt(i)).onRunEnded(elapsedtime); | |||
| } | |||
| } | |||
| } | |||
| @@ -227,7 +227,7 @@ public class MessageReader { | |||
| protected void notifyTestSuiteStopped(long elapsedtime) { | |||
| synchronized (listeners) { | |||
| for (int i = 0; i < listeners.size(); i++) { | |||
| ((TestRunListener) listeners.elementAt(i)).onTestRunStopped(elapsedtime); | |||
| ((TestRunListener) listeners.elementAt(i)).onRunStopped(elapsedtime); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.junit.remote; | |||
| import java.io.OutputStream; | |||
| import java.io.InputStream; | |||
| import java.io.IOException; | |||
| import java.io.ObjectInputStream; | |||
| import java.io.ObjectOutputStream; | |||
| /** | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public class Messenger { | |||
| private InputStream in; | |||
| private OutputStream out; | |||
| public Messenger(InputStream in, OutputStream out) throws IOException { | |||
| setOutputStream( new ObjectOutputStream(out) ); | |||
| setInputStream( new ObjectInputStream(in) ); | |||
| } | |||
| protected void finalize() throws Throwable { | |||
| close(); | |||
| } | |||
| public void close() throws IOException { | |||
| if (in != null) { | |||
| in.close(); | |||
| in = null; | |||
| } | |||
| if (out != null) { | |||
| out.flush(); | |||
| out.close(); | |||
| out = null; | |||
| } | |||
| } | |||
| public TestRunEvent read() throws IOException { | |||
| return (TestRunEvent)((ObjectInputStream)in).readObject(); | |||
| } | |||
| public void writeEvent(TestRunEvent evt) throws IOException { | |||
| ((ObjectOutputStream)out).writeObject(evt); | |||
| } | |||
| protected OutputStream getOutputStream(){ | |||
| return out; | |||
| } | |||
| protected InputStream getInputStream(){ | |||
| return in; | |||
| } | |||
| protected void setOutputStream(OutputStream out){ | |||
| this.out = out; | |||
| } | |||
| protected void setInputStream(InputStream in){ | |||
| this.in = in; | |||
| } | |||
| } | |||
| @@ -57,8 +57,6 @@ import java.io.IOException; | |||
| import java.net.ServerSocket; | |||
| import java.net.Socket; | |||
| import org.apache.tools.ant.taskdefs.optional.junit.TestRunListener; | |||
| /** | |||
| * The server that will receive events from a remote client. | |||
| * | |||
| @@ -83,10 +81,9 @@ public class Server { | |||
| private Socket client; | |||
| /** the reader in charge of interpreting messages from the client */ | |||
| private MessageReader reader = new MessageReader(); | |||
| private Messenger messenger; | |||
| /** writer used to send message to clients */ | |||
| private MessageWriter writer; | |||
| private EventDispatcher dispatcher = new EventDispatcher(); | |||
| public Server(int port) { | |||
| this.port = port; | |||
| @@ -102,7 +99,7 @@ public class Server { | |||
| * @param listener a instance of a listener. | |||
| */ | |||
| public void addListener(TestRunListener listener) { | |||
| reader.addListener(listener); | |||
| dispatcher.addListener(listener); | |||
| } | |||
| /** | |||
| @@ -110,7 +107,7 @@ public class Server { | |||
| * @param listener a instance of a listener. | |||
| */ | |||
| public void removeListener(TestRunListener listener) { | |||
| reader.removeListener(listener); | |||
| dispatcher.removeListener(listener); | |||
| } | |||
| /** return whether there is a client running or not */ | |||
| @@ -127,19 +124,16 @@ public class Server { | |||
| /** cancel the connection to the client */ | |||
| public void cancel() { | |||
| if (isRunning()) { | |||
| writer.sendMessage(MessageIds.TEST_STOP); | |||
| TestRunEvent evt = new TestRunEvent(new Integer(-1), TestRunEvent.RUN_STOP); | |||
| messenger.writeEvent(evt); | |||
| } | |||
| } | |||
| /** shutdown the server and any running client */ | |||
| public void shutdown() { | |||
| if (writer != null) { | |||
| writer.close(); | |||
| writer = null; | |||
| } | |||
| if (reader != null) { | |||
| //@fixme what about the stream ? | |||
| reader = null; | |||
| if (messenger != null) { | |||
| messenger.close(); | |||
| messenger = null; | |||
| } | |||
| try { | |||
| if (client != null) { | |||
| @@ -166,8 +160,11 @@ public class Server { | |||
| try { | |||
| server = new ServerSocket(port); | |||
| client = server.accept(); | |||
| writer = new MessageWriter(client.getOutputStream()); | |||
| reader.process(client.getInputStream()); | |||
| messenger = new Messenger(client.getInputStream(), client.getOutputStream()); | |||
| TestRunEvent evt = null; | |||
| while ( (evt = messenger.read()) != null ) { | |||
| dispatcher.dispatchEvent(evt); | |||
| } | |||
| } catch (IOException e) { | |||
| //@fixme this stacktrace might be normal when closing | |||
| // the socket. So decompose the above in distinct steps | |||
| @@ -0,0 +1,159 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.junit.remote; | |||
| import java.util.EventObject; | |||
| import java.util.Properties; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| /** | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public class TestRunEvent extends EventObject { | |||
| // received from clients | |||
| public final static int RUN_STARTED = 0; | |||
| public final static int RUN_ENDED = 1; | |||
| public final static int RUN_STOPPED = 2; | |||
| public final static int TEST_STARTED = 3; | |||
| public final static int TEST_FAILURE = 4; | |||
| public final static int TEST_ERROR = 5; | |||
| public final static int TEST_ENDED = 6; | |||
| public final static int SUITE_STARTED = 7; | |||
| public final static int SUITE_ENDED = 8; | |||
| // received from server | |||
| public final static int RUN_STOP = 9; | |||
| /** the type of event */ | |||
| private int type = -1; | |||
| /** timestamp for all tests */ | |||
| private long timestamp = System.currentTimeMillis(); | |||
| /** name of testcase(method name) or testsuite (classname) */ | |||
| private String name; | |||
| /** stacktrace for error or failure */ | |||
| private String stacktrace; | |||
| /** properties for end of testrun */ | |||
| private Properties props; | |||
| public TestRunEvent(Integer id, int type){ | |||
| super(id); | |||
| this.type = type; | |||
| } | |||
| public TestRunEvent(Integer id, int type, String name){ | |||
| this(id, type); | |||
| this.name = name; | |||
| } | |||
| public TestRunEvent(Integer id, int type, Properties props){ | |||
| this(id, type); | |||
| this.props = props; | |||
| } | |||
| public TestRunEvent(Integer id, int type, String name, Throwable t){ | |||
| this(id, type, name); | |||
| this.stacktrace = StringUtils.getStackTrace(t); | |||
| } | |||
| public void setType(int type) { | |||
| this.type = type; | |||
| } | |||
| public void setTimeStamp(long timestamp) { | |||
| this.timestamp = timestamp; | |||
| } | |||
| public void setStackTrace(String stacktrace) { | |||
| this.stacktrace = stacktrace; | |||
| } | |||
| public void setName(String name) { | |||
| this.name = name; | |||
| } | |||
| public void setProperties(Properties props) { | |||
| this.props = props; | |||
| } | |||
| public int getType(){ | |||
| return type; | |||
| } | |||
| public long getTimeStamp(){ | |||
| return timestamp; | |||
| } | |||
| public String getName(){ | |||
| return name; | |||
| } | |||
| public String getStackTrace(){ | |||
| return stacktrace; | |||
| } | |||
| public Properties getProperties(){ | |||
| return props; | |||
| } | |||
| public String toString(){ | |||
| return "Id: " + source + ", Type: " + type; | |||
| } | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2002 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| * modification, are permitted provided that the following conditions | |||
| * are met: | |||
| * | |||
| * 1. Redistributions of source code must retain the above copyright | |||
| * notice, this list of conditions and the following disclaimer. | |||
| * | |||
| * 2. Redistributions in binary form must reproduce the above copyright | |||
| * notice, this list of conditions and the following disclaimer in | |||
| * the documentation and/or other materials provided with the | |||
| * distribution. | |||
| * | |||
| * 3. The end-user documentation included with the redistribution, if | |||
| * any, must include the following acknowlegement: | |||
| * "This product includes software developed by the | |||
| * Apache Software Foundation (http://www.apache.org/)." | |||
| * Alternately, this acknowlegement may appear in the software itself, | |||
| * if and wherever such third-party acknowlegements normally appear. | |||
| * | |||
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software | |||
| * Foundation" must not be used to endorse or promote products derived | |||
| * from this software without prior written permission. For written | |||
| * permission, please contact apache@apache.org. | |||
| * | |||
| * 5. Products derived from this software may not be called "Apache" | |||
| * nor may "Apache" appear in their names without prior written | |||
| * permission of the Apache Group. | |||
| * | |||
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | |||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| * SUCH DAMAGE. | |||
| * ==================================================================== | |||
| * | |||
| * This software consists of voluntary contributions made by many | |||
| * individuals on behalf of the Apache Software Foundation. For more | |||
| * information on the Apache Software Foundation, please see | |||
| * <http://www.apache.org/>. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.junit.remote; | |||
| import java.util.EventListener; | |||
| /** | |||
| * | |||
| * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> | |||
| */ | |||
| public interface TestRunListener extends EventListener { | |||
| void onRunStarted(TestRunEvent evt); | |||
| void onRunEnded(TestRunEvent evt); | |||
| void onRunStopped(TestRunEvent evt); | |||
| void onSuiteStarted(TestRunEvent evt); | |||
| void onSuiteEnded(TestRunEvent evt); | |||
| void onTestStarted(TestRunEvent evt); | |||
| void onTestError(TestRunEvent evt); | |||
| void onTestFailure(TestRunEvent evt); | |||
| void onTestEnded(TestRunEvent evt); | |||
| } | |||
| @@ -61,6 +61,7 @@ import java.net.Socket; | |||
| import java.util.Properties; | |||
| import java.util.StringTokenizer; | |||
| import java.util.Vector; | |||
| import java.util.Random; | |||
| import junit.framework.AssertionFailedError; | |||
| import junit.framework.Test; | |||
| @@ -86,6 +87,9 @@ import org.apache.tools.ant.util.StringUtils; | |||
| */ | |||
| public class TestRunner implements TestListener { | |||
| /** unique identifier for the runner */ | |||
| private final Integer id = new Integer( (new Random()).nextInt() ); | |||
| /** host to connect to */ | |||
| private String host = "127.0.0.1"; | |||
| @@ -104,10 +108,7 @@ public class TestRunner implements TestListener { | |||
| private Socket clientSocket; | |||
| /** writer to send message to the server */ | |||
| private MessageWriter writer; | |||
| /** reader to listen for a shutdown from the server */ | |||
| private BufferedReader reader; | |||
| private Messenger messenger; | |||
| /** bean constructor */ | |||
| public TestRunner() { | |||
| @@ -152,9 +153,9 @@ public class TestRunner implements TestListener { | |||
| private class StopThread extends Thread { | |||
| public void run() { | |||
| try { | |||
| String line = null; | |||
| if ((line = reader.readLine()) != null) { | |||
| if (line.startsWith(MessageIds.TEST_STOP)) { | |||
| TestRunEvent evt = null; | |||
| if ((evt = messenger.read()) != null) { | |||
| if (evt.getType() == TestRunEvent.RUN_STOP) { | |||
| TestRunner.this.stop(); | |||
| } | |||
| } | |||
| @@ -298,26 +299,26 @@ public class TestRunner implements TestListener { | |||
| // count all testMethods and inform TestRunListeners | |||
| int count = countTests(suites); | |||
| log("Total tests to run: " + count); | |||
| writer.notifyTestRunStarted(count); | |||
| // send system properties to know for the JVM status | |||
| writer.notifySystemProperties(); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.RUN_STARTED)); | |||
| long startTime = System.currentTimeMillis(); | |||
| for (int i = 0; i < suites.length; i++) { | |||
| String name = suites[i].getClass().getName(); | |||
| if (suites[i] instanceof TestCase) { | |||
| suites[i] = new TestSuite(suites[i].getClass().getName()); | |||
| suites[i] = new TestSuite(name); | |||
| } | |||
| log("running suite: " + suites[i]); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_STARTED, name)); | |||
| suites[i].run(testResult); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_ENDED, name)); | |||
| } | |||
| // inform TestRunListeners of test end | |||
| long elapsedTime = System.currentTimeMillis() - startTime; | |||
| if (testResult == null || testResult.shouldStop()) { | |||
| writer.notifyTestRunStopped(elapsedTime); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.RUN_STOPPED, System.getProperties())); | |||
| } else { | |||
| writer.notifyTestRunEnded(elapsedTime); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.RUN_ENDED, System.getProperties())); | |||
| } | |||
| log("Finished after " + elapsedTime + "ms"); | |||
| shutDown(); | |||
| @@ -345,23 +346,16 @@ public class TestRunner implements TestListener { | |||
| protected void connect() throws IOException { | |||
| log("Connecting to " + host + " on port " + port + "..."); | |||
| clientSocket = new Socket(host, port); | |||
| writer = new MessageWriter(clientSocket.getOutputStream()); | |||
| reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); | |||
| messenger = new Messenger(clientSocket.getInputStream(), clientSocket.getOutputStream()); | |||
| new StopThread().start(); | |||
| } | |||
| protected void shutDown() { | |||
| if (writer != null) { | |||
| writer.close(); | |||
| writer = null; | |||
| } | |||
| try { | |||
| if (reader != null) { | |||
| reader.close(); | |||
| reader = null; | |||
| if (messenger != null) { | |||
| messenger.close(); | |||
| messenger = null; | |||
| } | |||
| } catch (IOException e) { | |||
| log(e); | |||
| @@ -377,6 +371,9 @@ public class TestRunner implements TestListener { | |||
| } | |||
| } | |||
| protected void fireEvent(TestRunEvent evt){ | |||
| messenger.writeEvent(evt); | |||
| } | |||
| // -------- JUnit TestListener implementation | |||
| @@ -384,14 +381,13 @@ public class TestRunner implements TestListener { | |||
| public void startTest(Test test) { | |||
| String testName = test.toString(); | |||
| log("starting test: " + test); | |||
| writer.notifyTestStarted(testName); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_STARTED, testName)); | |||
| } | |||
| public void addError(Test test, Throwable t) { | |||
| log("Adding error for test: " + test); | |||
| String testName = test.toString(); | |||
| String trace = StringUtils.getStackTrace(t); | |||
| writer.notifyTestFailed(TestRunListener.STATUS_ERROR, testName, trace); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_ERROR, testName, t)); | |||
| } | |||
| /** | |||
| @@ -409,14 +405,13 @@ public class TestRunner implements TestListener { | |||
| public void addFailure(Test test, Throwable t) { | |||
| log("Adding failure for test: " + test); | |||
| String testName = test.toString(); | |||
| String trace = StringUtils.getStackTrace(t); | |||
| writer.notifyTestFailed(TestRunListener.STATUS_FAILURE, testName, trace); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_FAILURE, testName, t)); | |||
| } | |||
| public void endTest(Test test) { | |||
| log("Ending test: " + test); | |||
| String testName = test.toString(); | |||
| writer.notifyTestEnded(testName); | |||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_ENDED, testName)); | |||
| } | |||
| public void log(String msg) { | |||