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) { | ||||