Browse Source

Use a wrapper for exceptions rather than the full stacktrace.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271354 13f79535-47bb-0310-9956-ffa450edef68
master
Stephane Bailliez 23 years ago
parent
commit
778a6800cf
8 changed files with 259 additions and 132 deletions
  1. +4
    -2
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java
  2. +12
    -4
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java
  3. +2
    -2
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java
  4. +21
    -27
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java
  5. +73
    -88
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java
  6. +133
    -0
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/ExceptionData.java
  7. +7
    -2
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java
  8. +7
    -7
      proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java

+ 4
- 2
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java View File

@@ -69,13 +69,15 @@ public class BriefFormatter extends SummaryFormatter {
ResourceManager.getPackageResources(BriefFormatter.class);

public void onTestFailure(TestRunEvent evt) {
String msg = RES.getString("brief.status-failure.msg", evt.getName(), evt.getStackTrace());
String msg = RES.getString("brief.status-failure.msg", evt.getName(),
evt.getError().getStackTrace());
getWriter().println(msg);
super.onTestFailure(evt);
}

public void onTestError(TestRunEvent evt) {
String msg = RES.getString("brief.status-error.msg", evt.getName(), evt.getStackTrace());
String msg = RES.getString("brief.status-error.msg", evt.getName(),
evt.getError().getStackTrace());
getWriter().println(msg);
super.onTestError(evt);
}


+ 12
- 4
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java View File

@@ -57,6 +57,7 @@ import java.util.StringTokenizer;

import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
import org.apache.tools.ant.taskdefs.optional.rjunit.remote.ExceptionData;

/**
* Filtered Formatter that strips out unwanted stack frames from the full
@@ -103,17 +104,24 @@ public class FilterStackFormatter extends FilterFormatter {
}

public void onTestFailure(TestRunEvent evt) {
String filteredTrace = filter(evt.getStackTrace());
evt.setStackTrace(filteredTrace);
filterEvent(evt);
super.onTestFailure(evt);
}

public void onTestError(TestRunEvent evt) {
String filteredTrace = filter(evt.getStackTrace());
evt.setStackTrace(filteredTrace);
filterEvent(evt);
super.onTestFailure(evt);
}

protected void filterEvent(TestRunEvent evt){
String filteredTrace = filter(evt.getError().getStackTrace());
ExceptionData error = new ExceptionData(
evt.getError().getType(),
evt.getError().getMessage(),
filteredTrace);
evt.setError(error);
}

protected String filter(String trace){
StringTokenizer st = new StringTokenizer(trace, "\r\n");
StringBuffer buf = new StringBuffer(trace.length());


+ 2
- 2
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java View File

@@ -84,12 +84,12 @@ public class PlainFormatter extends BaseStreamFormatter {

public void onTestFailure(TestRunEvent evt) {
getWriter().println(" failure: " + evt.getName());
getWriter().println(evt.getStackTrace());
getWriter().println(evt.getError().getStackTrace());
}

public void onTestError(TestRunEvent evt) {
getWriter().println(" error: " + evt.getName());
getWriter().println(evt.getStackTrace());
getWriter().println(evt.getError().getStackTrace());
}

public void onRunEnded(TestRunEvent evt) {


+ 21
- 27
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java View File

@@ -57,6 +57,7 @@ import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

@@ -68,7 +69,10 @@ import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.optional.rjunit.JUnitHelper;
import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestSummary;
import org.apache.tools.ant.taskdefs.optional.rjunit.remote.ExceptionData;
import org.apache.tools.ant.util.DOMElementWriter;
import org.apache.tools.ant.util.DateUtils;
import org.apache.tools.ant.util.StringUtils;

/**
* XML Formatter. Due to the nature of the XML we are forced to store
@@ -153,6 +157,7 @@ public class XMLFormatter extends BaseStreamFormatter {
private Element lastTestElement = null;
private TestRunEvent lastTestEvent = null;
private Element lastSuiteElement = null;
private long programStart;

public void onSuiteStarted(TestRunEvent evt) {
String fullclassname = evt.getName();
@@ -180,10 +185,12 @@ public class XMLFormatter extends BaseStreamFormatter {
}

public void onRunEnded(TestRunEvent evt) {
final String elapsedTime = String.valueOf(evt.getTimeStamp() - programStart);
rootElement.setAttribute("elapsed_time", elapsedTime);
// Output properties
Element propsElement = doc.createElement(PROPERTIES);
final Element propsElement = doc.createElement(PROPERTIES);
rootElement.appendChild(propsElement);
Properties props = evt.getProperties();
final Properties props = evt.getProperties();
if (props != null) {
Enumeration e = props.propertyNames();
while (e.hasMoreElements()) {
@@ -198,11 +205,13 @@ public class XMLFormatter extends BaseStreamFormatter {
}

public void onRunStarted(TestRunEvent evt) {
//
programStart = evt.getTimeStamp();
final String date = DateUtils.format(programStart, DateUtils.ISO8601_DATETIME_PATTERN);
rootElement.setAttribute("program_start", date);
}

public void onRunStopped(TestRunEvent evt) {
// add a stop attribute ?
rootElement.setAttribute("stopped", "true");
onRunEnded(evt);
}

@@ -242,22 +251,21 @@ public class XMLFormatter extends BaseStreamFormatter {
String type = evt.getType() == TestRunEvent.TEST_FAILURE ? FAILURE : ERROR;
Element nested = doc.createElement(type);
lastTestElement.appendChild(nested);

String[] args = parseFirstLine(evt.getStackTrace());
if (args[1] != null && args[1].length() > 0) {
nested.setAttribute(ATTR_MESSAGE, args[1]);
}
nested.setAttribute(ATTR_TYPE, args[0]);
Text text = doc.createTextNode(evt.getStackTrace());
ExceptionData error = evt.getError();
nested.setAttribute(ATTR_MESSAGE, error.getMessage());
nested.setAttribute(ATTR_TYPE, error.getType());
Text text = doc.createTextNode(error.getStackTrace());
nested.appendChild(text);
onTestEnded(evt);
}

protected void close() {
DOMElementWriter domWriter = new DOMElementWriter();
// the underlying writer uses UTF8 encoding
getWriter().println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
getWriter().println("<?xml version='1.0' encoding='UTF-8' ?>");
String now = DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN);
rootElement.setAttribute("snapshot_created", now);
try {
final DOMElementWriter domWriter = new DOMElementWriter();
domWriter.write(rootElement, getWriter(), 0, " ");
} catch (IOException e) {
throw new BuildException(e);
@@ -274,18 +282,4 @@ public class XMLFormatter extends BaseStreamFormatter {
}
}

protected static String[] parseFirstLine(String trace) {
int pos = trace.indexOf('\n');
if (pos == -1) {
return new String[]{trace, ""};
}
String line = trace.substring(0, pos);
pos = line.indexOf(": ");
if (pos != -1) {
String classname = line.substring(0, pos).trim();
String message = line.substring(pos + 1).trim();
return new String[]{classname, message};
}
return new String[]{trace, ""};
}
}

+ 73
- 88
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java View File

@@ -53,142 +53,127 @@
*/
package org.apache.tools.ant.taskdefs.optional.rjunit.remote;

import java.util.Vector;
import java.io.InputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

/**
* Dispatch messages to appropriate listener methode based on event id.
*
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
*/
public class EventDispatcher {

private final static HashMap eventMap = new HashMap(3);

static {
registerDefaults();
}

/** the set of registered listeners */
private Vector listeners = new Vector();
private ArrayList listeners = new ArrayList();

/**
/**
* Add a new listener.
* @param listener a listener that will receive events from the client.
*/
public void addListener(TestRunListener listener) {
listeners.addElement(listener);
listeners.add(listener);
}

public void removeListener(org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener listener) {
listeners.removeElement(listener);
public void removeListener(TestRunListener listener) {
listeners.remove(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.SUITE_ENDED:
fireSuiteEnded(evt);
break;
case TestRunEvent.SUITE_STARTED:
fireSuiteStarted(evt);
break;
default:
// should not happen
final Integer type = new Integer(evt.getType());
final EventAction action = (EventAction) eventMap.get(type);
if (action == null) {
return;
}
}

protected void fireRunStarted(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunStarted(evt);
final int count = listeners.size();
for (int i = 0; i < count; i++) {
TestRunListener listener = (TestRunListener) listeners.get(i);
action.dispatch(listener, evt);
}
}
}

protected void fireRunEnded(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunEnded(evt);
}
private static void registerDefaults() {
registerAction(TestRunEvent.RUN_STARTED, new RunStartedAction());
registerAction(TestRunEvent.RUN_ENDED, new RunEndedAction());
registerAction(TestRunEvent.TEST_STARTED, new TestStartedAction());
registerAction(TestRunEvent.TEST_ENDED, new TestEndedAction());
registerAction(TestRunEvent.TEST_FAILURE, new TestFailureAction());
registerAction(TestRunEvent.TEST_ERROR, new TestErrorAction());
registerAction(TestRunEvent.SUITE_STARTED, new SuiteStartedAction());
registerAction(TestRunEvent.SUITE_ENDED, new SuiteEndedAction());
registerAction(TestRunEvent.RUN_STOPPED, new RunStoppedAction());
}

private static void registerAction(int id, EventAction action){
eventMap.put(new Integer(id), action);
}

public interface EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt);
}

private static class RunStartedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onRunStarted(evt);
}
}

