blob: 96ea1d6cc28d67870713071030cb773a2e188618 [file] [log] [blame]
package org.eclipse.debug.jdi.tests;
/**********************************************************************
Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
This file is made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
**********************************************************************/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Vector;
import junit.framework.Test;
import junit.framework.TestCase;
import org.eclipse.jdi.Bootstrap;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ArrayType;
import com.sun.jdi.ClassLoaderReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.ExceptionEvent;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.request.AccessWatchpointRequest;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.ExceptionRequest;
import com.sun.jdi.request.ModificationWatchpointRequest;
import com.sun.jdi.request.StepRequest;
/**
* Tests for com.sun.jdi.* and JDWP commands.
* These tests assume that the target program is
* "org.eclipse.debug.jdi.tests.program.MainClass".
*
* Examples of arguments:
* -launcher SunVMLauncher -address c:\jdk1.2.2\ -cp d:\target
* -launcher J9VMLauncher -address d:\ive\ -cp d:\target
*/
public abstract class AbstractJDITest extends TestCase {
static int TIMEOUT = 10000; //ms
static protected int fBackEndPort = 9900;
// We want subsequent connections to use different ports.
protected String fVMLauncherName;
protected String fTargetAddress;
protected String fClassPath;
protected String fBootPath;
protected String fVMType;
protected com.sun.jdi.VirtualMachine fVM;
protected Process fLaunchedProxy;
protected Process fLaunchedVM;
protected int fVMTraceFlags = com.sun.jdi.VirtualMachine.TRACE_NONE;
protected EventReader fEventReader;
protected AbstractReader fConsoleReader;
protected AbstractReader fConsoleErrorReader;
protected AbstractReader fProxyReader;
protected AbstractReader fProxyErrorReader;
protected boolean fInControl = true;
// Whether this test should control the VM (ie. starting it and shutting it down)
protected boolean fVerbose;
protected String fStdoutFile;
protected String fStderrFile;
protected String fProxyoutFile;
protected String fProxyerrFile;
protected String fVmCmd;
protected String fProxyCmd;
// Stack offset to the MainClass.run() method
protected static final int RUN_FRAME_OFFSET = 1;
/**
* Constructs a test case with a default name.
*/
public AbstractJDITest() {
super("JDI Test");
}
/**
* Returns the names of the tests that are known to not work
* By default, none are excluded.
*/
protected String[] excludedTests() {
return new String[] {
};
}
/**
* Creates and returns an access watchpoint request
* for the field "fBool" in
* org.eclipse.debug.jdi.tests.program.MainClass
* NOTE: This assumes that the VM can watch field access.
*/
protected AccessWatchpointRequest getAccessWatchpointRequest() {
// Get the field
Field field = getField("fBool");
// Create an access watchpoint for this field
return fVM.eventRequestManager().createAccessWatchpointRequest(field);
}
/**
* Returns all tests that start with the given string.
* Returns a vector of String.
*/
protected Vector getAllMatchingTests(String match) {
Class theClass = this.getClass();
java.lang.reflect.Method[] methods = theClass.getDeclaredMethods();
Vector result = new Vector();
for (int i = 0; i < methods.length; i++) {
java.lang.reflect.Method m = methods[i];
String name = m.getName();
Class[] parameters = m.getParameterTypes();
if (parameters.length == 0 && name.startsWith(match)) {
if (!isExcludedTest(name)) {
result.add(name);
} else
System.out.println(name + " is excluded.");
}
}
return result;
}
/**
* Returns an array reference.
*/
protected ArrayReference getObjectArrayReference() {
// Get static field "fArray"
Field field = getField("fArray");
// Get value of "fArray"
return (ArrayReference) getMainClass().getValue(field);
}
/**
* Returns another array reference.
*/
protected ArrayReference getNonEmptyDoubleArrayReference() {
// Get static field "fDoubleArray"
Field field = getField("fDoubleArray");
// Get value of "fDoubleArray"
return (ArrayReference) getMainClass().getValue(field);
}
/**
* One-dimensional empty array reference getters
*/
protected ArrayReference getByteArrayReference() {
Field field = getField("byteArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getShortArrayReference() {
Field field = getField("shortArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getIntArrayReference() {
Field field = getField("intArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getLongArrayReference() {
Field field = getField("longArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getDoubleArrayReference() {
Field field = getField("doubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getFloatArrayReference() {
Field field = getField("floatArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getCharArrayReference() {
Field field = getField("charArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getBooleanArrayReference() {
Field field = getField("booleanArray");
return (ArrayReference) getMainClass().getValue(field);
}
/**
* Two-dimensional array reference getters
*/
protected ArrayReference getByteDoubleArrayReference() {
Field field = getField("byteDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getShortDoubleArrayReference() {
Field field = getField("shortDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getIntDoubleArrayReference() {
Field field = getField("intDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getLongDoubleArrayReference() {
Field field = getField("longDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getFloatDoubleArrayReference() {
Field field = getField("floatDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getDoubleDoubleArrayReference() {
Field field = getField("doubleDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getCharDoubleArrayReference() {
Field field = getField("charDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
protected ArrayReference getBooleanDoubleArrayReference() {
Field field = getField("booleanDoubleArray");
return (ArrayReference) getMainClass().getValue(field);
}
/**
* Returns the array type.
*/
protected ArrayType getArrayType() {
// Get array reference
ArrayReference value = getObjectArrayReference();
// Get reference type of "fArray"
return (ArrayType) value.referenceType();
}
/**
* One-dimensional primitive array getters
*/
protected ArrayType getByteArrayType() {
ArrayReference value = getByteArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getShortArrayType() {
ArrayReference value = getShortArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getIntArrayType() {
ArrayReference value = getIntArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getLongArrayType() {
ArrayReference value = getLongArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getFloatArrayType() {
ArrayReference value = getFloatArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getDoubleArrayType() {
ArrayReference value = getDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getCharArrayType() {
ArrayReference value = getCharArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getBooleanArrayType() {
ArrayReference value = getBooleanArrayReference();
return (ArrayType) value.referenceType();
}
/**
* Two-dimensional primitive array getters
*/
protected ArrayType getByteDoubleArrayType() {
ArrayReference value = getByteDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getShortDoubleArrayType() {
ArrayReference value = getShortDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getIntDoubleArrayType() {
ArrayReference value = getIntDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getLongDoubleArrayType() {
ArrayReference value = getLongDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getFloatDoubleArrayType() {
ArrayReference value = getFloatDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getDoubleDoubleArrayType() {
ArrayReference value = getDoubleDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getCharDoubleArrayType() {
ArrayReference value = getCharDoubleArrayReference();
return (ArrayType) value.referenceType();
}
protected ArrayType getBooleanDoubleArrayType() {
ArrayReference value = getBooleanDoubleArrayReference();
return (ArrayType) value.referenceType();
}
/**
* Creates and returns a breakpoint request in the first
* instruction of the MainClass.triggerBreakpointEvent() method.
*/
protected BreakpointRequest getBreakpointRequest() {
// Create a breakpoint request
return fVM.eventRequestManager().createBreakpointRequest(getLocation());
}
/**
* Returns the class with the given name or null if not loaded.
*/
protected ClassType getClass(String name) {
List classes = fVM.classesByName(name);
if (classes.size() == 0)
return null;
else
return (ClassType) classes.get(0);
}
/**
* Returns the class loader of
* org.eclipse.debug.jdi.tests.program.MainClass
*/
protected ClassLoaderReference getClassLoaderReference() {
// Get main class
ClassType type = getMainClass();
// Get its class loader
return type.classLoader();
}
/**
* Creates and returns an exception request for uncaught exceptions.
*/
protected ExceptionRequest getExceptionRequest() {
return fVM.eventRequestManager().createExceptionRequest(null, false, true);
}
/**
* Returns the static field "fObject" in
* org.eclipse.debug.jdi.tests.program.MainClass
*/
protected Field getField() {
return getField("fObject");
}
/**
* Returns the field with the given name in
* org.eclipse.debug.jdi.tests.program.MainClass.
*/
protected Field getField(String fieldName) {
// Get main class
ClassType type = getMainClass();
// Get field
Field result = type.fieldByName(fieldName);
if (result == null)
throw new Error("Unknown field: " + fieldName);
else
return result;
}
/**
* Returns the n frame (starting at the top of the stack) of the thread
* contained in the static field "fThread" of org.eclipse.debug.jdi.tests.program.MainClass.
*/
protected StackFrame getFrame(int n) {
// Make sure the thread is suspended
ThreadReference thread = getThread();
assertTrue(thread.isSuspended());
// Get the frame
StackFrame frame = null;
try {
List frames = thread.frames();
frame = (StackFrame) frames.get(n);
} catch (IncompatibleThreadStateException e) {
throw new Error("Thread was not suspended");
}
return frame;
}
/**
* Returns the interface type org.eclipse.debug.jdi.tests.program.Printable.
*/
protected InterfaceType getInterfaceType() {
List types = fVM.classesByName("org.eclipse.debug.jdi.tests.program.Printable");
return (InterfaceType) types.get(0);
}
/**
* Returns the variable "t" in the frame running MainClass.run().
*/
protected LocalVariable getLocalVariable() {
try {
return getFrame(RUN_FRAME_OFFSET).visibleVariableByName("t");
} catch (AbsentInformationException e) {
return null;
}
}
/**
* Returns the firt location in MainClass.print(OutputStream).
*/
protected Location getLocation() {
return getMethod().location();
}
/**
* Returns the class org.eclipse.debug.jdi.tests.program.MainClass.
*/
protected ClassType getMainClass() {
return getClass("org.eclipse.debug.jdi.tests.program.MainClass");
}
/**
* Returns the method "print(Ljava/io/OutputStream;)V"
* in org.eclipse.debug.jdi.tests.program.MainClass
*/
protected Method getMethod() {
return getMethod("print", "(Ljava/io/OutputStream;)V");
}
/**
* Returns the method with the given name and signature
* in org.eclipse.debug.jdi.tests.program.MainClass
*/
protected Method getMethod(String name, String signature) {
return getMethod(
"org.eclipse.debug.jdi.tests.program.MainClass",
name,
signature);
}
/**
* Returns the method with the given name and signature
* in the given class.
*/
protected Method getMethod(String className, String name, String signature) {
// Get main class
ClassType type = getClass(className);
// Get method print(OutputStream)
Method method = null;
List methods = type.methods();
ListIterator iterator = methods.listIterator();
while (iterator.hasNext()) {
Method m = (Method) iterator.next();
if ((m.name().equals(name)) && (m.signature().equals(signature))) {
method = m;
break;
}
}
if (method == null)
throw new Error("Unknown method: " + name + signature);
else
return method;
}
/**
* Creates and returns a modification watchpoint request
* for the field "fBool" in
* org.eclipse.debug.jdi.tests.program.MainClass.
* NOTE: This assumes that the VM can watch field modification.
*/
protected ModificationWatchpointRequest getModificationWatchpointRequest() {
// Get the field
Field field = getField("fBool");
// Create a modification watchpoint for this field
return fVM.eventRequestManager().createModificationWatchpointRequest(field);
}
/**
* Returns the value of the static field "fObject" in
* org.eclipse.debug.jdi.tests.program.MainClass
*/
protected ObjectReference getObjectReference() {
// Get main class
ClassType type = getMainClass();
// Get field "fObject"
Field field = getField();
// Get value of "fObject"
return (ObjectReference) type.getValue(field);
}
/**
* Creates and returns an access watchpoint request
* for the static field "fString" in
* org.eclipse.debug.jdi.tests.program.MainClass
* NOTE: This assumes that the VM can watch field access.
*/
protected AccessWatchpointRequest getStaticAccessWatchpointRequest() {
// Get the static field
Field field = getField("fString");
// Create an access watchpoint for this field
return fVM.eventRequestManager().createAccessWatchpointRequest(field);
}
/**
* Creates and returns a modification watchpoint request
* for the static field "fString" in
* org.eclipse.debug.jdi.tests.program.MainClass.
* NOTE: This assumes that the VM can watch field modification.
*/
protected ModificationWatchpointRequest getStaticModificationWatchpointRequest() {
// Get the field
Field field = getField("fString");
// Create a modification watchpoint for this field
return fVM.eventRequestManager().createModificationWatchpointRequest(field);
}
/**
* Returns the value of the static field "fString" in
* org.eclipse.debug.jdi.tests.program.MainClass
*/
protected StringReference getStringReference() {
// Get field "fString"
Field field = getField("fString");
// Get value of "fString"
return (StringReference) getMainClass().getValue(field);
}
/**
* Returns the class java.lang.Object.
*/
protected ClassType getSystemType() {
List classes = fVM.classesByName("java.lang.Object");
if (classes.size() == 0)
return null;
else
return (ClassType) classes.get(0);
}
/**
* Returns the thread contained in the static field "fThread" in
* org.eclipse.debug.jdi.tests.program.MainClass
*/
protected ThreadReference getThread() {
return getThread("fThread");
}
protected ThreadReference getMainThread() {
return getThread("fMainThread");
}
private ThreadReference getThread(String fieldName) {
ClassType type = getMainClass();
if (type == null)
return null;
// Get static field "fThread"
List fields = type.fields();
ListIterator iterator = fields.listIterator();
Field field = null;
while (iterator.hasNext()) {
field = (Field) iterator.next();
if (field.name().equals(fieldName))
break;
}
// Get value of "fThread"
Value value = type.getValue(field);
if (value == null)
return null;
else
return (ThreadReference) value;
}
/**
* Returns the VM info for this test.
*/
VMInformation getVMInfo() {
return new VMInformation(
fVM,
fVMType,
fLaunchedVM,
fEventReader,
fConsoleReader);
}
/**
* Returns whether the given test is excluded for the VM we are testing.
*/
private boolean isExcludedTest(String testName) {
String[] excludedTests = excludedTests();
if (excludedTests == null)
return false;
for (int i = 0; i < excludedTests.length; i++)
if (testName.equals(excludedTests[i]))
return true;
return false;
}
/**
* Launches the target VM and connects to VM.
*/
protected void launchTargetAndConnectToVM() {
launchTarget();
connectToVM();
}
protected boolean vmIsRunning() {
boolean isRunning = false;
try {
if (fLaunchedVM != null)
fLaunchedVM.exitValue();
} catch (IllegalThreadStateException e) {
isRunning = true;
}
return isRunning;
}
protected void launchTarget() {
if (fVmCmd != null)
launchCommandLineTarget();
else if (fVMLauncherName.equals("SunVMLauncher"))
launchSunTarget();
else if (fVMLauncherName.equals("IBMVMLauncher"))
launchIBMTarget();
else
launchJ9Target();
}
/**
* Launches the target VM specified on the command line.
*/
private void launchCommandLineTarget() {
try {
if (fProxyCmd != null) {
fLaunchedProxy = Runtime.getRuntime().exec(fProxyCmd);
}
fLaunchedVM = Runtime.getRuntime().exec(fVmCmd);
} catch (IOException e) {
throw new Error("Could not launch the VM because " + e.getMessage());
}
}
/**
* Launches the target J9 VM.
*/
private void launchJ9Target() {
try {
// Launch proxy
String proxyString[] = new String[3];
int index = 0;
String binDirectory =
fTargetAddress
+ System.getProperty("file.separator")
+ "bin"
+ System.getProperty("file.separator");
proxyString[index++] = binDirectory + "j9proxy";
proxyString[index++] = "localhost:" + (fBackEndPort - 1);
proxyString[index++] = "" + fBackEndPort;
fLaunchedProxy = Runtime.getRuntime().exec(proxyString);
// Launch target VM
String[] vmString;
if (fBootPath.length() > 0)
vmString = new String[5];
else
vmString = new String[4];
index = 0;
vmString[index++] = binDirectory + "j9w";
File vm= new File(vmString[index - 1] + ".exe");
if (!vm.exists()) {
vmString[index - 1] = binDirectory + "j9";
}
if (fBootPath.length() > 0)
vmString[index++] = "-bp:" + fBootPath;
vmString[index++] = "-cp:" + fClassPath;
vmString[index++] = "-debug:" + (fBackEndPort - 1);
vmString[index++] = "org.eclipse.debug.jdi.tests.program.MainClass";
fLaunchedVM = Runtime.getRuntime().exec(vmString);
} catch (IOException e) {
throw new Error("Could not launch the VM because " + e.getMessage());
}
}
/**
* Launches the target Sun VM.
*/
private void launchSunTarget() {
try {
// Launch target VM
StringBuffer binDirectory= new StringBuffer();
if (fTargetAddress.endsWith("jre")) {
binDirectory.append(fTargetAddress.substring(0, fTargetAddress.length() - 4));
} else {
binDirectory.append(fTargetAddress);
}
binDirectory.append(System.getProperty("file.separator"));
binDirectory.append("bin").append(System.getProperty("file.separator"));
String[] vmString;
if (fBootPath.length() > 0)
vmString = new String[10];
else
vmString = new String[8];
int index = 0;
vmString[index++] = binDirectory.toString() + "javaw";
File vm= new File(vmString[index - 1] + ".exe");
if (!vm.exists()) {
vmString[index - 1] = binDirectory + "java";
}
if (fBootPath.length() > 0) {
vmString[index++] = "-bootpath";
vmString[index++] = fBootPath;
}
vmString[index++] = "-classpath";
vmString[index++] = fClassPath;
vmString[index++] = "-Xdebug";
vmString[index++] = "-Xnoagent";
vmString[index++] = "-Djava.compiler=NONE";
vmString[index++] =
"-Xrunjdwp:transport=dt_socket,address=" + fBackEndPort + ",suspend=y,server=y";
vmString[index++] = "org.eclipse.debug.jdi.tests.program.MainClass";
fLaunchedVM = Runtime.getRuntime().exec(vmString);
} catch (IOException e) {
throw new Error("Could not launch the VM because " + e.getMessage());
}
}
/**
* Launches the target IBM VM.
*/
private void launchIBMTarget() {
try {
// Launch target VM
String binDirectory =
fTargetAddress
+ System.getProperty("file.separator")
+ "bin"
+ System.getProperty("file.separator");
String[] vmString;
if (fBootPath.length() > 0)
vmString = new String[10];
else
vmString = new String[8];
int index = 0;
vmString[index++] = binDirectory + "javaw";
if (fBootPath.length() > 0) {
vmString[index++] = "-bootpath";
vmString[index++] = fBootPath;
}
vmString[index++] = "-classpath";
vmString[index++] = fClassPath;
vmString[index++] = "-Xdebug";
vmString[index++] = "-Xnoagent";
vmString[index++] = "-Djava.compiler=NONE";
vmString[index++] =
"-Xrunjdwp:transport=dt_socket,address=" + fBackEndPort + ",suspend=y,server=y";
vmString[index++] = "org.eclipse.debug.jdi.tests.program.MainClass";
fLaunchedVM = Runtime.getRuntime().exec(vmString);
} catch (IOException e) {
throw new Error("Could not launch the VM because " + e.getMessage());
}
}
/**
* Conects to the target vm.
*/
protected void connectToVM() {
// Start the console reader if possible so that the VM doesn't block when the stdout is full
startConsoleReaders();
// Contact the VM (try 10 times)
for (int i = 0; i < 10; i++) {
try {
VirtualMachineManager manager = Bootstrap.virtualMachineManager();
List connectors = manager.attachingConnectors();
if (connectors.size() == 0)
break;
AttachingConnector connector = (AttachingConnector) connectors.get(0);
Map args = connector.defaultArguments();
((Connector.Argument) args.get("port")).setValue(String.valueOf(fBackEndPort));
((Connector.Argument) args.get("hostname")).setValue("localhost");
fVM = connector.attach(args);
if (fVMTraceFlags != com.sun.jdi.VirtualMachine.TRACE_NONE)
fVM.setDebugTraceMode(fVMTraceFlags);
break;
} catch (IllegalConnectorArgumentsException e) {
} catch (IOException e) {
System.out.println("Got exception: " + e.getMessage());
try {
System.out.println(
"Could not contact the VM at localhost" + ":" + fBackEndPort + ". Retrying...");
Thread.sleep(200);
} catch (InterruptedException e2) {
}
}
}
if (fVM == null) {
if (fLaunchedVM != null) {
// If the VM is not running, output error stream
try {
if (!vmIsRunning()) {
InputStream in = fLaunchedVM.getErrorStream();
int read;
do {
read = in.read();
if (read != -1)
System.out.print((char) read);
} while (read != -1);
}
} catch (IOException e) {
}
// Shut it down
killVM();
}
throw new Error("Could not contact the VM");
}
startEventReader();
}
/**
* Initializes the fields that are used by this test only.
*/
public abstract void localSetUp();
/**
* Makes sure the test leaves the VM in the same state it found it.
* Default is to do nothing.
*/
public void localTearDown() {
}
/**
* Parses the given arguments and store them in this tests
* fields.
* Returns whether the parsing was successfull.
*/
protected boolean parseArgs(String[] args) {
// Default values
String vmVendor = System.getProperty("java.vm.vendor");
String vmVersion = System.getProperty("java.vm.version");
String targetAddress = System.getProperty("java.home");
String vmLauncherName;
if (vmVendor != null
&& vmVendor.equals("Sun Microsystems Inc.")
&& vmVersion != null) {
vmLauncherName = "SunVMLauncher";
} else if (
vmVendor != null && vmVendor.equals("IBM Corporation") && vmVersion != null) {
vmLauncherName = "IBMVMLauncher";
} else {
vmLauncherName = "J9VMLauncher";
}
String classPath = System.getProperty("java.class.path");
String bootPath = "";
String vmType = "?";
boolean verbose = false;
// Parse arguments
for (int i = 0; i < args.length; ++i) {
String arg = args[i];
if (arg.startsWith("-")) {
if (arg.equals("-verbose") || arg.equals("-v")) {
verbose = true;
} else {
String next = (i < args.length - 1) ? args[++i] : null;
// If specified, passed values overide default values
if (arg.equals("-launcher")) {
vmLauncherName = next;
} else if (arg.equals("-address")) {
targetAddress = next;
} else if (arg.equals("-port")) {
fBackEndPort = Integer.parseInt(next);
} else if (arg.equals("-cp")) {
classPath = next;
} else if (arg.equals("-bp")) {
bootPath = next;
} else if (arg.equals("-vmtype")) {
vmType = next;
} else if (arg.equals("-stdout")) {
fStdoutFile = next;
} else if (arg.equals("-stderr")) {
fStderrFile = next;
} else if (arg.equals("-proxyout")) {
fProxyoutFile = next;
} else if (arg.equals("-proxyerr")) {
fProxyerrFile = next;
} else if (arg.equals("-vmcmd")) {
fVmCmd = next;
} else if (arg.equals("-proxycmd")) {
fProxyCmd = next;
} else if (arg.equals("-trace")) {
if (next.equals("all")) {
fVMTraceFlags = com.sun.jdi.VirtualMachine.TRACE_ALL;
} else {
fVMTraceFlags = Integer.decode(next).intValue();
}
} else {
System.out.println("Invalid option: " + arg);
printUsage();
return false;
}
}
}
}
fVMLauncherName = vmLauncherName;
fTargetAddress = targetAddress;
fClassPath = classPath;
fBootPath = bootPath;
fVMType = vmType;
fVerbose = verbose;
return true;
}
/**
* Prints the various options to pass to the constructor.
*/
protected void printUsage() {
System.out.println("Possible options:");
System.out.println("-launcher <Name of the launcher class>");
System.out.println("-address <Address of the target VM>");
System.out.println("-port <Debug port number>");
System.out.println("-cp <Path to the test program>");
System.out.println("-bp <Boot classpath for the system class library>");
System.out.println("-vmtype <The type of VM: JDK, J9, ...>");
System.out.println("-verbose | -v");
System.out.println("-stdout <file where VM output is written to>");
System.out.println("-stderr <file where VM error output is written to>");
System.out.println("-proxyout <file where proxy output is written to>");
System.out.println("-proxyerr <file where proxy error output is written to>");
System.out.println("-vmcmd <exec string to start VM>");
System.out.println("-proxycmd <exec string to start proxy>");
}
/**
* Set the value of the "fBool" field back to its original value
*/
protected void resetField() {
Field field = getField("fBool");
Value value = null;
value = fVM.mirrorOf(false);
try {
getObjectReference().setValue(field, value);
} catch (ClassNotLoadedException e) {
assertTrue("resetField.2", false);
} catch (InvalidTypeException e) {
assertTrue("resetField.3", false);
}
}
/**
* Set the value of the "fString" field back to its original value
*/
protected void resetStaticField() {
Field field = getField("fString");
Value value = null;
value = fVM.mirrorOf("Hello World");
try {
getMainClass().setValue(field, value);
} catch (ClassNotLoadedException e) {
assertTrue("resetField.1", false);
} catch (InvalidTypeException e) {
assertTrue("resetField.2", false);
}
}
/**
* Runs this test's suite with the given arguments.
*/
protected void runSuite(String[] args) {
// Check args
if (!parseArgs(args))
return;
// Run test
System.out.println(new java.util.Date());
System.out.println("Begin testing " + getName() + "...");
junit.textui.TestRunner.run(suite());
System.out.println("Done testing " + getName() + ".");
}
/**
* Sets the 'in control of the VM' flag for this test.
*/
void setInControl(boolean inControl) {
fInControl = inControl;
}
/**
* Launch target VM and start program in target VM.
*/
protected void launchTargetAndStartProgram() {
launchTargetAndConnectToVM();
startProgram();
}
/**
* Init tests
*/
protected void setUp() {
if (fVM == null && fInControl) {
launchTargetAndStartProgram();
}
try {
verbose("Setting up the test");
localSetUp();
} catch (RuntimeException e) {
System.out.println("Runtime exception during set up:");
e.printStackTrace();
} catch (Error e) {
System.out.println("Error during set up:");
e.printStackTrace();
}
}
/**
* Sets the VM info for this test.
*/
void setVMInfo(VMInformation info) {
if (info != null) {
fVM = info.fVM;
fLaunchedVM = info.fLaunchedVM;
fEventReader = info.fEventReader;
fConsoleReader = info.fConsoleReader;
}
}
/**
* Stop console and event readers.
*/
protected void stopReaders() {
stopEventReader();
stopConsoleReaders();
}
/**
* Shut down the target.
*/
protected void shutDownTarget() {
stopReaders();
if (fVM != null) {
try {
fVM.exit(0);
} catch (VMDisconnectedException e) {
}
}
fVM = null;
fLaunchedVM = null;
// We want subsequent connections to use different ports, unless a
// VM exec sting is given.
if (fVmCmd == null)
fBackEndPort += 2;
}
/**
* Starts the threads that reads from the VM and proxy input and error streams
*/
private void startConsoleReaders() {
if (fStdoutFile != null) {
fConsoleReader =
new FileConsoleReader(
"JDI Tests Console Reader",
fStdoutFile,
fLaunchedVM.getInputStream());
} else {
fConsoleReader =
new NullConsoleReader("JDI Tests Console Reader", fLaunchedVM.getInputStream());
}
fConsoleReader.start();
if (fStderrFile != null) {
fConsoleErrorReader =
new FileConsoleReader(
"JDI Tests Console Error Reader",
fStderrFile,
fLaunchedVM.getErrorStream());
} else {
fConsoleErrorReader =
new NullConsoleReader(
"JDI Tests Console Error Reader",
fLaunchedVM.getErrorStream());
}
fConsoleErrorReader.start();
if (fLaunchedProxy == null)
return;
if (fProxyoutFile != null) {
fProxyReader =
new FileConsoleReader(
"JDI Tests Proxy Reader",
fProxyoutFile,
fLaunchedProxy.getInputStream());
} else {
fProxyReader =
new NullConsoleReader(
"JDI Tests Proxy Reader",
fLaunchedProxy.getInputStream());
}
fProxyReader.start();
if (fProxyerrFile != null) {
fProxyErrorReader =
new FileConsoleReader(
"JDI Tests Proxy Error Reader",
fProxyerrFile,
fLaunchedProxy.getErrorStream());
} else {
fProxyErrorReader =
new NullConsoleReader(
"JDI Tests Proxy Error Reader",
fLaunchedProxy.getErrorStream());
}
fProxyErrorReader.start();
}
/**
* Stops the console reader.
*/
private void stopConsoleReaders() {
if (fConsoleReader != null)
fConsoleReader.stop();
if (fConsoleErrorReader != null)
fConsoleErrorReader.stop();
if (fProxyReader != null)
fProxyReader.stop();
if (fProxyErrorReader != null)
fProxyErrorReader.stop();
}
/**
* Starts event reader.
*/
private void startEventReader() {
// Create the VM event reader.
fEventReader = new EventReader("JDI Tests Event Reader", fVM.eventQueue());
}
/**
* Stops the event reader.
*/
private void stopEventReader() {
fEventReader.stop();
}
protected void killVM() {
if (fLaunchedVM != null)
fLaunchedVM.destroy();
if (fLaunchedProxy != null)
fLaunchedProxy.destroy();
}
/**
* Starts the target program.
*/
protected void startProgram() {
verbose("Starting target program");
// Request class prepare events
EventRequest classPrepareRequest =
fVM.eventRequestManager().createClassPrepareRequest();
classPrepareRequest.enable();
// Prepare to receive the token class prepare event
ClassPrepareEventWaiter waiter =
new ClassPrepareEventWaiter(
classPrepareRequest,
true,
"org.eclipse.debug.jdi.tests.program.MainClass");
fEventReader.addEventListener(waiter);
// Start the event reader (this will start the VM when the VMStartEvent is picked up)
fEventReader.start();
// Wait until the program has started
Event event = (ClassPrepareEvent) waitForEvent(waiter, 3 * TIMEOUT);
fEventReader.removeEventListener(waiter);
if (event == null) {
try {
System.out.println(
"\nThe program doesn't seem to have started after " + (3 * TIMEOUT) + "ms");
InputStream errorStream = fLaunchedVM.getErrorStream();
int read;
do {
read = errorStream.read();
if (read != -1)
System.out.print((char) read);
} while (read != -1);
} catch (IOException e) {
}
}
// Stop class prepare events
fVM.eventRequestManager().deleteEventRequest(classPrepareRequest);
// Wait for the program to be ready to be tested
waitUntilReady();
}
/**
* Returns all tests
*/
protected Test suite() {
JDITestSuite suite = new JDITestSuite(this);
Vector testNames = getAllMatchingTests("testJDI");
Iterator iterator = testNames.iterator();
while (iterator.hasNext()) {
String name = (String) iterator.next();
suite.addTest(new JDITestCase(this, name));
}
return suite;
}
/**
* Undo the initialization of the test.
*/
protected void tearDown() {
try {
super.tearDown();
} catch (Exception e) {
System.out.println("Exception during tear down:");
e.printStackTrace();
}
try {
verbose("Tearing down the test");
localTearDown();
// Ensure that the test didn't leave a modification watchpoint that could change the expected state of the program
if (fVM != null) {
assertTrue(fVM.eventRequestManager().modificationWatchpointRequests().size() == 0);
if (fInControl) {
shutDownTarget();
}
}
} catch (RuntimeException e) {
System.out.println("Runtime exception during tear down:");
e.printStackTrace();
} catch (Error e) {
System.out.println("Error during tear down:");
e.printStackTrace();
}
}
/**
* Triggers and waits for the given event to come in.
* Let the thread go if asked.
* Throws an Error if the event didn't come in after TIMEOUT ms
*/
protected Event triggerAndWait(
EventRequest request,
String eventType,
boolean shouldGo) {
Event event = triggerAndWait(request, eventType, shouldGo, TIMEOUT);
if (event == null)
throw new Error(
"Event for " + request + " didn't come in after " + TIMEOUT + "ms");
else
return event;
}
/**
* Triggers and waits for the given event to come in.
* Let the thread go if asked.
* Returns null if the event didn't come in after the given amount of time (in ms)
*/
protected Event triggerAndWait(
EventRequest request,
String eventType,
boolean shouldGo,
long time) {
// Suspend only if asked
if (shouldGo)
request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
else
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
// Enable request
request.enable();
// Prepare to receive the event
EventWaiter waiter = new EventWaiter(request, shouldGo);
fEventReader.addEventListener(waiter);
// Trigger the event
triggerEvent(eventType);
// Wait for the event to come in
Event event = waitForEvent(waiter, TIMEOUT);
fEventReader.removeEventListener(waiter);
if (shouldGo) {
// Wait for the program to be ready
waitUntilReady();
}
// Clear request
fVM.eventRequestManager().deleteEventRequest(request);
return event;
}
/**
* Triggers the given type of event. See the MainClass for details on types of event.
*/
protected void triggerEvent(String eventType) {
// Set the "fEventType" field to the given eventType
ClassType type = getMainClass();
Field field = type.fieldByName("fEventType");
assertTrue("1", field != null);
Value value = null;
value = fVM.mirrorOf(eventType);
try {
type.setValue(field, value);
} catch (ClassNotLoadedException e) {
assertTrue("2", false);
} catch (InvalidTypeException e) {
assertTrue("3", false);
}
// Resume the test thread
ThreadReference thread = getThread();
int suspendCount = thread.suspendCount();
for (int i = 0; i < suspendCount; i++)
thread.resume();
}
/**
* Triggers a step event and waits for it to come in.
*/
protected StepEvent triggerStepAndWait() {
return triggerStepAndWait(
getThread(),
StepRequest.STEP_MIN,
StepRequest.STEP_OVER);
}
protected StepEvent triggerStepAndWait(
ThreadReference thread,
int gran,
int depth) {
// Request for step events
EventRequest eventRequest =
fVM.eventRequestManager().createStepRequest(thread, gran, depth);
eventRequest.addCountFilter(1);
eventRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
eventRequest.enable();
return triggerStepAndWait(thread, eventRequest, TIMEOUT);
}
protected StepEvent triggerStepAndWait(
ThreadReference thread,
EventRequest eventRequest,
int timeout) {
// Prepare to receive the event
EventWaiter waiter = new EventWaiter(eventRequest, true);
fEventReader.addEventListener(waiter);
// Trigger step event
int suspendCount = thread.suspendCount();
for (int i = 0; i < suspendCount; i++)
thread.resume();
// Wait for the event to come in
StepEvent event = (StepEvent) waitForEvent(waiter, timeout);
fEventReader.removeEventListener(waiter);
if (event == null)
throw new Error("StepEvent didn't come in after " + timeout + "ms");
// Stop getting step events
fVM.eventRequestManager().deleteEventRequest(eventRequest);
// Wait for the program to be ready
waitUntilReady();
return event;
}
/**
* Output verbose string if asked for.
*/
protected void verbose(String verboseString) {
if (fVerbose)
System.out.println(verboseString);
}
/**
* Waits for an event to come in using the given waiter.
* Waits for the given time. If it times out, returns null.
*/
protected Event waitForEvent(EventWaiter waiter, long time) {
Event event;
try {
event = waiter.waitEvent(time);
} catch (InterruptedException e) {
event = null;
}
return event;
}
/**
* Waits until the program is ready to be tested.
* The default behaviour is to wait until the "Test Thread" throws and catches
* an exception.
*/
protected void waitUntilReady() {
// Make sure the program is running
ThreadReference thread = getThread();
while (thread == null || thread.suspendCount() > 0) {
fVM.resume();
thread = getThread();
}
// Create exception request
EventRequest request =
fVM.eventRequestManager().createExceptionRequest(null, true, false);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.enable();
// Prepare to receive the event
EventWaiter waiter = new EventWaiter(request, false);
fEventReader.addEventListener(waiter);
while (true) {
// Wait for the event to come in
ExceptionEvent event = (ExceptionEvent) waitForEvent(waiter, TIMEOUT);
// Throw error if event is null
if (event == null)
throw new Error("Target program was not ready after " + TIMEOUT + "ms");
// Get the method where the exception was thrown
Method meth = event.location().method();
if (meth == null || !meth.name().equals("printAndSignal"))
fVM.resume();
else
break;
}
// Disable request
fEventReader.removeEventListener(waiter);
fVM.eventRequestManager().deleteEventRequest(request);
}
}