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; | package org.apache.tools.ant.taskdefs.optional.junit; | ||||
| import java.util.Properties; | 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> | * @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. | * A test has started. | ||||
| * @param a testname made of the testname and testcase classname. | * @param a testname made of the testname and testcase classname. | ||||
| * in the following format: <tt><testname>(<testcase>)</tt> | * in the following format: <tt><testname>(<testcase>)</tt> | ||||
| */ | */ | ||||
| public void onTestStarted(String testname); | |||||
| public void onTestStarted(TestRunEvent evt); | |||||
| /** | /** | ||||
| * A test ended. | * A test ended. | ||||
| * @param a testname made of the testname and testcase classname. | * @param a testname made of the testname and testcase classname. | ||||
| * in the following format: <tt><testname>(<testcase>)</tt> | * in the following format: <tt><testname>(<testcase>)</tt> | ||||
| */ | */ | ||||
| public void onTestEnded(String testname); | |||||
| public void onTestEnded(TestRunEvent evt); | |||||
| /** | /** | ||||
| * A test has failed. | * A test has failed. | ||||
| @@ -97,24 +94,19 @@ public interface TestRunListener { | |||||
| * @param trace the error/failure stacktrace. | * @param trace the error/failure stacktrace. | ||||
| * @todo change this to a testFailure / testError ? | * @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. */ | /** 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. */ | /** 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. */ | /** 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 java.util.Properties; | ||||
| import org.apache.tools.ant.BuildException; | 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 | * Provide a common set of attributes and methods to factorize | ||||
| @@ -81,42 +82,39 @@ public abstract class BaseFormatter implements Formatter { | |||||
| close(); | 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(); | 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.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | 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> | * Display additional messages from a <tt>SummaryFormatter</tt> | ||||
| @@ -67,15 +68,15 @@ public class BriefFormatter extends SummaryFormatter { | |||||
| private final static Resources RES = | private final static Resources RES = | ||||
| ResourceManager.getPackageResources(BriefFormatter.class); | 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); | 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 java.util.Properties; | ||||
| import org.apache.tools.ant.BuildException; | 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. | * A base class that can be used to filter data. | ||||
| @@ -75,40 +76,40 @@ public abstract class FilterFormatter implements Formatter { | |||||
| formatter.init(props); | 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 */ | /** set the wrapped formatter */ | ||||
| @@ -56,6 +56,7 @@ package org.apache.tools.ant.taskdefs.optional.junit.formatter; | |||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
| import org.apache.tools.ant.util.StringUtils; | 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 | * Filtered Formatter that strips out unwanted stack frames from the full | ||||
| @@ -99,7 +100,19 @@ public class FilterStackFormatter extends FilterFormatter { | |||||
| super(formatter); | 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"); | StringTokenizer st = new StringTokenizer(trace, "\r\n"); | ||||
| StringBuffer buf = new StringBuffer(trace.length()); | StringBuffer buf = new StringBuffer(trace.length()); | ||||
| while (st.hasMoreTokens()) { | while (st.hasMoreTokens()) { | ||||
| @@ -108,9 +121,8 @@ public class FilterStackFormatter extends FilterFormatter { | |||||
| buf.append(line).append(StringUtils.LINE_SEP); | 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. | * Check whether or not the line should be accepted. | ||||
| * @param the line to be check for acceptance. | * @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 java.util.Properties; | ||||
| import org.apache.tools.ant.taskdefs.optional.junit.remote.TestRunEvent; | |||||
| /** | /** | ||||
| * Default formatter to text. | * Default formatter to text. | ||||
| * | * | ||||
| @@ -62,38 +64,39 @@ import java.util.Properties; | |||||
| */ | */ | ||||
| public class PlainFormatter extends BaseStreamFormatter { | 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.util.DOMElementWriter; | ||||
| import org.apache.tools.ant.BuildException; | 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 | * 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. */ | /** Timing helper. */ | ||||
| private Hashtable testStarts = new Hashtable(); | 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... | //@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); | Element currentTest = doc.createElement(TESTCASE); | ||||
| currentTest.setAttribute(ATTR_NAME, testname); | |||||
| currentTest.setAttribute(ATTR_NAME, evt.getName()); | |||||
| rootElement.appendChild(currentTest); | 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. | // with a TestSetup, startTest and endTest are not called. | ||||
| if (currentTest == null) { | 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)); | 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 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); | currentTest.appendChild(nested); | ||||
| String[] args = parseFirstLine(trace); | |||||
| String[] args = parseFirstLine(evt.getStackTrace()); | |||||
| if (args[1] != null && args[1].length() > 0) { | if (args[1] != null && args[1].length() > 0) { | ||||
| nested.setAttribute(ATTR_MESSAGE, args[1]); | nested.setAttribute(ATTR_MESSAGE, args[1]); | ||||
| } | } | ||||
| nested.setAttribute(ATTR_TYPE, args[0]); | nested.setAttribute(ATTR_TYPE, args[0]); | ||||
| Text text = doc.createTextNode(trace); | |||||
| Text text = doc.createTextNode(evt.getStackTrace()); | |||||
| nested.appendChild(text); | 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() { | 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) { | protected void notifyTestFailed(int kind, String testname, String trace) { | ||||
| synchronized (listeners) { | synchronized (listeners) { | ||||
| for (int i = 0; i < listeners.size(); i++) { | 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) { | protected void notifyTestSuiteStarted(int count) { | ||||
| synchronized (listeners) { | synchronized (listeners) { | ||||
| for (int i = 0; i < listeners.size(); i++) { | 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) { | protected void notifyTestSuiteEnded(long elapsedtime) { | ||||
| synchronized (listeners) { | synchronized (listeners) { | ||||
| for (int i = 0; i < listeners.size(); i++) { | 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) { | protected void notifyTestSuiteStopped(long elapsedtime) { | ||||
| synchronized (listeners) { | synchronized (listeners) { | ||||
| for (int i = 0; i < listeners.size(); i++) { | 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.ServerSocket; | ||||
| import java.net.Socket; | import java.net.Socket; | ||||
| import org.apache.tools.ant.taskdefs.optional.junit.TestRunListener; | |||||
| /** | /** | ||||
| * The server that will receive events from a remote client. | * The server that will receive events from a remote client. | ||||
| * | * | ||||
| @@ -83,10 +81,9 @@ public class Server { | |||||
| private Socket client; | private Socket client; | ||||
| /** the reader in charge of interpreting messages from the 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) { | public Server(int port) { | ||||
| this.port = port; | this.port = port; | ||||
| @@ -102,7 +99,7 @@ public class Server { | |||||
| * @param listener a instance of a listener. | * @param listener a instance of a listener. | ||||
| */ | */ | ||||
| public void addListener(TestRunListener 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. | * @param listener a instance of a listener. | ||||
| */ | */ | ||||
| public void removeListener(TestRunListener listener) { | public void removeListener(TestRunListener listener) { | ||||
| reader.removeListener(listener); | |||||
| dispatcher.removeListener(listener); | |||||
| } | } | ||||
| /** return whether there is a client running or not */ | /** return whether there is a client running or not */ | ||||
| @@ -127,19 +124,16 @@ public class Server { | |||||
| /** cancel the connection to the client */ | /** cancel the connection to the client */ | ||||
| public void cancel() { | public void cancel() { | ||||
| if (isRunning()) { | 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 */ | /** shutdown the server and any running client */ | ||||
| public void shutdown() { | 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 { | try { | ||||
| if (client != null) { | if (client != null) { | ||||
| @@ -166,8 +160,11 @@ public class Server { | |||||
| try { | try { | ||||
| server = new ServerSocket(port); | server = new ServerSocket(port); | ||||
| client = server.accept(); | 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) { | } catch (IOException e) { | ||||
| //@fixme this stacktrace might be normal when closing | //@fixme this stacktrace might be normal when closing | ||||
| // the socket. So decompose the above in distinct steps | // 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.Properties; | ||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import java.util.Random; | |||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| @@ -86,6 +87,9 @@ import org.apache.tools.ant.util.StringUtils; | |||||
| */ | */ | ||||
| public class TestRunner implements TestListener { | public class TestRunner implements TestListener { | ||||
| /** unique identifier for the runner */ | |||||
| private final Integer id = new Integer( (new Random()).nextInt() ); | |||||
| /** host to connect to */ | /** host to connect to */ | ||||
| private String host = "127.0.0.1"; | private String host = "127.0.0.1"; | ||||
| @@ -104,10 +108,7 @@ public class TestRunner implements TestListener { | |||||
| private Socket clientSocket; | private Socket clientSocket; | ||||
| /** writer to send message to the server */ | /** 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 */ | /** bean constructor */ | ||||
| public TestRunner() { | public TestRunner() { | ||||
| @@ -152,9 +153,9 @@ public class TestRunner implements TestListener { | |||||
| private class StopThread extends Thread { | private class StopThread extends Thread { | ||||
| public void run() { | public void run() { | ||||
| try { | 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(); | TestRunner.this.stop(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -298,26 +299,26 @@ public class TestRunner implements TestListener { | |||||
| // count all testMethods and inform TestRunListeners | // count all testMethods and inform TestRunListeners | ||||
| int count = countTests(suites); | int count = countTests(suites); | ||||
| log("Total tests to run: " + count); | 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(); | long startTime = System.currentTimeMillis(); | ||||
| for (int i = 0; i < suites.length; i++) { | for (int i = 0; i < suites.length; i++) { | ||||
| String name = suites[i].getClass().getName(); | |||||
| if (suites[i] instanceof TestCase) { | if (suites[i] instanceof TestCase) { | ||||
| suites[i] = new TestSuite(suites[i].getClass().getName()); | |||||
| suites[i] = new TestSuite(name); | |||||
| } | } | ||||
| log("running suite: " + suites[i]); | log("running suite: " + suites[i]); | ||||
| fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_STARTED, name)); | |||||
| suites[i].run(testResult); | suites[i].run(testResult); | ||||
| fireEvent(new TestRunEvent(id, TestRunEvent.SUITE_ENDED, name)); | |||||
| } | } | ||||
| // inform TestRunListeners of test end | // inform TestRunListeners of test end | ||||
| long elapsedTime = System.currentTimeMillis() - startTime; | long elapsedTime = System.currentTimeMillis() - startTime; | ||||
| if (testResult == null || testResult.shouldStop()) { | if (testResult == null || testResult.shouldStop()) { | ||||
| writer.notifyTestRunStopped(elapsedTime); | |||||
| fireEvent(new TestRunEvent(id, TestRunEvent.RUN_STOPPED, System.getProperties())); | |||||
| } else { | } else { | ||||
| writer.notifyTestRunEnded(elapsedTime); | |||||
| fireEvent(new TestRunEvent(id, TestRunEvent.RUN_ENDED, System.getProperties())); | |||||
| } | } | ||||
| log("Finished after " + elapsedTime + "ms"); | log("Finished after " + elapsedTime + "ms"); | ||||
| shutDown(); | shutDown(); | ||||
| @@ -345,23 +346,16 @@ public class TestRunner implements TestListener { | |||||
| protected void connect() throws IOException { | protected void connect() throws IOException { | ||||
| log("Connecting to " + host + " on port " + port + "..."); | log("Connecting to " + host + " on port " + port + "..."); | ||||
| clientSocket = new Socket(host, 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(); | new StopThread().start(); | ||||
| } | } | ||||
| protected void shutDown() { | protected void shutDown() { | ||||
| if (writer != null) { | |||||
| writer.close(); | |||||
| writer = null; | |||||
| } | |||||
| try { | try { | ||||
| if (reader != null) { | |||||
| reader.close(); | |||||
| reader = null; | |||||
| if (messenger != null) { | |||||
| messenger.close(); | |||||
| messenger = null; | |||||
| } | } | ||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| log(e); | log(e); | ||||
| @@ -377,6 +371,9 @@ public class TestRunner implements TestListener { | |||||
| } | } | ||||
| } | } | ||||
| protected void fireEvent(TestRunEvent evt){ | |||||
| messenger.writeEvent(evt); | |||||
| } | |||||
| // -------- JUnit TestListener implementation | // -------- JUnit TestListener implementation | ||||
| @@ -384,14 +381,13 @@ public class TestRunner implements TestListener { | |||||
| public void startTest(Test test) { | public void startTest(Test test) { | ||||
| String testName = test.toString(); | String testName = test.toString(); | ||||
| log("starting test: " + test); | log("starting test: " + test); | ||||
| writer.notifyTestStarted(testName); | |||||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_STARTED, testName)); | |||||
| } | } | ||||
| public void addError(Test test, Throwable t) { | public void addError(Test test, Throwable t) { | ||||
| log("Adding error for test: " + test); | log("Adding error for test: " + test); | ||||
| String testName = test.toString(); | 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) { | public void addFailure(Test test, Throwable t) { | ||||
| log("Adding failure for test: " + test); | log("Adding failure for test: " + test); | ||||
| String testName = test.toString(); | 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) { | public void endTest(Test test) { | ||||
| log("Ending test: " + test); | log("Ending test: " + test); | ||||
| String testName = test.toString(); | String testName = test.toString(); | ||||
| writer.notifyTestEnded(testName); | |||||
| fireEvent(new TestRunEvent(id, TestRunEvent.TEST_ENDED, testName)); | |||||
| } | } | ||||
| public void log(String msg) { | public void log(String msg) { | ||||