protected void fireTestStarted(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestStarted(evt);
}
private static class RunEndedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onRunEnded(evt);
}
}

protected void fireTestEnded(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestEnded(evt);
}
private static class TestStartedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onTestStarted(evt);
}
}

protected void fireTestFailure(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestFailure(evt);
}
private static class TestEndedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onTestEnded(evt);
}
}

protected void fireTestError(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onTestError(evt);
}
private static class TestFailureAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onTestFailure(evt);
}
}

protected void fireSuiteStarted(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onSuiteStarted(evt);
}
private static class TestErrorAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onTestError(evt);
}
}

protected void fireSuiteEnded(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onSuiteEnded(evt);
}
private static class SuiteStartedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onSuiteStarted(evt);
}
}

protected void fireRunStopped(TestRunEvent evt) {
synchronized (listeners) {
for (int i = 0; i < listeners.size(); i++) {
((org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener) listeners.elementAt(i)).onRunStopped(evt);
}
private static class SuiteEndedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onSuiteEnded(evt);
}
}

private static class RunStoppedAction implements EventAction {
public void dispatch(TestRunListener listener, TestRunEvent evt) {
listener.onRunStopped(evt);
}
}



+ 133
- 0
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/ExceptionData.java View File

@@ -0,0 +1,133 @@
/*
* 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.rjunit.remote;

import java.io.Serializable;

import org.apache.tools.ant.util.StringUtils;

/**
* A wrapper around an exception since an exception stacktrace is
* not serializable.
*
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
*/
public class ExceptionData implements Serializable {

/** the stacktrace of the exception */
private final String stacktrace;

/** the classname of an exception */
private final String type;

/** the message associated to this exception */
private final String message;

/**
* Create a new error.
* @param exception the exception to run as
*/
public ExceptionData(Throwable exception) {
this(exception.getClass().getName(),
exception.getMessage(),
StringUtils.getStackTrace(exception));
}

/**
* Create a new error.
* @param type the type of the error (ie classname).
* @param message the message associated to this error.
* @param stacktrace the full stacktrace of this error.
*/
public ExceptionData(String type, String message, String stacktrace) {
this.stacktrace = stacktrace;
this.type = type;
this.message = message;
}

/**
* @return the type of the error (ie classname)
*/
public String getType() {
return type;
}

/**
* @return the message associated to this error.
*/
public String getMessage() {
return message;
}

/**
* @return the stacktrace for this error.
*/
public String getStackTrace() {
return stacktrace;
}

public boolean equals(Object o){
if ( o instanceof ExceptionData ){
ExceptionData other = (ExceptionData)o;
return ( ( type == null ? other.type == null : type.equals(other.type) ) &&
( message == null ? other.message == null : message.equals(other.message) ) &&
( stacktrace == null ? other.stacktrace == null : stacktrace.equals(other.stacktrace) ) );
}
return false;
}

public String toString() {
return (message != null) ? (type + ": " + message) : type;
}
}

