blob: 4420489e0526998b80ff38390ff97550cc1e378b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 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.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.wst.jsdt.debug.core.jsdi.VirtualMachine;
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.JSONUtil;
import org.eclipse.wst.jsdt.debug.internal.rhino.transport.RhinoRequest;
import org.eclipse.wst.jsdt.debug.transport.DebugSession;
import org.eclipse.wst.jsdt.debug.transport.exception.DisconnectedException;
import org.eclipse.wst.jsdt.debug.transport.exception.TimeoutException;
/**
* Event handler for testing purposes
*
* @since 1.0
*/
public class TestEventHandler implements Runnable {
/**
* Sub-handler for test to implement and add to the root
* {@link TestEventHandler}
*/
public interface Subhandler {
boolean handleEvent(DebugSession debugSession, EventPacket event);
String testName();
}
/**
* Sub-handler for breakpoint specific operations
*
* @since 1.1
*/
public interface BreakpointSubHandler extends Subhandler {
/**
* Array of line numbers to add breakpoints to
*
* @param lines
*/
void linesToAddBreakpoints(int[] lines);
/**
* Array of lines to remove breakpoints from
*
* @param lines
*/
void linesToRemoveBreakpoints(int[] lines);
}
private DebugSession debugSession;
private Thread thread;
private final List subhandlers = new ArrayList();
private final ArrayList expectedEvents = new ArrayList();
private final ArrayList actualEvents = new ArrayList();
private volatile boolean shutdown = false;
private int eventCount = 0;
private String testname = null;
/**
* Constructor
*
* @param debugSession
* the current session to handle
* @param testname
* the name of the test using this handler
*/
public TestEventHandler(DebugSession debugSession, String testname) {
this.debugSession = debugSession;
this.thread = new Thread(this, "TestEventHandler"); //$NON-NLS-1$
this.testname = testname;
}
/**
* start the test handler
*/
public void start() {
thread.start();
}
/**
* stop the test handler
*/
public void stop() {
shutdown = true;
thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
this.expectedEvents.clear();
this.actualEvents.clear();
this.subhandlers.clear();
this.eventCount = 0;
}
}
/**
* Sets the events that the handler is expected to receive
*
* @param events
*/
public synchronized void setExpectedEvents(EventPacket[] events) {
this.expectedEvents.clear();
for (int i = 0; i < events.length; i++) {
this.expectedEvents.add(events[i]);
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
public void run() {
while (!shutdown) {
try {
EventPacket event = (EventPacket) debugSession.receive(JSONConstants.EVENT, VirtualMachine.DEFAULT_TIMEOUT);
handleEvent(event);
} catch (TimeoutException e) {
// ignore
} catch (DisconnectedException e) {
e.printStackTrace();
}
}
}
/**
* Add a sub handler
*
* @param subhandler
*/
public synchronized void addSubhandler(Subhandler subhandler) {
subhandlers.add(subhandler);
}
/**
* Remove a sub handler
*
* @param subhandler
*/
public synchronized void removeSubhandler(Subhandler subhandler) {
subhandlers.remove(subhandler);
}
/**
* Handles the given event packet
*
* @param event
*/
private synchronized void handleEvent(EventPacket event) {
String estring = null;
if (RequestTest.isTracing()) {
estring = JSONUtil.write(event.toJSON());
System.out.println(this.testname + " got event: " + estring); //$NON-NLS-1$
}
for (ListIterator iterator = subhandlers.listIterator(); iterator.hasNext();) {
Subhandler subhandler = (Subhandler) iterator.next();
try {
if (subhandler.handleEvent(debugSession, event)) {
if (RequestTest.isTracing()) {
System.out.println("\t" + this.testname + " handled event: " + estring); //$NON-NLS-1$ //$NON-NLS-2$
}
this.expectedEvents.remove(event);
actualEvents.add(event);
eventCount++;
notifyAll();
}
} catch (Throwable t) {
t.printStackTrace();
}
}
if (!event.getEvent().equals("thread")) { //$NON-NLS-1$
sendContinue(event, null);
}
}
/**
* Continues the handler
*
* @param event
* @param step
*/
protected void sendContinue(EventPacket event, String step) {
Number threadId = (Number) event.getBody().get("threadId"); //$NON-NLS-1$
RhinoRequest request = new RhinoRequest("continue"); //$NON-NLS-1$
request.getArguments().put("threadId", threadId); //$NON-NLS-1$
request.getArguments().put("step", step); //$NON-NLS-1$
try {
debugSession.send(request);
debugSession.receiveResponse(request.getSequence(), VirtualMachine.DEFAULT_TIMEOUT);
} catch (DisconnectedException e) {
if (!shutdown)
e.printStackTrace();
} catch (TimeoutException e) {
if (!shutdown)
e.printStackTrace();
}
}
/**
* Waits for all of the events specified from
* {@link #setExpectedEvents(EventPacket[])}
*
* @param count
*/
public synchronized void waitForEvents(int count) {
long timeout = System.currentTimeMillis() + 5000;
while (eventCount < count && System.currentTimeMillis() < timeout) {
try {
wait(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
if (eventCount != count) {
for (Iterator it = actualEvents.iterator(); it.hasNext();) {
System.err.println(it.next().toString());
}
throw new IllegalStateException("eventcount was: " + eventCount + " expected: " + count); //$NON-NLS-1$ //$NON-NLS-2$
}
} finally {
this.eventCount = 0;
}
}
/**
* Waits for the given collection of events to be handled, or a default
* timeout to occur
*
* @param events
*/
public synchronized void waitForEvents(EventPacket[] events) {
long timeout = System.currentTimeMillis() + 5000;
while (!this.expectedEvents.isEmpty() && System.currentTimeMillis() < timeout) {
try {
wait(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!this.expectedEvents.isEmpty()) {
try {
throw new IllegalStateException("Some expected events were not received"); //$NON-NLS-1$
} finally {
this.eventCount = 0;
for (int i = 0; i < this.expectedEvents.size(); i++) {
System.out.println(this.testname + " missed expected event: " + JSONUtil.write(this.expectedEvents.get(i))); //$NON-NLS-1$
}
}
}
if (this.eventCount > events.length) {
try {
throw new IllegalStateException(this.testname + " got too many events - expected [" + events.length + "] got [" + eventCount + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} finally {
this.eventCount = 0;
}
}
}
}