blob: 8a84cbd3d3b25bffd79cd159b9bc7fe97cc5a5bb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.tools.ant.taskdefs.optional.junit;
import java.io.OutputStream;
import java.lang.reflect.Method;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
/**
* Formatter that doesn't create any output but tries to invoke the
* tearDown method on a testcase if that test was forked and caused a
* timeout or VM crash.
*
* <p>This formatter has some limitations, for details see the
* &lt;junit&gt; task's manual.</p>
*
* @since Ant 1.8.0
*/
public class TearDownOnVmCrash implements JUnitResultFormatter {
private String suiteName;
/**
* Records the suite's name to later determine the class to invoke
* tearDown on.
*/
@Override
public void startTestSuite(final JUnitTest suite) {
suiteName = suite.getName();
if (suiteName != null && suiteName.endsWith(JUnitTask.NAME_OF_DUMMY_TEST)) {
// no way to know which class caused the timeout
suiteName = null;
}
}
/**
* Only invoke tearDown if the suite is known and not the dummy
* test we get when a Batch fails and the error is an actual
* error generated by Ant.
*/
@Override
public void addError(final Test fakeTest, final Throwable t) {
if (suiteName != null && fakeTest instanceof JUnitTaskMirrorImpl.VmExitErrorTest) {
tearDown();
}
}
// no need to implement the rest
public void addFailure(Test test, Throwable t) {
}
@Override
public void addFailure(Test test, AssertionFailedError t) {
}
@Override
public void startTest(Test test) {
}
@Override
public void endTest(Test test) {
}
@Override
public void endTestSuite(JUnitTest suite) {
}
@Override
public void setOutput(OutputStream out) {
}
@Override
public void setSystemOutput(String out) {
}
@Override
public void setSystemError(String err) {
}
private void tearDown() {
try {
// first try to load the class and let's hope it is on our
// classpath
Class<?> testClass = null;
if (Thread.currentThread().getContextClassLoader() != null) {
try {
testClass = Thread.currentThread().getContextClassLoader()
.loadClass(suiteName);
} catch (ClassNotFoundException cnfe) {
// ignore
}
}
if (testClass == null && getClass().getClassLoader() != null) {
try {
testClass = getClass().getClassLoader().loadClass(suiteName);
} catch (ClassNotFoundException cnfe) {
// ignore
}
}
if (testClass == null) {
// fall back to system classloader
testClass = Class.forName(suiteName);
}
// if the test has a suite method, then we can't know
// which test of the executed suite timed out, ignore it
try {
// check if there is a suite method
testClass.getMethod("suite");
return;
} catch (NoSuchMethodException e) {
// no suite method
}
// a loadable class and no suite method
// no reason to check for JUnit 4 since JUnit4TestAdapter
// doesn't have any tearDown method.
try {
Method td = testClass.getMethod("tearDown");
if (td.getReturnType() == Void.TYPE) {
td.invoke(testClass.getDeclaredConstructor().newInstance());
}
} catch (NoSuchMethodException nsme) {
// no tearDown, fine
}
} catch (ClassNotFoundException cnfe) {
// class probably is not in our classpath, there is
// nothing we can do
} catch (Throwable t) {
System.err.println("Caught an exception while trying to invoke"
+ " tearDown: " + t.getMessage());
}
}
}