blob: a48e284a63c660ea50f27ae1f22ad4fad3e3f61f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2012 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
*******************************************************************************/
package org.eclipse.wst.jsdt.debug.rhino.tests;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
import org.eclipse.wst.jsdt.debug.internal.rhino.debugger.RhinoDebuggerImpl;
import org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket;
import org.eclipse.wst.jsdt.debug.internal.rhino.transport.JSONConstants;
import org.eclipse.wst.jsdt.debug.internal.rhino.transport.PipedTransportService;
import org.eclipse.wst.jsdt.debug.internal.rhino.transport.RhinoRequest;
import org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler;
import org.eclipse.wst.jsdt.debug.transport.DebugSession;
import org.eclipse.wst.jsdt.debug.transport.TransportService;
import org.eclipse.wst.jsdt.debug.transport.exception.DisconnectedException;
import org.eclipse.wst.jsdt.debug.transport.exception.TimeoutException;
import org.eclipse.wst.jsdt.debug.transport.packet.Response;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Scriptable;
/**
* Abstract test for making requests
*
* @since 1.0
*/
public abstract class RequestTest extends TestCase {
/**
* Default implementation of a {@link Subhandler}
*/
abstract class SubHandler implements Subhandler {
private String testname = null;
public SubHandler(String testname) {
Assert.assertNotNull("The test name cannot be null", testname); //$NON-NLS-1$
this.testname = testname;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#testName()
*/
public String testName() {
return this.testname;
}
}
/**
* Handler to check that we can get frames from a suspended thread
* @since 1.1
*/
final class FrameCheckHandler extends SubHandler {
/**
* Constructor
* @param testname
*/
public FrameCheckHandler() {
super(getName());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#handleEvent(org.eclipse.wst.jsdt.debug.transport.DebugSession, org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket)
*/
public boolean handleEvent(DebugSession debugSession, EventPacket event) {
if (event.getEvent().equals(JSONConstants.BREAK)) {
Number threadId = (Number) event.getBody().get(JSONConstants.THREAD_ID);
Number contextId = (Number) event.getBody().get(JSONConstants.CONTEXT_ID);
RhinoRequest request = new RhinoRequest(JSONConstants.FRAMES);
request.getArguments().put(JSONConstants.THREAD_ID, threadId);
try {
debugSession.send(request);
Response response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(testName()+": the request for frames from thread ["+threadId.intValue()+"] was not successful", response.isSuccess()); //$NON-NLS-1$ //$NON-NLS-2$
Collection frames = (Collection) response.getBody().get(JSONConstants.FRAMES);
for (Iterator iterator = frames.iterator(); iterator.hasNext();) {
Number frameId = (Number) iterator.next();
request = new RhinoRequest(JSONConstants.FRAME);
request.getArguments().put(JSONConstants.THREAD_ID, threadId);
request.getArguments().put(JSONConstants.CONTEXT_ID, contextId);
request.getArguments().put(JSONConstants.FRAME_ID, frameId);
debugSession.send(request);
response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(testName()+": the request for frame ["+frameId.intValue()+"] frmo thread ["+threadId.intValue()+"] was not successful", response.isSuccess()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
} catch (DisconnectedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
/**
* Handler to check that the thread returned when suspended is the same thread
* from the break event
* @since 1.1
*/
final class ThreadCheckHandler extends SubHandler {
/**
* Constructor
*/
public ThreadCheckHandler() {
super(getName());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#handleEvent(org.eclipse.wst.jsdt.debug.transport.DebugSession, org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket)
*/
public boolean handleEvent(DebugSession debugSession, EventPacket event) {
if (event.getEvent().equals(JSONConstants.BREAK)) {
Number threadId = (Number) event.getBody().get(JSONConstants.THREAD_ID);
RhinoRequest request = new RhinoRequest(JSONConstants.THREADS);
try {
debugSession.send(request);
Response response = debugSession.receiveResponse(request.getSequence(), 10000);
assertTrue(response.isSuccess());
List threads = (List) response.getBody().get(JSONConstants.THREADS);
assertTrue(testName()+": the listing of threads must not be empty", threads.size() > 0); //$NON-NLS-1$
assertEquals(testName()+": the thread ids do not match", threadId.intValue(), Util.numberAsInt(threads.get(0))); //$NON-NLS-1$
} catch (DisconnectedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
/**
* Handler for setting breakpoints on all executable lines in a loaded script
* @since 1.1
*/
final class SetBreakpointsHandler extends SubHandler {
/**
* Constructor
*/
public SetBreakpointsHandler() {
super(getName());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#handleEvent(org.eclipse.wst.jsdt.debug.transport.DebugSession, org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket)
*/
public boolean handleEvent(DebugSession debugSession, EventPacket event) {
if (event.getEvent().equals(JSONConstants.SCRIPT)) {
Number scriptId = (Number) event.getBody().get(JSONConstants.SCRIPT_ID);
RhinoRequest request = new RhinoRequest(JSONConstants.SCRIPT);
request.getArguments().put(JSONConstants.SCRIPT_ID, scriptId);
try {
debugSession.send(request);
Response response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(response.isSuccess());
Map result = (Map) response.getBody().get(JSONConstants.SCRIPT);
// line numbers
List lineNumbers = (List) result.get(JSONConstants.LINES);
for (Iterator iterator = lineNumbers.iterator(); iterator.hasNext();) {
Number lineNumber = (Number) iterator.next();
request = new RhinoRequest(JSONConstants.SETBREAKPOINT);
request.getArguments().put(JSONConstants.SCRIPT_ID, scriptId);
request.getArguments().put(JSONConstants.LINE, lineNumber);
request.getArguments().put(JSONConstants.CONDITION, "1===1"); //$NON-NLS-1$
debugSession.send(request);
response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(testName()+": the request to set a breakpoint on line ["+lineNumber+"] was not successful", response.isSuccess()); //$NON-NLS-1$ //$NON-NLS-2$
Map breakpoint = (Map) response.getBody().get(JSONConstants.BREAKPOINT);
Number breakpointId = (Number) breakpoint.get(JSONConstants.BREAKPOINT_ID);
request = new RhinoRequest(JSONConstants.BREAKPOINT);
request.getArguments().put(JSONConstants.BREAKPOINT_ID, breakpointId);
debugSession.send(request);
response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(response.isSuccess());
breakpoint = (Map) response.getBody().get(JSONConstants.BREAKPOINT);
assertEquals(breakpointId.intValue(), Util.numberAsInt(breakpoint.get(JSONConstants.BREAKPOINT_ID)));
assertEquals(scriptId.intValue(), Util.numberAsInt(breakpoint.get(JSONConstants.SCRIPT_ID)));
assertEquals(lineNumber.intValue(), Util.numberAsInt(breakpoint.get(JSONConstants.LINE)));
assertEquals("1===1", breakpoint.get(JSONConstants.CONDITION)); //$NON-NLS-1$
}
} catch (DisconnectedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
/**
* Handler to set breakpoints on a given set of lines. The lines are not checked
* to see if they are valid.
*
* @since 1.1
*/
final class SetBreakpointHandler extends SubHandler {
int[] adds = null;
/**
* Constructor
* @param lines <code>null</code> is not accepted, not is an empty array
*/
public SetBreakpointHandler(int[] lines) {
super(getName());
assertNotNull(testName()+": no line numbers have been specified to set breakpoints on", lines); //$NON-NLS-1$
assertTrue(testName()+": no line numbers have been specified to set breakpoints on", lines.length > 0); //$NON-NLS-1$
this.adds = lines;
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#handleEvent(org.eclipse.wst.jsdt.debug.transport.DebugSession, org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket)
*/
public boolean handleEvent(DebugSession debugSession, EventPacket event) {
if (event.getEvent().equals(JSONConstants.SCRIPT)) {
Number scriptId = (Number) event.getBody().get(JSONConstants.SCRIPT_ID);
RhinoRequest request = new RhinoRequest(JSONConstants.SCRIPT);
request.getArguments().put(JSONConstants.SCRIPT_ID, scriptId);
try {
debugSession.send(request);
Response response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(response.isSuccess());
Map script = (Map) response.getBody().get(JSONConstants.SCRIPT);
assertNotNull(testName()+": the response body cannot be null", script); //$NON-NLS-1$
for (int i = 0; i < adds.length; i++) {
request = new RhinoRequest(JSONConstants.SETBREAKPOINT);
request.getArguments().put(JSONConstants.SCRIPT_ID, scriptId);
request.getArguments().put(JSONConstants.LINE, new Integer(adds[i]));
debugSession.send(request);
response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(testName()+": the request to set a breakpoint on line ["+adds[i]+"] was not successful", response.isSuccess()); //$NON-NLS-1$ //$NON-NLS-2$
}
} catch (DisconnectedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
/**
* Clears all of the breakpoints that are hit
*
* @since 1.1
*/
final class ClearBreakpointsHandler extends SubHandler {
/**
* Constructor
*/
public ClearBreakpointsHandler() {
super(getName());
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.debug.rhino.tests.TestEventHandler.Subhandler#handleEvent(org.eclipse.wst.jsdt.debug.transport.DebugSession, org.eclipse.wst.jsdt.debug.internal.rhino.transport.EventPacket)
*/
public boolean handleEvent(DebugSession debugSession, EventPacket event) {
if (event.getEvent().equals(JSONConstants.BREAK)) {
Number bid = (Number)event.getBody().get(JSONConstants.BREAKPOINT);
if(bid == null && JSONConstants.STEP_OUT.equals(event.getBody().get(JSONConstants.STEP))) {
return false;
}
RhinoRequest request = new RhinoRequest(JSONConstants.CLEARBREAKPOINT);
request.getArguments().put(JSONConstants.BREAKPOINT_ID, bid);
try {
debugSession.send(request);
Response response = debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
assertTrue(testName()+": the request to clear breakpoint ["+bid+"] should have succeeded", response.isSuccess()); //$NON-NLS-1$ //$NON-NLS-2$
return true;
} catch (DisconnectedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
return false;
}
}
protected RhinoDebuggerImpl debugger;
protected DebugSession debugSession;
protected TestEventHandler eventHandler;
protected ContextFactory contextFactory;
private static boolean tracing = false;
/**
* Turns on tracing for the test. All testing event handlers use this.
*/
protected void useTracing() {
tracing = true;
}
/**
* Turns off tracing. This method is called on every {@link #tearDown()} invocation.
*/
protected void disableTracing() {
tracing = false;
}
/**
* Returns if tracing is enabled
*
* @return if tracing is enabled
*/
public static boolean isTracing() {
return tracing;
}
/**
* Evaluates the given script source
* @param script
* @since 1.1
*/
protected void evalScript(String script) {
Scriptable scope = null;
Context context = contextFactory.enterContext();
try {
scope = context.initStandardObjects();
context.evaluateString(scope, script, JSONConstants.SCRIPT, 0, null);
} finally {
Context.exit();
}
}
/**
* Evaluates the given script source and waits for the given number of events
* @param script
* @param eventcount
* @since 1.1
*/
protected void evalScript(String script, int eventcount) {
evalScript(script);
waitForEvents(eventcount);
}
/**
* Evaluates the given script and waits for the specific events to be received
* @param script
* @param events
* @since 1.1
*/
protected void evalScript(String script, EventPacket[] events) {
evalScript(script);
waitForEvents(events);
}
/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
TransportService pipedTransport = new PipedTransportService();
ConnectionHelper helper = new ConnectionHelper(pipedTransport, null);
debugger = new RhinoDebuggerImpl(pipedTransport, null, false, false);
debugger.start();
debugSession = new DebugSession(helper.getClientConnection());
eventHandler = new TestEventHandler(debugSession, getName());
eventHandler.start();
assertTrue(suspendForRuntime(debugger, 100));
contextFactory = new ContextFactory();
contextFactory.addListener(debugger);
super.setUp();
}
/**
* Suspend waiting for the debugger to have a connected session
*
* @param debug the debugger to poll for a session connection
* @param timeout the amount of time to wait
* @return true when a {@link DebugSession} has connected
*/
public synchronized boolean suspendForRuntime(RhinoDebuggerImpl debug, long timeout) {
while (!debug.isConnected())
try {
wait(timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
return debug.isConnected();
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown() throws Exception {
disableTracing();
super.tearDown();
contextFactory.removeListener(debugger);
eventHandler.stop();
debugger.stop();
debugSession.dispose();
}
/**
* Forces the backing event handler to block until the given number of events have been
* received or a timeout occurs.
*
* @param count the event count to wait for
*/
synchronized void waitForEvents(int count) {
eventHandler.waitForEvents(count);
}
/**
* Sets the collection of specific events we are expecting to handle
*
* @param events the collection of events
*/
synchronized void setExpectedEvents(EventPacket[] events) {
eventHandler.setExpectedEvents(events);
}
/**
* Forces the backing event handler to block until the given number of events have been
* received or a timeout occurs.
*
* @param events the specific set of events expected
* @see #setExpectedEvents(EventPacket[])
*/
synchronized void waitForEvents(EventPacket[] events) {
eventHandler.waitForEvents(events);
}
/**
* @param props
* @param varname
* @return the variable map or <code>null</code>
*/
protected Map findVar(List props, String varname) {
if(props != null && varname != null) {
Map prop = null;
for (Iterator i = props.iterator(); i.hasNext();) {
prop = (Map) i.next();
if(varname.equals(prop.get(JSONConstants.NAME))) {
return prop;
}
}
}
return null;
}
/**
* @param session
* @param threadid
* @param contextid
* @param frameid
* @param refid
* @return the response, never <code>null</code>
*/
protected Response doLookup(DebugSession session, Number threadid, Number contextid, Number frameid, Number refid) throws Exception {
RhinoRequest request = new RhinoRequest(JSONConstants.LOOKUP);
request.getArguments().put(JSONConstants.THREAD_ID, threadid);
request.getArguments().put(JSONConstants.CONTEXT_ID, contextid);
request.getArguments().put(JSONConstants.FRAME_ID, frameid);
request.getArguments().put(JSONConstants.REF, refid);
debugSession.send(request);
return debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
}
}