/******************************************************************************* * 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.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 = 1000; 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]); 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; } }