blob: b941eada8a8cee7123ed48c7c34462c60033b84c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Andrey Loskutov 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:
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.debug.tests.breakpoints;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.eval.IEvaluationListener;
import org.eclipse.jdt.debug.eval.IEvaluationResult;
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
import org.eclipse.jdt.debug.tests.TestAgainException;
import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
import org.eclipse.jdt.internal.debug.ui.threadgroups.JavaDebugTargetProxy;
import org.eclipse.jdt.internal.debug.ui.threadgroups.JavaThreadEventHandler;
/**
* Tests for JavaThreadEventHandler
*/
public class JavaThreadEventHandlerTests extends AbstractDebugTest {
public JavaThreadEventHandlerTests(String name) {
super(name);
}
/**
* Tests that we can compute frame index for arbitrary frames, see bug 515696
*/
public void testComputeFrameIndexOnSecondFrameAndMonitorsOn() throws Exception {
final String typeName = "DropTests";
final int expectedFramesCount = 5;
IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
IJavaThread thread = null;
try {
thread = launchToBreakpoint(typeName);
IBreakpoint hit = getBreakpoint(thread);
assertNotNull("suspended, but not by breakpoint", hit);
assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
assertNotNull("There should be a stackframe", frame);
IDebugTarget debugTarget = thread.getDebugTarget();
JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
eventHandler.displayMonitors = true;
IStackFrame[] frames = frame.getThread().getStackFrames();
assertEquals(expectedFramesCount, frames.length);
// They are all off by one, because we have one monitor installed
int monitorCount = 1;
for (int i = 0; i < frames.length; i++) {
int index = eventHandler.indexOf(frames[i]);
assertEquals(i + monitorCount, index);
}
}
finally {
terminateAndRemove(thread);
removeAllBreakpoints();
}
}
/**
* Tests that we can compute frame index for arbitrary frames, see bug 515696
*/
public void testComputeFrameIndexOnSecondFrameAndMonitorsOff() throws Exception {
final String typeName = "DropTests";
final int expectedFramesCount = 5;
IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
IJavaThread thread = null;
try {
thread = launchToBreakpoint(typeName);
IBreakpoint hit = getBreakpoint(thread);
assertNotNull("suspended, but not by breakpoint", hit);
assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
assertNotNull("There should be a stackframe", frame);
IDebugTarget debugTarget = thread.getDebugTarget();
JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
eventHandler.displayMonitors = false;
IStackFrame[] frames = frame.getThread().getStackFrames();
assertEquals(expectedFramesCount, frames.length);
for (int i = 0; i < frames.length; i++) {
int index = eventHandler.indexOf(frames[i]);
assertEquals(i, index);
}
}
finally {
terminateAndRemove(thread);
removeAllBreakpoints();
}
}
/**
* Tests that we can (or can't) compute frame index during evaluation
*
* @throws Exception
*/
public void testComputeFrameIndexDuringEvaluation() throws Exception {
String typeName = "DropTests";
final int expectedFramesCount = 5;
IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
IJavaThread thread = null;
try {
thread = launchToBreakpoint(typeName);
IBreakpoint hit = getBreakpoint(thread);
assertNotNull("suspended, but not by breakpoint", hit);
assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
final int sleepTimeMillis = 750;
String snippet = "java.lang.Thread.sleep(" + sleepTimeMillis + "); return true;";
TaskOnFrame task = new TaskOnFrame() {
@Override
public void performChecks(IJavaThread thread, IStackFrame[] frames, MyJavaThreadEventHandler eventHandler) throws Exception {
assertEquals(expectedFramesCount, frames.length);
IStackFrame[] currFrames = frames[0].getThread().getStackFrames();
// thread not suspended, so no stack frames as per method contract
assertEquals(0, currFrames.length);
assertTrue(thread.isPerformingEvaluation());
// indexOf method waits for evaluation and computes the right result
for (int i = 0; i < expectedFramesCount; i++) {
int index = eventHandler.indexOf(frames[i]);
if (index == -1) {
throw new TestAgainException("Evaluation took too long");
}
assertEquals(i, index);
}
Thread.sleep(sleepTimeMillis);
// evaluation should be done by now
assertFalse(thread.isPerformingEvaluation());
}
};
IValue value = doEvalAndRunInParallel(thread, snippet, task);
assertTrue("The result of '" + snippet + "') should be true", Boolean.parseBoolean(value.getValueString()));
}
finally {
terminateAndRemove(thread);
removeAllBreakpoints();
}
}
private IValue doEvalAndRunInParallel(IJavaThread thread, String snippet, TaskOnFrame task) throws Exception {
class Listener implements IEvaluationListener {
IEvaluationResult fResult;
@Override
public void evaluationComplete(IEvaluationResult result) {
fResult = result;
}
public IEvaluationResult getResult() {
return fResult;
}
}
Listener listener = new Listener();
IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
assertNotNull("There should be a stackframe", frame);
IStackFrame[] frames = thread.getStackFrames();
IDebugTarget debugTarget = thread.getDebugTarget();
JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
ASTEvaluationEngine engine = new ASTEvaluationEngine(getProjectContext(), (IJavaDebugTarget) debugTarget);
try {
assertTrue(thread.isSuspended());
engine.evaluate(snippet, frame, listener, DebugEvent.EVALUATION_IMPLICIT, false);
long timeout = System.currentTimeMillis() + 5000;
while (thread.isSuspended() && System.currentTimeMillis() < timeout) {
System.out.println("Waiting for evaluation to start..");
Thread.sleep(10);
}
// evaluation must be running now
assertTrue(thread.isPerformingEvaluation());
assertFalse(thread.isSuspended());
assertNull(listener.getResult());
// Actual test
task.performChecks(thread, frames, eventHandler);
// Checck post-conditions
IEvaluationResult result = listener.getResult();
assertNotNull("The evaluation should have result: ", result);
assertNull("The evaluation should not have exception : " + result.getException(), result.getException());
String firstError = result.hasErrors() ? result.getErrorMessages()[0] : "";
assertFalse("The evaluation should not have errors : " + firstError, result.hasErrors());
return listener.getResult().getValue();
}
finally {
engine.dispose();
eventHandler.dispose();
}
}
static class MyJavaThreadEventHandler extends JavaThreadEventHandler {
boolean displayMonitors;
public MyJavaThreadEventHandler(AbstractModelProxy proxy) {
super(proxy);
}
@Override
public int indexOf(IStackFrame frame) {
return super.indexOf(frame);
}
@Override
protected boolean isDisplayMonitors() {
return displayMonitors;
}
}
interface TaskOnFrame {
void performChecks(IJavaThread thread, IStackFrame[] frames, MyJavaThreadEventHandler eventHandler) throws Exception;
}
}