Revision: 1692 http://svn.sourceforge.net/vexi/?rev=1692&view=rev Author: mkpg2 Date: 2007-02-24 10:56:15 -0800 (Sat, 24 Feb 2007)
Log Message: ----------- Fixed race condition when running tests causing intermittent failures. Redone debug handling (was only working in trivial cases). Modified Paths: -------------- core/trunk/org.ibex.js/src/org/ibex/js/IDebugHandler.java core/trunk/org.vexi.debug/src/org/ibex/js/DebugHandler.java core/trunk/org.vexi.debug/src/org/ibex/js/ThreadInfo.java core/trunk/org.vexi.debug/src/org/vexi/debug/Constants.java core/trunk/org.vexi.debug/src/org/vexi/debug/DebugServer.java core/trunk/org.vexi.debug/src/org/vexi/debug/MessagePasser.java core/trunk/org.vexi.debug/src/org/vexi/devl/Main.java core/trunk/org.vexi.debug/src_junit/test/debug/Debugee.java core/trunk/org.vexi.debug/src_junit/test/debug/simple/TestSimple.java core/trunk/org.vexi.debug/src_junit/test/debug/thread/TestThread.java core/trunk/org.vexi.debug/src_junit/test/debug/vars/TestVars.java Added Paths: ----------- core/trunk/org.vexi.debug/src_junit/test/debug/DebuggerTest.java core/trunk/org.vexi.debug/src_junit/test/debug/thread/RunDebugee.java core/trunk/org.vexi.debug/src_junit/test/debug/vars/RunDebugee.java Removed Paths: ------------- core/trunk/org.vexi.debug/src_junit/test/debug/AbstractDebuggerTests.java Modified: core/trunk/org.ibex.js/src/org/ibex/js/IDebugHandler.java =================================================================== --- core/trunk/org.ibex.js/src/org/ibex/js/IDebugHandler.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.ibex.js/src/org/ibex/js/IDebugHandler.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -26,13 +26,9 @@ * Called before the execution of every byte code in the intepreter (if debugging * is on). The params provide sufficient information to display the current * execution state. - * - * @param f - * @param scope - * @param stack - * @param pc + * @param interpreter */ - public abstract void handle(JSFunction f, Scope scope, Stack stack, int pc); + public abstract void handle(Interpreter interpreter); //// Modified: core/trunk/org.vexi.debug/src/org/ibex/js/DebugHandler.java =================================================================== --- core/trunk/org.vexi.debug/src/org/ibex/js/DebugHandler.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/ibex/js/DebugHandler.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,40 +1,18 @@ package org.ibex.js; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.StringWriter; import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.TreeSet; -import java.util.Vector; -import org.ibex.js.Interpreter.Stack; -import org.ibex.js.JSNumber.I; import org.ibex.js.Parser.ScopeInfo; -import org.ibex.util.Log; import org.vexi.debug.BreakPoint; import org.vexi.debug.Constants; import org.vexi.debug.DebugServer; import org.vexi.debug.MessagePasser; import org.vexi.debug.SourceManager; -import org.vexi.debug.MessagePasser.IMessagePart; -import org.vexi.plat.Platform; -/** System.out.println("+Attempting to load session+"); +/** * TODO - update this - TODO * Handler gets chance to act before the execution of every bytecode. * <br> @@ -173,19 +151,16 @@ } - public void handle(JSFunction f, Scope scope, Stack stack, int pc) { + public void handle(Interpreter i) { //int bcode = f.op[pc]; //String bcodeName =JSU.opName(bcode); //System.out.println(bcodeName); /// Track scopes in a map - if(RTScopeInfo.Map.get(scope)==null){ - RTScopeInfo.Map.put(scope, f, pc); + if(RTScopeInfo.Map.get(i.scope)==null){ + RTScopeInfo.Map.put(i.scope, i.f, i.pc); } - - int ln = f.line[pc]; - int callPos = stack.findCallPos(); - currentThread.handle(f, ln, callPos, pc, scope, scopeDepth(scope)); + currentThread.handle(i);//.f, ln, callPos, i.pc, i.scope, scopeDepth(i.scope)); } @@ -214,6 +189,7 @@ public Boolean restart() { if(!(msg.isStatus(STATUS_STOPPED))) return Boolean.FALSE; + msg.setStatus(STATUS_RESTARTING); stopInMain = true; synchronized (MAIN_THREAD_LOCK) { MAIN_THREAD_LOCK.notify(); @@ -251,4 +227,5 @@ //broken = true; currentThread.breakMode = STEPPING_INTO; } + } Modified: core/trunk/org.vexi.debug/src/org/ibex/js/ThreadInfo.java =================================================================== --- core/trunk/org.vexi.debug/src/org/ibex/js/ThreadInfo.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/ibex/js/ThreadInfo.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -9,18 +9,164 @@ import java.util.Map; import java.util.Vector; +import org.ibex.util.Log; import org.vexi.debug.SourceManager; import org.vexi.debug.MessagePasser.IMessagePart; -class CallInfo{ - CallInfo(String srcName, int ln, Scope scope) { - this.srcName = srcName; +class CallStack{ + static class InterpreterInfo{ + InterpreterInfo(InterpreterInfo parent, Interpreter preter){ + this.parent = parent; + this.basepos = parent==null?0:parent.basepos+parent.callpos()+1; + this.preter = preter; + //base = new CallInfo(preter); + } + LinkedList callStack = new LinkedList(); + InterpreterInfo parent; + int basepos; + //CallInfo baseScope; + Interpreter preter; + + InterpreterInfo get(Interpreter i){ + InterpreterInfo info = this; + while(info!=null){ + if(info.preter == i) return info; + info = info.parent; + } + return null; + } + + int handle(Position prevPos, Scope prevScope){ + // We do not count the first (entering file) + int count = preter.stack.callCount() -1; + int size = callStack.size(); + if(count>size){ + callStack.push(new CallInfo(prevPos,prevScope)); + }else if(count==size){ + + }else{ + while(count<size){ + callStack.pop(); + size--; + } + } + return basepos + count; + } + + int callpos(){ + return basepos + preter.stack.callCount(); + } + + public void addToMessage(Vector v) { + Iterator I = callStack.iterator(); + while(I.hasNext()){ + CallInfo ci = (CallInfo)I.next(); + v.add(ci.message()); + } + //v.add(base.message()); + } + + public Scope getScope(int callStackPos) { + int relPos = callStackPos - basepos; + if(relPos<0) return parent.getScope(callStackPos); + else{ + if(relPos >= callStack.size()){ + if(relPos > callStack.size()) + Log.warn(getClass(), "Scope position bigger than callstack"); + // Return interpreter's current scope + return preter.scope; + }else{ + return ((CallInfo)callStack.get(relPos)).scope; + } + + } + } + } + + + static class CallInfo{ + CallInfo(Position pos, Scope s){ + this(pos.f.sourceName, pos.ln, s); + } + private CallInfo(String srcName, int ln, Scope scope) { + this.srcName = srcName; + this.ln = ln; + this.scope = scope; + } + + Hashtable message(){ + Hashtable h = new Hashtable(); + h.put("srcName", srcName); + h.put("ln", new Integer(ln)); + return h; + } + + String srcName; + int ln; + Scope scope; + + public String toString() { + return srcName + ":" + ln; + } + + } + + + int nInterpreters = 0; + InterpreterInfo preterStack = null; + + int handle(Interpreter i, Position prevPos, Scope prevScope){ + if(preterStack==null){ + preterStack = new InterpreterInfo(null,i); + return 0; + }else{ + InterpreterInfo corresponding = preterStack.get(i); + if(corresponding==null){ + preterStack = new InterpreterInfo(preterStack, i); + return preterStack.basepos; + }else{ + // Possibly drop interpreterInfo (if returning from + // or moving up the stack due to an exception) + preterStack = corresponding; + return preterStack.handle(prevPos,prevScope); + } + } + } + + Vector message(){ + Vector v = new Vector(); + InterpreterInfo ii = preterStack; + while(ii!=null){ + ii.addToMessage(v); + ii = ii.parent; + } + + + + return v; + } + public Scope getScope(int callStackPos) { + return preterStack.getScope(callStackPos); + } + +} + + + +class Position{ + final static Position NOWHERE = new Position(new JSFunction("",-1,null),-1,-1); + Position(JSFunction f, int ln, int callpos) { + this.f = f; this.ln = ln; - this.scope = scope; + this.callpos = callpos; } - String srcName; + + boolean sameLine(Position p){ + return ln==p.ln && f==p.f; + } + JSFunction f; int ln; - Scope scope; + int callpos; } public class ThreadInfo implements IMessagePart, org.vexi.debug.Constants, ByteCodes{ @@ -96,7 +242,7 @@ // CONTEXT /////////////////////////////////////////////////////////// - LinkedList callStack = new LinkedList(); + CallStack callStack = new CallStack(); int breakMode; @@ -105,29 +251,31 @@ private int sd = -1; // current scope depth private String line; // current line Scope scope; - private int ln = -1; // current line number + Position pos = Position.NOWHERE; + /*private int ln = -1; // current line number JSFunction f; - private int callPos = -1; + private int callPos = -1;*/ // State when it was last halted. - private int lastHalt_ln; - private JSFunction lastHalt_f; - private int lastHalt_callPos; + Position lastHaltPos = Position.NOWHERE; - + public boolean haltable(){ + if(line.trim().length()==0) + return false; + return true; + } + public boolean doWeHalt(){ // Still on the same line -> continue - if(lastHalt_ln == ln) + if(lastHaltPos.sameLine(pos)) return false; - if(line.trim().length()==0) - return false; - + // Do not halt on certain byte codes - int op = this.f.op[this.pc]; + int op = this.pos.f.op[this.pc]; if(op == OLDSCOPE || op == NEWSCOPE) return false; - if(DebugHandler.breakpoints.isBreakPoint(f.sourceName, ln)) + if(DebugHandler.breakpoints.isBreakPoint(pos.f.sourceName, pos.ln)) return true; @@ -140,48 +288,42 @@ return false; - if(f == lastHalt_f){ + if(pos.f == lastHaltPos.f){ return (breakMode==STEPPING_OVER || breakMode==STEPPING_INTO); }else{ //Handle function change - if(callPos > lastHalt_callPos) // New function + if(pos.callpos > lastHaltPos.callpos) // New function return breakMode==STEPPING_INTO; return true; } } - public void handle(JSFunction f, int ln, int callPos, int pc, Scope scope, int sd) { + public void handle(Interpreter i){ + JSFunction f = i.f; + int ln = f.line[i.pc]; + int pc = i.pc; + Scope scope = i.scope; + int sd = DebugHandler.scopeDepth(scope); + + this.line = SourceManager.getSourceLine(f.sourceName,ln); + + if(!haltable())return; // still required? - if(ln==-1) lastHalt_ln = -1; + //if(ln==-1) lastHalt_ln = -1; /// CALL STUFF - if(callPos > this.callPos && this.f != null) - callStack.addLast(new CallInfo(this.f.sourceName,this.f.line[this.pc], this.scope)); - /*if(callStack.size()>0) - callStack.addLast(new CallInfo(this.f.sourceName,this.f.line[this.pc])); - else - currentThread.callStack.addLast(new CallInfo(srcName,ln));*/ - else if(callPos< this.callPos) - callStack.removeLast(); + int callpos = callStack.handle(i, this.pos, this.scope); /// Update State - this.line = SourceManager.getSourceLine(f.sourceName,ln); - this.f = f; this.scope = scope; this.pc = pc; - this.ln = ln; this.sd = sd; - this.callPos = callPos; + this.pos = new Position(f,ln,callpos); - - - - //System.out.println("line " + ln); if(doWeHalt()){ - lastHalt_ln = ln; - lastHalt_f = f; - lastHalt_callPos = callPos; + doWeHalt(); + lastHaltPos = this.pos; // FEATURE - send vars corresponding to vars in currently selected // view in debugger DebugHandler.msg.halt(this, new ScopeInfoManager.VarMessage(scope)); @@ -199,25 +341,17 @@ Hashtable r = new Hashtable(); r.put("name", t.description()); r.put("id", new Integer(id)); - if(lastHalt_f!=null){ - r.put("srcName", lastHalt_f.sourceName); - r.put("ln", new Integer(lastHalt_ln)); + if(lastHaltPos!=Position.NOWHERE){ + r.put("srcName", lastHaltPos.f.sourceName); + r.put("ln", new Integer(lastHaltPos.ln)); } - Vector v = new Vector(); - Iterator I = callStack.iterator(); - while(I.hasNext()){ - CallInfo ci = (CallInfo)I.next(); + Vector v = callStack.message(); + if(lastHaltPos!=Position.NOWHERE){ Hashtable h = new Hashtable(); - h.put("srcName", ci.srcName); - h.put("ln", new Integer(ci.ln)); + h.put("srcName", lastHaltPos.f.sourceName); + h.put("ln", new Integer(lastHaltPos.ln)); v.add(h); } - if(lastHalt_f!=null){ - Hashtable h = new Hashtable(); - h.put("srcName", lastHalt_f.sourceName); - h.put("ln", new Integer(lastHalt_ln)); - v.add(h); - } r.put("callStack", v); return r; } @@ -227,11 +361,7 @@ } public Scope getScope(int callStackPos) { - if(callStackPos >= callStack.size()){ - return scope; - } - return ((CallInfo)callStack.get(callStackPos)).scope; + return callStack.getScope(callStackPos); } - } Modified: core/trunk/org.vexi.debug/src/org/vexi/debug/Constants.java =================================================================== --- core/trunk/org.vexi.debug/src/org/vexi/debug/Constants.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/vexi/debug/Constants.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -16,7 +16,9 @@ final static public String STATUS_HALTED = "halted"; final static public String STATUS_RUNNING = "running"; final static public String STATUS_STOPPED = "stopped"; + final static public String STATUS_RESTARTING = "restarting"; + // public void start(); //final static public int SUSPENDING = 2; final static public int STEPPING_INTO = 1; Modified: core/trunk/org.vexi.debug/src/org/vexi/debug/DebugServer.java =================================================================== --- core/trunk/org.vexi.debug/src/org/vexi/debug/DebugServer.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/vexi/debug/DebugServer.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,8 +1,6 @@ package org.vexi.debug; import java.io.IOException; -import java.util.Collection; -import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedList; import java.util.Vector; Modified: core/trunk/org.vexi.debug/src/org/vexi/debug/MessagePasser.java =================================================================== --- core/trunk/org.vexi.debug/src/org/vexi/debug/MessagePasser.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/vexi/debug/MessagePasser.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -100,7 +100,7 @@ return message; } - void setStatus(String status){ + public void setStatus(String status){ Log.info(MessagePasser.class, "Status: " + status); this.status = status; } Modified: core/trunk/org.vexi.debug/src/org/vexi/devl/Main.java =================================================================== --- core/trunk/org.vexi.debug/src/org/vexi/devl/Main.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src/org/vexi/devl/Main.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -108,11 +108,11 @@ " set some initial breakpoints"; private static void printUsage() { - System.err.println("Usage: vexi [options] [ url | file | directory ]"); - System.err.println(""); - System.err.println(org.vexi.core.Main.CORE_OPTIONS); - System.err.println(""); - System.err.println(DEBUG_OPTIONS); + Log.uInfo(Main.class, "Usage: vexi [options] [ url | file | directory ]"); + Log.uInfo(Main.class, ""); + Log.uInfo(Main.class, org.vexi.core.Main.CORE_OPTIONS); + Log.uInfo(Main.class, ""); + Log.uInfo(Main.class, DEBUG_OPTIONS); Runtime.getRuntime().exit(-1); } Deleted: core/trunk/org.vexi.debug/src_junit/test/debug/AbstractDebuggerTests.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/AbstractDebuggerTests.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src_junit/test/debug/AbstractDebuggerTests.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,330 +0,0 @@ -package test.debug; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.Vector; - -import junit.framework.TestCase; - -import org.apache.xmlrpc.XmlRpcClient; -import org.apache.xmlrpc.XmlRpcException; -import org.vexi.debug.Constants; -import org.vexi.debug.StreamGobbler; - -import test.js.JSTestSuite; - - - -public abstract class AbstractDebuggerTests extends TestCase implements Constants { - - XmlRpcClient xmlrpc; - Debugee debugee; - protected TestClient tc; - String mainTemplate; - - protected AbstractDebuggerTests(){ - this("main"); - } - - protected AbstractDebuggerTests(String mainTemplate){ - this.mainTemplate = mainTemplate; - } - - - Object execXmlrpc(String method) throws XmlRpcException, IOException{ - return execXmlrpc(method, new Vector()); - } - - Object execXmlrpc(String method, Vector args) throws XmlRpcException, IOException{ - Object response = xmlrpc.execute(HANDLER + "." + method, args); - if(response instanceof XmlRpcException){ - throw (XmlRpcException)response; - } - return response; - } - - protected class TestClient implements Runnable{ - private int stateCounter = -1; - private int lastStateCounter = -1; - private String status=""; - - private Hashtable currentThread; - private Vector sleepingThreads; - private Vector scheduledThreads; - private Vector vars; - private Thread t; - private boolean killed =false; - - public TestClient() { - start(); - } - - private void start(){ - t=new Thread(this); - t.start(); - } - - - - - ////////////// - // Remote methods. - /////////////// - public void killDebugee(){ - killed = true; - t.interrupt(); - try{ - execXmlrpc("suicide"); - }catch(Exception e){ - // ignore, call cannot complete as - // xmlserver was killed before it could respond - } - } - - public void stepOver() throws XmlRpcException, IOException{ - Object response = execXmlrpc("stepOver"); - assertEquals(Boolean.TRUE,response); - } - - public void resume() throws XmlRpcException, IOException{ - Object response = execXmlrpc("resume"); - assertEquals(Boolean.TRUE,response); - } - - public void restart() throws XmlRpcException, IOException{ - start(); - Object response = execXmlrpc("restart"); - assertEquals(Boolean.TRUE,response); - } - - public void setBreakPoint(String filename, int ln) throws XmlRpcException, IOException { - Vector args = new Vector(); - args.add(filename); - args.add(new Integer(ln)); - Object response = execXmlrpc("addBreakPoint", args); - assertEquals(Boolean.TRUE,response); - } - - //////// - // Wait for - //// - public void waitForHalt() throws XmlRpcException, IOException, InterruptedException{ - waitFor(); - assertEquals(STATUS_HALTED,status); - } - - public void waitForStop() throws XmlRpcException, IOException, InterruptedException{ - waitFor(); - assertEquals(STATUS_STOPPED,status); - } - - private void waitFor() throws XmlRpcException, IOException, InterruptedException{ - while(!isSynchronized()){ - Thread.sleep(100); - } - lastStateCounter = stateCounter; - } - - //////////// - // State synchronization - /// - synchronized private void update(Integer stateCounter, String status, Hashtable currentThread, Vector scheduledThreads, Vector sleepingThreads, Vector vars){ - this.stateCounter = stateCounter.intValue(); - this.status = status; - if(currentThread!=null) this.currentThread = currentThread; - if(sleepingThreads!=null) this.sleepingThreads = sleepingThreads; - if(scheduledThreads!=null) this.scheduledThreads = scheduledThreads; - - this.vars = vars; - } - - private boolean isSynchronized() throws XmlRpcException, IOException{ - Hashtable r = (Hashtable) execXmlrpc("getStatusAndState"); - String status = (String)r.get("status"); - Integer stateCounter = (Integer)r.get("stateCounter"); - return (STATUS_HALTED.equals(status) || STATUS_STOPPED.equals(status)) && - stateCounter.intValue() == this.stateCounter && - this.stateCounter!=lastStateCounter; // make sure were not in the previous halted state - } - - public void run() { - - while(true){ - try{ - Vector args = new Vector(); - args.add(new Integer(stateCounter)); - Object response = execXmlrpc("getState",args); - Map message = (Map)response; - System.out.println(response); - System.out.println("vars " + message.get("vars")); - update((Integer) message.get("stateCounter"), - (String) message.get("status"), - (Hashtable) message.get("currentThread"), - (Vector) message.get("scheduledThreads"), - (Vector) message.get("sleepingThreads"), - (Vector) message.get("vars")); - if(STATUS_STOPPED.equals(this.status)) - break; - }catch(Exception e){ - if(killed) break; - e.printStackTrace(); - try { - Thread.sleep(300); - } catch (InterruptedException e1) { - if(killed) break; - e1.printStackTrace(); - } - } - } - } - - - /////////// - // Assertions - ////// - synchronized public void assertPosition(String srcName, int line){ - assertEquals(new Integer(line),currentThread.get("ln")); - assertEquals(srcName,currentThread.get("srcName")); - } - - synchronized public void assertCurrentThread(String threadName){ - assertEquals(threadName,currentThread.get("name")); - } - - synchronized public void assertCallStack(String[] strings){ - Vector v = (Vector)currentThread.get("callStack"); - System.err.println(v); - assertEquals(strings.length, v.size()); - for(int i=0; i<strings.length;i++){ - int divider = strings[i].indexOf(':'); - String srcName = strings[i].substring(0,divider); - int ln = Integer.parseInt(strings[i].substring(divider+1)); - - Hashtable call = (Hashtable) v.get(i); - - assertEquals(srcName, call.get("srcName")); - assertEquals(ln, ((Integer)call.get("ln")).intValue()); - - } - - } - - synchronized public void assertScheduledThreads(String[] threadNames){ - for(int i=0; i<threadNames.length; i++){ - assertContains(scheduledThreads, threadNames[i]); - } - } - - private boolean assertContains(Vector threads, String threadName){ - for(int i=0; i<threads.size(); i++){ - Hashtable t = (Hashtable) threads.get(i); - if(threadName.equals(t.get("name"))) - return true; - } - return false; - } - - public VarInfo getVarInfo() { - return new VarInfo(vars); - } - - public VarInfo getVarInfo(int callStackPos) throws XmlRpcException, IOException { - Vector args = new Vector(); - args.add((Integer)currentThread.get("id")); - args.add(new Integer(callStackPos)); - Object r = execXmlrpc("getVarInfo", args ); - return new VarInfo((Vector) r); - } - - - } - - public static class VarInfo{ - - Vector vars; - public VarInfo(Vector vars){ - this.vars = vars; - } - - public void assertVar(String name, Object val) { - - assertVar(name, val, VARTYPE_PRIMITIVE); - } - public void assertVar(String name, Object val, String type) { - for(int i=0; i<vars.size(); i++){ - Hashtable var = (Hashtable) vars.get(i); - if(var.get("name").equals(name)){ - Object valSent = var.get("value"); - Object typeSent = var.get("type"); - if(VARTYPE_PRIMITIVE.equals(type)){ - if(val == null){ - assertEquals(typeSent, VARTYPE_NULL); - return; - } - else - assertEquals(val, valSent); - } - assertEquals(type, typeSent); - return; - } - } - fail(); - } - - public void assertNoVar(String name) { - for(int i=0; i<vars.size(); i++){ - Hashtable var = (Hashtable) vars.get(i); - if(var.get("name").equals(name)){ - fail(); - } - } - } - } - - - protected void setUp() throws Exception { - debugee = new Debugee(mainTemplate, this.getClass()); - debugee.launch(); - super.setUp(); - setUpClient(); - } - - protected void setUpClient() throws MalformedURLException{ - xmlrpc = new XmlRpcClient("http://localhost:" + DEFAULT_PORT); - - System.out.println("Wait for debug server to come up"); - while(true){ - try{ - Thread.sleep(300); - Object o = execXmlrpc("getVersion"); - System.out.println("Server up. Protocol version: " + o); - break; - }catch(Exception e){ - continue; - } - } - - tc = new TestClient(); - } - - protected void tearDown() throws Exception { - super.tearDown(); - // Port is blocked otherwise. When running (in eclipse at least) the - // child process does not get killed. - - // REMARK - killing the debugees process does not always seem to work - //debugee.kill(); - - // So kill with XmlrpcCall - tc.killDebugee(); - } - /* - public String getName() { - return JSTestSuite.nameFromClass(getClass()); - }*/ -} - Modified: core/trunk/org.vexi.debug/src_junit/test/debug/Debugee.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/Debugee.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src_junit/test/debug/Debugee.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -7,6 +7,8 @@ import org.vexi.debug.StreamGobbler; public class Debugee { + static Object lock = new Object(); + Process proc; String mainTemplate; Class resourceLocator; @@ -20,18 +22,47 @@ //URL url = AbstractDebuggerTests.this.getClass().getResource("."); URL url = resourceLocator.getResource("."); - File workingDir = new File(url.getPath()); - String[] command = + final File workingDir = new File(url.getPath()); + final String[] command = new String[]{"java","-cp", System.getProperty("java.class.path"), "org.vexi.devl.Main","-db","-dbclient=NONE",".",mainTemplate}; + + synchronized (lock) { + try{ + proc = Runtime.getRuntime().exec(command, null, workingDir); - proc = Runtime.getRuntime().exec(command, null, workingDir); - - StreamGobbler sgOut = new StreamGobbler(proc.getInputStream(),"DEBUGGEE OUT"); - StreamGobbler sgErr = new StreamGobbler(proc.getErrorStream(),"DEBUGGEE ERR"); - - sgOut.start(); - sgErr.start(); + StreamGobbler sgOut = new StreamGobbler(proc.getInputStream(),"DEBUGGEE OUT"); + StreamGobbler sgErr = new StreamGobbler(proc.getErrorStream(),"DEBUGGEE ERR"); + + sgOut.start(); + sgErr.start(); + }catch (Exception e) { + e.printStackTrace(); + } + } /* + new Thread("Lock thread"){ + public void run() { + synchronized (lock) { + + boolean finish = false; + while( !finish ){ + try{ + //proc.exitValue(); + finish = true; + } catch(IllegalThreadStateException e){ + try { + Thread.sleep(100); + } catch (InterruptedException e2) {} + } + } + lock.notifyAll(); + } + + } + }.start();*/ + + + } Copied: core/trunk/org.vexi.debug/src_junit/test/debug/DebuggerTest.java (from rev 1691, core/trunk/org.vexi.debug/src_junit/test/debug/AbstractDebuggerTests.java) =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/DebuggerTest.java (rev 0) +++ core/trunk/org.vexi.debug/src_junit/test/debug/DebuggerTest.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -0,0 +1,370 @@ +package test.debug; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import junit.framework.ComparisonFailure; +import junit.framework.TestCase; + +import org.apache.xmlrpc.XmlRpcClient; +import org.apache.xmlrpc.XmlRpcException; +import org.ibex.util.Log; +import org.vexi.debug.Constants; +import org.vexi.debug.StreamGobbler; + +import test.js.JSTestSuite; + + + +public abstract class DebuggerTest extends TestCase implements Constants { + + XmlRpcClient xmlrpc; + Debugee debugee; + protected TestClient tc; + String mainTemplate; + + protected DebuggerTest(){ + this("main"); + } + + protected DebuggerTest(String mainTemplate){ + this.mainTemplate = mainTemplate; + } + + + Object execXmlrpc(String method) throws XmlRpcException, IOException{ + return execXmlrpc(method, new Vector()); + } + + Object execXmlrpc(String method, Vector args) throws XmlRpcException, IOException{ + Object response = xmlrpc.execute(HANDLER + "." + method, args); + if(response instanceof XmlRpcException){ + throw (XmlRpcException)response; + } + return response; + } + + protected class TestClient implements Runnable{ + private int stateCounter = -1; + private int lastStateCounter = -1; + private String status=""; + + private Hashtable currentThread; + private Vector sleepingThreads; + private Vector scheduledThreads; + private Vector vars; + private Thread t; + private boolean killed =false; + + public TestClient() { + start(); + } + + private void start(){ + t=new Thread(this); + t.start(); + } + + + + + ////////////// + // Remote methods. + /////////////// + public void killDebugee(){ + killed = true; + t.interrupt(); + try{ + execXmlrpc("suicide"); + }catch(Exception e){ + // ignore, call cannot complete as + // xmlserver was killed before it could respond + } + } + + public void stepOver() throws XmlRpcException, IOException{ + Object response = execXmlrpc("stepOver"); + assertEquals(Boolean.TRUE,response); + } + + public void resume() throws XmlRpcException, IOException{ + Object response = execXmlrpc("resume"); + assertEquals(Boolean.TRUE,response); + } + + public void restart() throws XmlRpcException, IOException{ + start(); + Object response = execXmlrpc("restart"); + assertEquals(Boolean.TRUE,response); + } + + public void setBreakPoint(String filename, int ln) throws XmlRpcException, IOException { + Vector args = new Vector(); + args.add(filename); + args.add(new Integer(ln)); + Object response = execXmlrpc("addBreakPoint", args); + assertEquals(Boolean.TRUE,response); + } + + //////// + // Wait for + //// + public void waitForHalt() throws XmlRpcException, IOException, InterruptedException{ + waitFor(STATUS_HALTED); + assertEquals(STATUS_HALTED,status); + } + + public void waitForStop() throws XmlRpcException, IOException, InterruptedException{ + waitFor(); + assertEquals(STATUS_STOPPED,status); + } + + private void waitFor(String status) throws XmlRpcException, IOException, InterruptedException{ + do{ + while(!isSynchronized(status)){ + Thread.sleep(100); + } + lastStateCounter = stateCounter; + }while(status!=null && !status.equals(this.status)); + //System.out.println("stateCounter: " + stateCounter); + } + + private void waitFor() throws XmlRpcException, IOException, InterruptedException{ + waitFor(null); + } + + //////////// + // State synchronization + /// + synchronized private void update(Integer stateCounter, String status, Hashtable currentThread, Vector scheduledThreads, Vector sleepingThreads, Vector vars){ + this.stateCounter = stateCounter.intValue(); + this.status = status; + if(currentThread!=null) this.currentThread = currentThread; + if(sleepingThreads!=null) this.sleepingThreads = sleepingThreads; + if(scheduledThreads!=null) this.scheduledThreads = scheduledThreads; + + this.vars = vars; + } + + private boolean isSynchronized(String syncStatus) throws XmlRpcException, IOException{ + Hashtable r = (Hashtable) execXmlrpc("getStatusAndState"); + String status = (String)r.get("status"); + Integer stateCounter = (Integer)r.get("stateCounter"); + //boolean correctStatus = (syncStatus==null&&(STATUS_HALTED.equals(status) || STATUS_STOPPED.equals(status))) + // || (syncStatus!=null&&syncStatus.equals(status)); + return (STATUS_HALTED.equals(status) || STATUS_STOPPED.equals(status)) && + stateCounter.intValue() >= this.stateCounter && + this.stateCounter!=lastStateCounter; // make sure were not in the previous halted state + } + + public void run() { + + while(true){ + try{ + Vector args = new Vector(); + args.add(new Integer(stateCounter)); + Object response = execXmlrpc("getState",args); + Map message = (Map)response; + //System.out.println(response); + //System.out.println("vars " + message.get("vars")); + update((Integer) message.get("stateCounter"), + (String) message.get("status"), + (Hashtable) message.get("currentThread"), + (Vector) message.get("scheduledThreads"), + (Vector) message.get("sleepingThreads"), + (Vector) message.get("vars")); + if(STATUS_STOPPED.equals(this.status)) + break; + }catch(Exception e){ + if(killed) break; + e.printStackTrace(); + try { + Thread.sleep(300); + } catch (InterruptedException e1) { + if(killed) break; + e1.printStackTrace(); + } + } + } + } + + + /////////// + // Assertions + ////// + synchronized public void assertPosition(String srcName, int line){ + assertEquals(srcName,currentThread.get("srcName")); + assertEquals(new Integer(line),currentThread.get("ln")); + } + + synchronized public void assertCurrentThread(String threadName){ + assertEquals(threadName,currentThread.get("name")); + } + + synchronized public void assertCallStack(String[] strings){ + Vector v = (Vector)currentThread.get("callStack"); + //System.err.println(v); + String a = "", b = ""; + for(int i=0; i<strings.length;i++){a += strings[i] + ",";} + for(int i=0; i<v.size();i++){ + Hashtable call = (Hashtable) v.get(i); + b+=call.get("srcName")+":"+call.get("ln")+","; + } + try{ + assertEquals(a,b); + }catch(ComparisonFailure e){ + Log.uError(DebuggerTest.class, "exp: <"+a +">"); + Log.uError(DebuggerTest.class, "act: <"+b +">"); + throw e; + } + /* + assertEquals(strings.length, v.size()); + for(int i=0; i<strings.length;i++){ + int divider = strings[i].indexOf(':'); + String srcName = strings[i].substring(0,divider); + int ln = Integer.parseInt(strings[i].substring(divider+1)); + + Hashtable call = (Hashtable) v.get(i); + + assertEquals(srcName, call.get("srcName")); + assertEquals(ln, ((Integer)call.get("ln")).intValue()); + + }*/ + + } + + synchronized public void assertScheduledThreads(String[] threadNames){ + for(int i=0; i<threadNames.length; i++){ + assertContains(scheduledThreads, threadNames[i]); + } + } + + private boolean assertContains(Vector threads, String threadName){ + for(int i=0; i<threads.size(); i++){ + Hashtable t = (Hashtable) threads.get(i); + if(threadName.equals(t.get("name"))) + return true; + } + return false; + } + + public VarInfo getVarInfo() { + return new VarInfo(vars); + } + + public VarInfo getVarInfo(int callStackPos) throws XmlRpcException, IOException { + Vector args = new Vector(); + args.add((Integer)currentThread.get("id")); + args.add(new Integer(callStackPos)); + Object r = execXmlrpc("getVarInfo", args ); + return new VarInfo((Vector) r); + } + + + } + + public static class VarInfo{ + + Vector vars; + public VarInfo(Vector vars){ + this.vars = vars; + } + + public void assertVar(String name, Object val) { + + assertVar(name, val, VARTYPE_PRIMITIVE); + } + public void assertVar(String name, Object val, String type) { + for(int i=0; i<vars.size(); i++){ + Hashtable var = (Hashtable) vars.get(i); + if(var.get("name").equals(name)){ + Object valSent = var.get("value"); + Object typeSent = var.get("type"); + if(VARTYPE_PRIMITIVE.equals(type)){ + if(val == null){ + assertEquals(typeSent, VARTYPE_NULL); + return; + } + else + assertEquals(val, valSent); + } + assertEquals(type, typeSent); + return; + } + } + fail(); + } + + public void assertNoVar(String name) { + for(int i=0; i<vars.size(); i++){ + Hashtable var = (Hashtable) vars.get(i); + if(var.get("name").equals(name)){ + fail(); + } + } + } + } + + + protected void setUp() throws Exception { + Log.uError("---------------", "---------------- " + this.getName() + "-----------------"); + + killPrevious(); + debugee = new Debugee(mainTemplate, this.getClass()); + debugee.launch(); + super.setUp(); + setUpClient(); + } + protected void killPrevious() throws MalformedURLException{ + try{ + xmlrpc = new XmlRpcClient("http://localhost:" + DEFAULT_PORT); + while(true){ + execXmlrpc("getVersion"); + Log.uInfo(DebuggerTest.class,"Previous debuggee process has not finished, killing it"); + execXmlrpc("suicide"); + } + + }catch(Exception e){ + // Expected + } + } + + protected void setUpClient() throws MalformedURLException{ + xmlrpc = new XmlRpcClient("http://localhost:" + DEFAULT_PORT); + + Log.uInfo(DebuggerTest.class,"Wait for debug server to come up"); + while(true){ + try{ + Thread.sleep(300); + Object o = execXmlrpc("getVersion"); + Log.uInfo(DebuggerTest.class,"Server up. Protocol version: " + o); + break; + }catch(Exception e){ + continue; + } + } + + tc = new TestClient(); + } + + protected void tearDown() throws Exception { + // Port is blocked otherwise. When running (in eclipse at least) the + // child process does not get killed. + + // REMARK - killing the debugees process does not always seem to work + //debugee.kill(); + + // So kill with XmlrpcCall + tc.killDebugee(); + } + /* + public String getName() { + return JSTestSuite.nameFromClass(getClass()); + }*/ +} + Modified: core/trunk/org.vexi.debug/src_junit/test/debug/simple/TestSimple.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/simple/TestSimple.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src_junit/test/debug/simple/TestSimple.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,8 +1,8 @@ package test.debug.simple; -import test.debug.AbstractDebuggerTests; +import test.debug.DebuggerTest; -public class TestSimple extends AbstractDebuggerTests { +public class TestSimple extends DebuggerTest { public TestSimple() { super(); @@ -13,9 +13,13 @@ public static void main(String[] args) throws Exception { TestSimple t = new TestSimple(); //t.setUp(); + t.killPrevious(); t.setUpClient(); - t.testRestart(); - t.tearDown(); + try{ + t.testRestart(); + }finally{ + t.tearDown(); + } } /////////// @@ -24,6 +28,7 @@ public void testStepOver() throws Exception{ tc.waitForHalt(); tc.assertPosition("main", 2); + tc.assertCallStack(new String[]{"main:2"}); tc.stepOver(); tc.waitForHalt(); tc.assertPosition("main", 4); Added: core/trunk/org.vexi.debug/src_junit/test/debug/thread/RunDebugee.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/thread/RunDebugee.java (rev 0) +++ core/trunk/org.vexi.debug/src_junit/test/debug/thread/RunDebugee.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -0,0 +1,16 @@ +package test.debug.thread; + + +public class RunDebugee { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String path = RunDebugee.class.getResource(".").getPath(); + org.vexi.devl.Main.main(new String[]{"-db","-dbclient=NONE",path,"main"}); + + } + +} Modified: core/trunk/org.vexi.debug/src_junit/test/debug/thread/TestThread.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/thread/TestThread.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src_junit/test/debug/thread/TestThread.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,8 +1,8 @@ package test.debug.thread; -import test.debug.AbstractDebuggerTests; +import test.debug.DebuggerTest; -public class TestThread extends AbstractDebuggerTests { +public class TestThread extends DebuggerTest { public TestThread() { super(); @@ -13,7 +13,11 @@ public static void main(String[] args) throws Exception { TestThread t = new TestThread(); t.setUpClient(); - t.testSwitchingThreads(); + try{ + t.testSwitchingThreads(); + }finally{ + t.tearDown(); + } } /////////// Added: core/trunk/org.vexi.debug/src_junit/test/debug/vars/RunDebugee.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/vars/RunDebugee.java (rev 0) +++ core/trunk/org.vexi.debug/src_junit/test/debug/vars/RunDebugee.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -0,0 +1,16 @@ +package test.debug.vars; + + +public class RunDebugee { + + /** + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + String path = RunDebugee.class.getResource(".").getPath(); + org.vexi.devl.Main.main(new String[]{"-db","-dbclient=NONE",path,"main"}); + + } + +} Modified: core/trunk/org.vexi.debug/src_junit/test/debug/vars/TestVars.java =================================================================== --- core/trunk/org.vexi.debug/src_junit/test/debug/vars/TestVars.java 2007-02-21 17:02:49 UTC (rev 1691) +++ core/trunk/org.vexi.debug/src_junit/test/debug/vars/TestVars.java 2007-02-24 18:56:15 UTC (rev 1692) @@ -1,8 +1,8 @@ package test.debug.vars; -import test.debug.AbstractDebuggerTests; +import test.debug.DebuggerTest; -public class TestVars extends AbstractDebuggerTests { +public class TestVars extends DebuggerTest { public TestVars() { super(); @@ -12,8 +12,13 @@ // as a debugable process. public static void main(String[] args) throws Exception { TestVars t = new TestVars(); + t.killPrevious(); t.setUpClient(); - t.testVarsFromPrevious(); + try{ + t.testVarsFromPrevious(); + }finally{ + t.tearDown(); + } } @@ -39,6 +44,15 @@ vi.assertVar("d","d"); } + public void testCallstack() throws Exception{ + tc.waitForHalt(); + tc.setBreakPoint("main", 9); + tc.resume(); + tc.waitForHalt(); + tc.assertCallStack(new String[]{"main:13","main:9"}); + tc.resume(); + } + public void testVars() throws Exception{ tc.waitForHalt(); // This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn