/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sebastian Davids: sdavids@gmx.de bug 26754
*******************************************************************************/
package org.eclipse.jdt.internal.junit.runner;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
import org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestLoader;
import org.openntf.junit4xpages.OsgiTest;
import org.osgi.framework.Bundle;
/**
* A TestRunner that reports results via a socket connection. See MessageIds for more information about the protocol.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
public class RemoteTestRunner implements MessageSender, IVisitsTestTrees {
private static String BOOTSTRAP_CLASS_LOADER = "com.ibm.domino.http.bootstrap.BootstrapClassLoader";
/**
* Holder for information for a rerun request
*/
private static class RerunRequest {
String fRerunClassName;
String fRerunTestName;
int fRerunTestId;
public RerunRequest(final int testId, final String className, final String testName) {
fRerunTestId = testId;
fRerunClassName = className;
fRerunTestName = testName;
}
}
public static final String RERAN_FAILURE = "FAILURE"; //$NON-NLS-1$
public static final String RERAN_ERROR = "ERROR"; //$NON-NLS-1$
public static final String RERAN_OK = "OK"; //$NON-NLS-1$
/**
* The name of the test classes to be executed
*/
private String[] fTestClassNames;
/**
* The name of the test (argument -test)
*/
private String fTestName;
/**
* The current test result
*/
private TestExecution fExecution;
/**
* The version expected by the client
*/
private String fVersion = ""; //$NON-NLS-1$
/**
* The client socket.
*/
private Socket fClientSocket;
/**
* Print writer for sending messages
*/
private PrintWriter fWriter;
/**
* Reader for incoming messages
*/
private BufferedReader fReader;
/**
* Host to connect to, default is the localhost
*/
private String fHost = ""; //$NON-NLS-1$
/**
* Port to connect to.
*/
private int fPort = -1;
/**
* Is the debug mode enabled?
*/
private boolean fDebugMode = false;
/**
* Keep the test run server alive after a test run has finished. This allows to rerun tests.
*/
private boolean fKeepAlive = false;
/**
* Has the server been stopped
*/
private boolean fStopped = false;
/**
* Queue of rerun requests.
*/
private Vector fRerunRequests = new Vector(10);
/**
* Thread reading from the socket
*/
private ReaderThread fReaderThread;
private String fRerunTest;
private final TestIdMap fIds = new TestIdMap();
private String[] fFailureNames;
private ITestLoader fLoader;
private MessageSender fSender;
private boolean fConsoleMode = false;
/**
* Reader thread that processes messages from the client.
*/
private class ReaderThread extends Thread {
public ReaderThread() {
super("ReaderThread"); //$NON-NLS-1$
}
@Override
public void run() {
try {
String message = null;
while (true) {
if ((message = fReader.readLine()) != null) {
if (message.startsWith(MessageIds.TEST_STOP)) {
fStopped = true;
RemoteTestRunner.this.stop();
synchronized (RemoteTestRunner.this) {
RemoteTestRunner.this.notifyAll();
}
break;
}
else if (message.startsWith(MessageIds.TEST_RERUN)) {
String arg = message.substring(MessageIds.MSG_HEADER_LENGTH);
//format: testId className testName
int c0 = arg.indexOf(' ');
int c1 = arg.indexOf(' ', c0 + 1);
String s = arg.substring(0, c0);
int testId = Integer.parseInt(s);
String className = arg.substring(c0 + 1, c1);
String testName = arg.substring(c1 + 1, arg.length());
synchronized (RemoteTestRunner.this) {
fRerunRequests.add(new RerunRequest(testId, className, testName));
RemoteTestRunner.this.notifyAll();
}
}
}
}
} catch (Exception e) {
RemoteTestRunner.this.stop();
}
}
}
public RemoteTestRunner() {
setMessageSender(this);
}
public void setMessageSender(final MessageSender sender) {
fSender = sender;
}
/**
* The main entry point.
*
* @param args
* Parameters:
*
* <pre>
* -classnames: the name of the test suite class
* -testfilename: the name of a file containing classnames of test suites
* -test: the test method name (format classname testname)
* -host: the host to connect to default local host
* -port: the port to connect to, mandatory argument
* -keepalive: keep the process alive after a test run
* </pre>
*/
public static void main(final String[] args) {
boolean osgiPresent = false;
boolean osgiTest = false;
try {
Class<?> bcl = Class.forName(BOOTSTRAP_CLASS_LOADER);
Method method = bcl.getMethod("getSharedClassLoader");
ClassLoader sharedCl = (ClassLoader) method.invoke(null);
osgiPresent = sharedCl != null;
} catch (Exception rex) {
}
try {
RemoteTestRunner testRunServer = new RemoteTestRunner();
testRunServer.init(args);
if (!osgiPresent) {
osgiTest = testRunServer.hasOsgiTests();
}
if (osgiTest) {
runAsOsgi(args);
} else {
testRunServer.run();
}
} catch (Throwable e) {
e.printStackTrace(); // don't allow System.exit(0) to swallow exceptions
} finally {
// fix for 14434
if (!osgiPresent)
System.exit(0);
}
}
protected boolean hasOsgiTests() {
Set<URL> osgiClassPaths = new HashSet<URL>();
for (Class<?> c : loadClasses(fTestClassNames)) {
OsgiTest annot = c.getAnnotation(OsgiTest.class);
if (annot != null) {
if (annot.value() == null) {
// nop
} else if (annot.value().equals("")) {
// nop
} else if (System.getProperty("junit4xpages.bundle", "").equals("")) {
System.setProperty("junit4xpages.bundle", annot.value());
}
osgiClassPaths.add(c.getProtectionDomain().getCodeSource().getLocation());
}
}
if (osgiClassPaths.isEmpty())
return false;
StringBuilder sb = new StringBuilder();
for (URL u : osgiClassPaths) {
if (sb.length() > 0)
sb.append(';');
sb.append(u.toString());
}
System.setProperty("junit4xpages.classpath", sb.toString());
return true;
}
private static void runAsOsgi(final String[] args) {
try {
System.out.println("[JUnit4XPages] starting framework");
Class<?> bcl = Class.forName(BOOTSTRAP_CLASS_LOADER);
Method method = bcl.getMethod("findClass", String.class);
Class<?> beClass = (Class<?>) method.invoke(null, "com.ibm.designer.runtime.domino.bootstrap.BootstrapEnvironment");
// BootstrapEnvironment be = BootstrapEnvironment.getInstance();
Object /* BootstrapEnvironment */be = beClass.getMethod("getInstance").invoke(null);
// LCDRequestHandler lcdReqHandler = be.getRequestHandler();
Object /* LCDEnvironment */lcdReqHandler = be.getClass().getMethod("getLCDRequestHandler").invoke(be);
// lcdReqHandler.initialize();
lcdReqHandler.getClass().getMethod("initialize").invoke(lcdReqHandler);
System.out.println("[JUnit4XPages] framework started");
try {
// Now start the runner = this class INSIDE the framework
ClassLoader sharedCl = (ClassLoader) bcl.getMethod("getSharedClassLoader").invoke(null);
// load the Runner from the xsp-bundle
Class platformCl = sharedCl.loadClass("org.eclipse.core.runtime.Platform");
Object bundle = platformCl.getMethod("getBundle", String.class).invoke(null, "org.openntf.junit4xpages");
method = bundle.getClass().getMethod("loadClass", String.class);
Class osgiRunnerCl = (Class) method.invoke(bundle, RemoteTestRunner.class.getName());
Thread.currentThread().setContextClassLoader(osgiRunnerCl.getClassLoader());
System.out.println("[JUnit4XPages] starting OSGI-Runner");
osgiRunnerCl.getMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { args });
} finally {
System.out.println("[JUnit4XPages] stopping framework");
// lcdReqHandler.stop();
method = lcdReqHandler.getClass().getMethod("destroy");
method.invoke(lcdReqHandler);
System.out.println("[JUnit4XPages] framework stopped");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Parse command line arguments. Hook for subclasses to process additional arguments.
*
* @param args
* the arguments
*/
protected void init(final String[] args) {
defaultInit(args);
}
private ClassLoader classLoader;
/**
* The class loader to be used for loading tests. Subclasses may override to use another class loader.
*
* @return the class loader to lead test classes
*/
protected ClassLoader getTestClassLoader() {
if (classLoader == null) {
String cp = System.getProperty("junit4xpages.classpath");
if (cp == null) {
classLoader = getClass().getClassLoader();
} else {
String[] paths = cp.split(";");
URL[] urls = new URL[paths.length];
for (int i = 0; i < paths.length; i++) {
try {
urls[i] = new URL(paths[i]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
ClassLoader cl1 = getClass().getClassLoader();
ClassLoader cl2 = Thread.currentThread().getContextClassLoader();
String bundleName = System.getProperty("junit4xpages.bundle", "org.openntf.domino.xsp");
final Bundle bundle = org.eclipse.core.runtime.Platform.getBundle(bundleName);
classLoader = new URLClassLoader(urls, null) {
@Override
public java.lang.Class<?> loadClass(final String className) throws ClassNotFoundException {
Class<?> ret;
try {
ret = super.loadClass(className);
//System.out.println("super.loadClass(" + className + ")");
return ret;
} catch (ClassNotFoundException cnf) {
ret = bundle.loadClass(className);
//System.out.println("bundle.loadClass(" + className + ")");
return ret;
}
}
@Override
public URL getResource(final String resName) {
// TODO Auto-generated method stub
URL ret = super.getResource(resName);
if (ret == null) {
ret = bundle.getResource(resName);
}
return ret;
}
};
}
}
return classLoader;
}
/**
* Process the default arguments.
*
* @param args
* arguments
*/
protected final void defaultInit(final String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].toLowerCase().equals("-classnames") || args[i].toLowerCase().equals("-classname")) { //$NON-NLS-1$ //$NON-NLS-2$
Vector list = new Vector();
for (int j = i + 1; j < args.length; j++) {
if (args[j].startsWith("-")) //$NON-NLS-1$
break;
list.add(args[j]);
}
fTestClassNames = (String[]) list.toArray(new String[list.size()]);
} else if (args[i].toLowerCase().equals("-test")) { //$NON-NLS-1$
String testName = args[i + 1];
int p = testName.indexOf(':');
if (p == -1)
throw new IllegalArgumentException("Testname not separated by \'%\'"); //$NON-NLS-1$
fTestName = testName.substring(p + 1);
fTestClassNames = new String[] { testName.substring(0, p) };
i++;
} else if (args[i].toLowerCase().equals("-testnamefile")) { //$NON-NLS-1$
String testNameFile = args[i + 1];
try {
readTestNames(testNameFile);
} catch (IOException e) {
throw new IllegalArgumentException("Cannot read testname file."); //$NON-NLS-1$
}
i++;
} else if (args[i].toLowerCase().equals("-testfailures")) { //$NON-NLS-1$
String testFailuresFile = args[i + 1];
try {
readFailureNames(testFailuresFile);
} catch (IOException e) {
throw new IllegalArgumentException("Cannot read testfailures file."); //$NON-NLS-1$
}
i++;
} else if (args[i].toLowerCase().equals("-port")) { //$NON-NLS-1$
fPort = Integer.parseInt(args[i + 1]);
i++;
} else if (args[i].toLowerCase().equals("-host")) { //$NON-NLS-1$
fHost = args[i + 1];
i++;
} else if (args[i].toLowerCase().equals("-rerun")) { //$NON-NLS-1$
fRerunTest = args[i + 1];
i++;
} else if (args[i].toLowerCase().equals("-keepalive")) { //$NON-NLS-1$
fKeepAlive = true;
} else if (args[i].toLowerCase().equals("-debugging") || args[i].toLowerCase().equals("-debug")) { //$NON-NLS-1$ //$NON-NLS-2$
fDebugMode = true;
} else if (args[i].toLowerCase().equals("-version")) { //$NON-NLS-1$
fVersion = args[i + 1];
i++;
} else if (args[i].toLowerCase().equals("-junitconsole")) { //$NON-NLS-1$
fConsoleMode = true;
} else if (args[i].toLowerCase().equals("-testloaderclass")) { //$NON-NLS-1$
String className = args[i + 1];
createLoader(className);
i++;
}
}
if (getTestLoader() == null)
initDefaultLoader();
if (fTestClassNames == null || fTestClassNames.length == 0)
throw new IllegalArgumentException(JUnitMessages.getString("RemoteTestRunner.error.classnamemissing")); //$NON-NLS-1$
if (fPort == -1)
throw new IllegalArgumentException(JUnitMessages.getString("RemoteTestRunner.error.portmissing")); //$NON-NLS-1$
if (fDebugMode)
System.out.println("keepalive " + fKeepAlive); //$NON-NLS-1$
}
public void initDefaultLoader() {
createLoader(JUnit3TestLoader.class.getName());
}
public void createLoader(final String className) {
setLoader(createRawTestLoader(className));
}
protected ITestLoader createRawTestLoader(final String className) {
try {
return (ITestLoader) loadTestLoaderClass(className).newInstance();
} catch (Exception e) {
StringWriter trace = new StringWriter();
e.printStackTrace(new PrintWriter(trace));
String message = JUnitMessages.getFormattedString(
"RemoteTestRunner.error.invalidloader", new Object[] { className, trace.toString() }); //$NON-NLS-1$
throw new IllegalArgumentException(message);
}
}
protected Class loadTestLoaderClass(final String className) throws ClassNotFoundException {
return Class.forName(className);
}
public void setLoader(final ITestLoader newInstance) {
fLoader = newInstance;
}
private void readTestNames(final String testNameFile) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(testNameFile)), "UTF-8")); //$NON-NLS-1$
try {
String line;
Vector list = new Vector();
while ((line = br.readLine()) != null) {
list.add(line);
}
fTestClassNames = (String[]) list.toArray(new String[list.size()]);
} finally {
br.close();
}
if (fDebugMode) {
System.out.println("Tests:"); //$NON-NLS-1$
for (int i = 0; i < fTestClassNames.length; i++) {
System.out.println(" " + fTestClassNames[i]); //$NON-NLS-1$
}
}
}
private void readFailureNames(final String testFailureFile) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(testFailureFile)), "UTF-8")); //$NON-NLS-1$
try {
String line;
Vector list = new Vector();
while ((line = br.readLine()) != null) {
list.add(line);
}
fFailureNames = (String[]) list.toArray(new String[list.size()]);
} finally {
br.close();
}
if (fDebugMode) {
System.out.println("Failures:"); //$NON-NLS-1$
for (int i = 0; i < fFailureNames.length; i++) {
System.out.println(" " + fFailureNames[i]); //$NON-NLS-1$
}
}
}
/**
* Connects to the remote ports and runs the tests.
*/
protected void run() {
if (!connect())
return;
if (fRerunTest != null) {
rerunTest(new RerunRequest(Integer.parseInt(fRerunTest), fTestClassNames[0], fTestName));
return;
}
FirstRunExecutionListener listener = firstRunExecutionListener();
fExecution = new TestExecution(listener, getClassifier());
runTests(fExecution);
if (fKeepAlive)
waitForReruns();
shutDown();
}
public FirstRunExecutionListener firstRunExecutionListener() {
return new FirstRunExecutionListener(fSender, fIds);
}
/**
* Waits for rerun requests until an explicit stop request
*/
private synchronized void waitForReruns() {
while (!fStopped) {
try {
wait();
if (!fStopped && fRerunRequests.size() > 0) {
RerunRequest r = (RerunRequest) fRerunRequests.remove(0);
rerunTest(r);
}
} catch (InterruptedException e) {
}
}
}
public void runFailed(final String message, final Exception exception) {
//TODO: remove System.err.println?
System.err.println(message);
if (exception != null)
exception.printStackTrace(System.err);
}
protected Class[] loadClasses(final String[] testClassNames) {
Vector classes = new Vector();
for (int i = 0; i < testClassNames.length; i++) {
String name = testClassNames[i];
Class clazz = loadClass(name, this);
if (clazz != null) {
classes.add(clazz);
}
}
return (Class[]) classes.toArray(new Class[classes.size()]);
}
protected void notifyListenersOfTestEnd(final TestExecution execution, final long testStartTime) {
if (execution == null || execution.shouldStop())
notifyTestRunStopped(System.currentTimeMillis() - testStartTime);
else
notifyTestRunEnded(System.currentTimeMillis() - testStartTime);
}
/**
* Runs a set of tests.
*
* @param testClassNames
* classes to be run
* @param testName
* individual method to be run
* @param execution
* executor
*/
public void runTests(final String[] testClassNames, final String testName, final TestExecution execution) {
ITestReference[] suites = fLoader.loadTests(loadClasses(testClassNames), testName, fFailureNames, this);
// count all testMethods and inform ITestRunListeners
int count = countTests(suites);
notifyTestRunStarted(count);
if (count == 0) {
notifyTestRunEnded(0);
return;
}
sendTrees(suites);
long testStartTime = System.currentTimeMillis();
execution.run(suites);
notifyListenersOfTestEnd(execution, testStartTime);
}
private void sendTrees(final ITestReference[] suites) {
long startTime = System.currentTimeMillis();
if (fDebugMode)
System.out.print("start send tree..."); //$NON-NLS-1$
for (int i = 0; i < suites.length; i++) {
suites[i].sendTree(this);
}
if (fDebugMode)
System.out.println("done send tree - time(ms): " + (System.currentTimeMillis() - startTime)); //$NON-NLS-1$
}
private int countTests(final ITestReference[] tests) {
int count = 0;
for (int i = 0; i < tests.length; i++) {
ITestReference test = tests[i];
if (test != null)
count = count + test.countTestCases();
}
return count;
}
/**
* Reruns a test as defined by the fully qualified class name and the name of the test.
*
* @param r
* rerun request
*/
public void rerunTest(final RerunRequest r) {
final Class[] classes = loadClasses(new String[] { r.fRerunClassName });
ITestReference rerunTest1 = fLoader.loadTests(classes, r.fRerunTestName, null, this)[0];
RerunExecutionListener service = rerunExecutionListener();
TestExecution execution = new TestExecution(service, getClassifier());
ITestReference[] suites = new ITestReference[] { rerunTest1 };
execution.run(suites);
notifyRerunComplete(r, service.getStatus());
}
public RerunExecutionListener rerunExecutionListener() {
return new RerunExecutionListener(fSender, fIds);
}
protected IClassifiesThrowables getClassifier() {
return new DefaultClassifier(fVersion);
}
public void visitTreeEntry(final ITestIdentifier id, final boolean b, final int i) {
notifyTestTreeEntry(getTestId(id) + ',' + escapeComma(id.getName()) + ',' + b + ',' + i);
}
private String escapeComma(final String s) {
if ((s.indexOf(',') < 0) && (s.indexOf('\\') < 0))
return s;
StringBuffer sb = new StringBuffer(s.length() + 10);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ',')
sb.append("\\,"); //$NON-NLS-1$
else if (c == '\\')
sb.append("\\\\"); //$NON-NLS-1$
else
sb.append(c);
}
return sb.toString();
}
// WANT: work in bug fixes since RC2?
private String getTestId(final ITestIdentifier id) {
return fIds.getTestId(id);
}
/**
* Stop the current test run.
*/
protected void stop() {
if (fExecution != null) {
fExecution.stop();
}
}
/**
* Connect to the remote test listener.
*
* @return <code>true</code> if connection successful, <code>false</code> if failed
*/
protected boolean connect() {
if (fConsoleMode) {
fClientSocket = null;
fWriter = new PrintWriter(System.out);
fReader = new BufferedReader(new InputStreamReader(System.in));
fReaderThread = new ReaderThread();
fReaderThread.start();
return true;
}
if (fDebugMode)
System.out.println("RemoteTestRunner: trying to connect" + fHost + ":" + fPort); //$NON-NLS-1$ //$NON-NLS-2$
Exception exception = null;
for (int i = 1; i < 20; i++) {
try {
fClientSocket = new Socket(fHost, fPort);
try {
fWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fClientSocket.getOutputStream(), "UTF-8")), false/*true*/); //$NON-NLS-1$
} catch (UnsupportedEncodingException e1) {
fWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fClientSocket.getOutputStream())), false/*true*/);
}
try {
fReader = new BufferedReader(new InputStreamReader(fClientSocket.getInputStream(), "UTF-8")); //$NON-NLS-1$
} catch (UnsupportedEncodingException e1) {
fReader = new BufferedReader(new InputStreamReader(fClientSocket.getInputStream()));
}
fReaderThread = new ReaderThread();
fReaderThread.start();
return true;
} catch (IOException e) {
exception = e;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
runFailed(
JUnitMessages.getFormattedString("RemoteTestRunner.error.connect", new String[] { fHost, Integer.toString(fPort) }), exception); //$NON-NLS-1$
return false;
}
/**
* Shutsdown the connection to the remote test listener.
*/
private void shutDown() {
if (fWriter != null) {
fWriter.close();
fWriter = null;
}
try {
if (fReaderThread != null) {
// interrupt reader thread so that we don't block on close
// on a lock held by the BufferedReader
// fix for bug: 38955
try {
fReaderThread.interrupt();
} catch (java.lang.NullPointerException NPE) {
// Bug in NotesAgentManager - throws a NPE if there is no ThreadGroup present
}
}
if (fReader != null) {
fReader.close();
fReader = null;
}
} catch (IOException e) {
if (fDebugMode)
e.printStackTrace();
}
try {
if (fClientSocket != null) {
fClientSocket.close();
fClientSocket = null;
}
} catch (IOException e) {
if (fDebugMode)
e.printStackTrace();
}
}
/*
* @see org.eclipse.jdt.internal.junit.runner.MessageSender#sendMessage(java.lang.String)
*/
public void sendMessage(final String msg) {
if (fWriter == null)
return;
fWriter.println(msg);
// if (!fConsoleMode)
// System.out.println(msg);
}
protected void notifyTestRunStarted(final int testCount) {
fSender.sendMessage(MessageIds.TEST_RUN_START + testCount + " " + "v2"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void notifyTestRunEnded(final long elapsedTime) {
fSender.sendMessage(MessageIds.TEST_RUN_END + elapsedTime);
fSender.flush();
//shutDown();
}
protected void notifyTestRunStopped(final long elapsedTime) {
fSender.sendMessage(MessageIds.TEST_STOPPED + elapsedTime);
fSender.flush();
//shutDown();
}
protected void notifyTestTreeEntry(final String treeEntry) {
fSender.sendMessage(MessageIds.TEST_TREE + treeEntry);
}
/*
* @see org.eclipse.jdt.internal.junit.runner.RerunCompletionListener#notifyRerunComplete(org.eclipse.jdt.internal.junit.runner.RerunRequest,
* java.lang.String)
*/
public void notifyRerunComplete(final RerunRequest r, final String status) {
if (fPort != -1) {
fSender.sendMessage(MessageIds.TEST_RERAN + r.fRerunTestId + " " + r.fRerunClassName + " " + r.fRerunTestName + " " + status); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
fSender.flush();
}
}
public void flush() {
fWriter.flush();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.internal.junit.runner.TestRunner#runTests(org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.TestExecution)
*/
public void runTests(final TestExecution execution) {
runTests(fTestClassNames, fTestName, execution);
}
public ITestLoader getTestLoader() {
return fLoader;
}
public Class loadClass(final String className, final RemoteTestRunner listener) {
Class clazz = null;
try {
clazz = getTestClassLoader().loadClass(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
listener.runFailed(JUnitMessages.getFormattedString("RemoteTestRunner.error.classnotfound", className), e); //$NON-NLS-1$
}
return clazz;
}
}