blob: a701a1ed7346e5e8c11b97e79e801f22f16ec41b [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 com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.ClassUnloadEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.ClassUnloadRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.StepRequest;
/**
* Tests for the hot code replacement JDI extension.
*/
public class HotCodeReplacementTest extends AbstractJDITest {
/**
* Creates a new test.
*/
public HotCodeReplacementTest() {
super();
}
private void dropTopFrame(
ThreadReference thread,
org.eclipse.jdi.hcr.ThreadReference hcrThread) {
// Get stack size
int stackSize = 0;
try {
stackSize = thread.frames().size();
} catch (IncompatibleThreadStateException e) {
assertTrue("dropTopFrame.1", false);
}
// Create and install step out request
StepRequest request =
fVM.eventRequestManager().createStepRequest(
thread,
StepRequest.STEP_MIN,
StepRequest.STEP_OUT);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.enable();
// Prepare to receive the event
EventWaiter waiter = new EventWaiter(request, false);
fEventReader.addEventListener(waiter);
// Do return
boolean finallyBlocksSkipped = hcrThread.doReturn(null, true);
assertTrue("dropTopFrame.2", !finallyBlocksSkipped);
// Wait for the event to come in
Event event = waitForEvent(waiter, 10000); // Wait 10s max
assertTrue("dropTopFrame.3", event != null);
fEventReader.removeEventListener(waiter);
fVM.eventRequestManager().deleteEventRequest(request);
// Check thread has dropped top frame
assertTrue("dropTopFrame.4", thread.isSuspended());
int newStackSize = 0;
try {
newStackSize = thread.frames().size();
} catch (IncompatibleThreadStateException e) {
assertTrue("dropTopFrame.5", false);
}
assertEquals("dropTopFrame.6", stackSize - 1, newStackSize);
}
private void getClassFileVersion() {
org.eclipse.jdi.hcr.ReferenceType type =
(org.eclipse.jdi.hcr.ReferenceType) getMainClass();
int version = type.getClassFileVersion();
assertEquals("getClassFileVersion.1", -211226504, version);
}
/**
* Init the fields that are used by this test only.
*/
public void localSetUp() {
waitUntilReady();
}
/**
* Run all tests and output to standard output.
*/
public static void main(String[] args) {
new HotCodeReplacementTest().runSuite(args);
}
/**
* Gets the name of the test case.
*/
public String getName() {
return "Hot code replacement extension to JDI (org.eclipse.jdi.hcr) tests";
}
private void reenterOnExit(ThreadReference thread) {
// Get top frame's location
Location location = null;
try {
StackFrame frame = (StackFrame) thread.frames(0, 1).get(0);
location = frame.location();
} catch (IncompatibleThreadStateException e) {
assertTrue("reenterOnExit.1", false);
}
// Create and install reenter step request
org.eclipse.jdi.hcr.EventRequestManager eventRequestManager =
(org.eclipse.jdi.hcr.EventRequestManager) fVM.eventRequestManager();
org.eclipse.jdi.hcr.ReenterStepRequest request =
eventRequestManager.createReenterStepRequest(thread);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.enable();
// Prepare to receive the step event
EventWaiter waiter = new EventWaiter(request, false);
fEventReader.addEventListener(waiter);
// Resume thread with a doReturn so that the frame is reentered right away
((org.eclipse.jdi.hcr.ThreadReference) thread).doReturn(null, false);
// Wait for the step event to come in
StepEvent event = (StepEvent) waitForEvent(waiter, 10000); // Wait 10s max
assertTrue("reenterOnExit.2", event != null);
fEventReader.removeEventListener(waiter);
fVM.eventRequestManager().deleteEventRequest(request);
// Check that the top frame location is as expected
Location newLocation = null;
try {
StackFrame frame = (StackFrame) thread.frames(0, 1).get(0);
newLocation = frame.location();
} catch (IncompatibleThreadStateException e) {
assertTrue("reenterOnExit.3", false);
}
assertTrue("reenterOnExit.4", !newLocation.equals(location));
assertTrue("reenterOnExit.5", newLocation.codeIndex() <= location.codeIndex());
}
private void reloadClasses() {
// Gets the old class
ReferenceType oldType = getMainClass();
// Create and install class unload and class prepare event requests
ClassUnloadRequest unloadRequest =
fVM.eventRequestManager().createClassUnloadRequest();
unloadRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
unloadRequest.enable();
ClassPrepareRequest loadRequest =
fVM.eventRequestManager().createClassPrepareRequest();
loadRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
loadRequest.enable();
// Prepare to receive the class unload event
EventWaiter unloadEventWaiter = new EventWaiter(unloadRequest, true);
fEventReader.addEventListener(unloadEventWaiter);
// Prepare to receive the class prepare event
EventWaiter loadEventWaiter = new EventWaiter(loadRequest, true);
fEventReader.addEventListener(loadEventWaiter);
// Reload classes
org.eclipse.jdi.hcr.VirtualMachine vm =
(org.eclipse.jdi.hcr.VirtualMachine) fVM;
int result =
vm.classesHaveChanged(
new String[] { "org.eclipse.debug.jdi.tests.program.MainClass" });
assertEquals("reloadClasses.1", org.eclipse.jdi.hcr.VirtualMachine.RELOAD_SUCCESS, result);
// Wait for the class unload event to come in
ClassUnloadEvent unloadEvent =
(ClassUnloadEvent) waitForEvent(unloadEventWaiter, 10000);
// Wait 10s max
assertTrue("reloadClasses.2", unloadEvent != null);
fEventReader.removeEventListener(unloadEventWaiter);
fVM.eventRequestManager().deleteEventRequest(unloadRequest);
assertEquals(
"reloadClasses.3",
"org.eclipse.debug.jdi.tests.program.MainClass",
unloadEvent.className());
// Wait for the class prepare event to come in
ClassPrepareEvent loadEvent =
(ClassPrepareEvent) waitForEvent(loadEventWaiter, 10000);
// Wait 10s max
assertTrue("reloadClasses.4", loadEvent != null);
fEventReader.removeEventListener(loadEventWaiter);
fVM.eventRequestManager().deleteEventRequest(loadRequest);
ReferenceType newType = loadEvent.referenceType();
assertEquals(
"reloadClasses.5",
"org.eclipse.debug.jdi.tests.program.MainClass",
newType.name());
assertTrue("reloadClasses.6", !oldType.equals(newType));
}
/**
* Use case 1:
* . get a thread and suspend it
* . get hot code replacement capabilities
* . drop the top a frame
* . reload some classes
* . request reeenter on exit
* . resume thread
* . get step event
* . get class file version for some classes
*/
public void testJDIUseCase1() {
// Get the suspended thread
ThreadReference thread = getThread();
assertTrue("1", thread.isSuspended());
assertEquals("2", 1, thread.suspendCount());
org.eclipse.jdi.hcr.ThreadReference hcrThread =
(org.eclipse.jdi.hcr.ThreadReference) thread;
org.eclipse.jdi.hcr.VirtualMachine vm =
(org.eclipse.jdi.hcr.VirtualMachine) fVM;
// Drop the top a frame
try {
if (vm.canDoReturn()) {
dropTopFrame(thread, hcrThread);
}
} catch (UnsupportedOperationException e) {
//not using a VM that supports the extension
return;
}
// Reload classes
if (vm.canReloadClasses())
reloadClasses();
// Reenter on exit
if (vm.canReenterOnExit())
reenterOnExit(thread);
// Get class file version
// MML: commented out, otherwise this test fails after a change to
// the main class.
// if (vm.canGetClassFileVersion()) {
// getClassFileVersion();
// }
}
/**
* Make sure the test leaves the VM in the same state it found it.
*/
public void localTearDown() {
waitUntilReady();
}
}