+ 7
- 2
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java View File

@@ -60,6 +60,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
* Read or write events to/from appropriate streams.
*
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
*/
@@ -90,8 +91,12 @@ public class Messenger {
}
}

public TestRunEvent read() throws Exception {
return (TestRunEvent)((ObjectInputStream)in).readObject();
public TestRunEvent read() {
try {
return (TestRunEvent)((ObjectInputStream)in).readObject();
} catch (Exception e){
return null;
}
}

public void writeEvent(TestRunEvent evt) throws IOException {


+ 7
- 7
proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java View File

@@ -91,7 +91,7 @@ public class TestRunEvent extends EventObject {
private String name;

/** stacktrace for error or failure */
private String stacktrace;
private ExceptionData error;

/** properties for end of testrun */
private Properties props;
@@ -122,7 +122,7 @@ public class TestRunEvent extends EventObject {

public TestRunEvent(Integer id, int type, String name, Throwable t){
this(id, type, name);
this.stacktrace = StringUtils.getStackTrace(t);
this.error = new ExceptionData(t);
}

public void setType(int type) {
@@ -133,8 +133,8 @@ public class TestRunEvent extends EventObject {
this.timestamp = timestamp;
}

public void setStackTrace(String stacktrace) {
this.stacktrace = stacktrace;
public void setError(ExceptionData error) {
this.error = error;
}

public void setName(String name) {
@@ -161,8 +161,8 @@ public class TestRunEvent extends EventObject {
return result;
}

public String getStackTrace(){
return stacktrace;
public ExceptionData getError(){
return error;
}

public Properties getProperties(){
@@ -175,7 +175,7 @@ public class TestRunEvent extends EventObject {
return ( (type == other.type) &&
(timestamp == other.timestamp) &&
( name == null ? other.name == null : name.equals(other.name) ) &&
( stacktrace == null ? other.stacktrace == null : stacktrace.equals(other.stacktrace) ) &&
( error == null ? other.error == null : error.equals(other.error) ) &&
( props == null ? other.props == null : props.equals(other.props) ) &&
( result == null ? other.result == null : result.equals(other.result) ) );
}


Loading…
Cancel
Save