implemented contiki test scripts as threads instead of state machines for easier test development

This commit is contained in:
fros4943 2009-01-08 16:33:14 +00:00
parent fd432fa22c
commit 94f0d8ca02

View file

@ -26,13 +26,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: LogScriptEngine.java,v 1.6 2008/11/27 08:51:35 fros4943 Exp $ * $Id: LogScriptEngine.java,v 1.7 2009/01/08 16:33:14 fros4943 Exp $
*/ */
package se.sics.cooja.plugins; package se.sics.cooja.plugins;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
import java.util.*; import java.util.*;
import java.util.concurrent.Semaphore;
import javax.swing.*; import javax.swing.*;
import javax.script.*; import javax.script.*;
@ -40,13 +41,15 @@ import org.apache.log4j.Logger;
import se.sics.cooja.*; import se.sics.cooja.*;
/** /**
* Executes JavaScripts on mote logs. * Executes Contiki test scripts.
* *
* @see ScriptRunner * @see ScriptRunner
* *
* @author Fredrik Osterlind * @author Fredrik Osterlind
*/ */
public class LogScriptEngine { public class LogScriptEngine {
private static final int DEFAULT_TIMEOUT = 1200000; /* 1200s = 20 minutes */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(LogScriptEngine.class); private static Logger logger = Logger.getLogger(LogScriptEngine.class);
@ -59,23 +62,59 @@ public class LogScriptEngine {
private GUI gui; private GUI gui;
private Observer scriptedLogObserver = null; private Thread scriptThread = null;
private Observer scriptLogObserver = null; private Observer scriptLogObserver = null;
private String scriptCode;
private ScriptMote scriptMote; private ScriptMote scriptMote;
private boolean stopSimulation = false, quitCooja = false;
private Semaphore semaphoreScript = null;
private Semaphore semaphoreSim = null;
private boolean scriptActive = false;
private TimeEvent timeoutEvent = new TimeEvent(0) {
public void execute(long t) {
engine.put("TIMEOUT", true);
stepScript();
}
};
private interface ScriptLog { private interface ScriptLog {
public void log(String log); public void log(String log);
public void testOK(); public void testOK();
public void testFailed(); public void testFailed();
} }
public LogScriptEngine(GUI gui, String code) { private void stepScript() {
/* Release script - halt simulation */
semaphoreScript.release();
/* ... script executing ... */
try {
semaphoreSim.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
/* ... script is now again waiting for script semaphore ... */
/* Check if test script requested us to stop */
if (stopSimulation) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
stopSimulation = false;
}
if (quitCooja) {
LogScriptEngine.this.gui.doQuit(false);
quitCooja = false;
}
}
public LogScriptEngine(GUI gui) {
this.gui = gui; this.gui = gui;
this.scriptCode = code;
/* Create GUI observer: keeps track of new simulations */ /* Create GUI observer: keeps track of new simulations */
guiObserver = new Observer() { guiObserver = new Observer() {
@ -99,9 +138,21 @@ public class LogScriptEngine {
logObserver = new Observer() { logObserver = new Observer() {
public void update(Observable obs, Object obj) { public void update(Observable obs, Object obj) {
try { try {
if (scriptedLogObserver != null) { if (scriptThread == null ||
scriptedLogObserver.update(obs, obj); !scriptThread.isAlive()) {
logger.info("script thread not alive. try deactivating script.");
/*scriptThread.isInterrupted()*/
return;
} }
/* Update script variables */
Mote mote = (Mote) obj;
engine.put("mote", mote);
engine.put("id", mote.getInterfaces().getMoteID().getMoteID());
engine.put("time", mote.getSimulation().getSimulationTime());
stepScript();
} catch (UndeclaredThrowableException e) { } catch (UndeclaredThrowableException e) {
e.printStackTrace(); e.printStackTrace();
JOptionPane.showMessageDialog(GUI.getTopParentContainer(), JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
@ -115,19 +166,6 @@ public class LogScriptEngine {
} }
}; };
/* Create script engine */
try {
createScriptEngine(scriptCode);
} catch (ScriptException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
"See console for more information.",
"Script error", JOptionPane.ERROR_MESSAGE);
if (LogScriptEngine.this.gui.getSimulation() != null) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
}
unregisterLogObserver();
}
} }
public void setScriptLogObserver(Observer observer) { public void setScriptLogObserver(Observer observer) {
@ -158,23 +196,30 @@ public class LogScriptEngine {
} }
} }
/**
* Activate script
*/
public void activateScript() {
gui.addObserver(guiObserver);
if (gui.getSimulation() != null) {
gui.getSimulation().addObserver(simObserver);
}
registerLogObserver();
}
/** /**
* Deactivate script * Deactivate script
*/ */
public void deactiveScript() { public void deactivateScript() {
if (!scriptActive) {
return;
}
scriptActive = false;
if (semaphoreScript == null) {
logger.warn("semaphoreScript is not initialized");
}
if (semaphoreSim == null) {
logger.warn("semaphoreSim is not initialized");
}
if (scriptThread == null) {
logger.warn("scriptThread is not initialized");
}
if (timeoutEvent != null) {
timeoutEvent.remove();
timeoutEvent = null;
}
gui.deleteObserver(guiObserver); gui.deleteObserver(guiObserver);
if (gui.getSimulation() != null) { if (gui.getSimulation() != null) {
@ -182,25 +227,124 @@ public class LogScriptEngine {
} }
unregisterLogObserver(); unregisterLogObserver();
engine.put("SHUTDOWN", true);
try {
semaphoreScript.release(100);
} catch (Exception e) {
} finally {
semaphoreScript = null;
}
try {
semaphoreSim.release(100);
} catch (Exception e) {
} finally {
semaphoreSim = null;
}
if (scriptThread != null) {
try {
scriptThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
scriptThread = null;
}
}
} }
private void createScriptEngine(String code) throws ScriptException { public void activateScript(String scriptCode) throws ScriptException {
engine.eval("function update(obs, obj) { " + if (scriptActive) {
"if (obj != null) {" + return;
" mote = obj;" + }
" id = mote.getInterfaces().getMoteID().getMoteID();" + scriptActive = true;
" msg = mote.getInterfaces().getLog().getLastLogMessage();" +
" node.setMoteMsg(mote, msg);" +
"} else {" +
" return;" +
"} " +
code +
" };");
Invocable inv = (Invocable) engine; if (semaphoreScript != null) {
scriptedLogObserver = inv.getInterface(Observer.class); logger.warn("semaphoreScript is already initialized");
}
if (semaphoreSim != null) {
logger.warn("semaphoreSim is already initialized");
}
if (scriptThread != null) {
logger.warn("scriptThread is already initialized");
}
/* Create script logger */ /* Parse current script */
ScriptParser parser = new ScriptParser(scriptCode);
String jsCode = parser.getJSCode();
long timeoutTime = parser.getTimeoutTime();
if (gui.getSimulation() != null) {
if (timeoutTime > 0) {
gui.getSimulation().scheduleEvent(
timeoutEvent,
gui.getSimulation().getSimulationTime() + timeoutTime);
} else {
gui.getSimulation().scheduleEvent(
timeoutEvent,
gui.getSimulation().getSimulationTime() + DEFAULT_TIMEOUT);
}
}
engine.eval(jsCode);
/* Setup script control */
semaphoreScript = new Semaphore(1);
semaphoreSim = new Semaphore(1);
engine.put("TIMEOUT", false);
engine.put("SHUTDOWN", false);
engine.put("SEMAPHORE_SCRIPT", semaphoreScript);
engine.put("SEMAPHORE_SIM", semaphoreSim);
try {
semaphoreScript.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
scriptThread = new Thread(new Runnable() {
public void run() {
/*logger.info("test script thread starts");*/
try {
((Invocable)engine).getInterface(Runnable.class).run();
} catch (RuntimeException e) {
Throwable throwable = e;
while (throwable.getCause() != null) {
throwable = throwable.getCause();
}
if (throwable.getMessage() != null &&
throwable.getMessage().contains("test script killed") ) {
/*logger.info("test script thread terminated by exception");*/
} else {
if (!GUI.isVisualized()) {
logger.fatal("Test script error, terminating Cooja.");
e.printStackTrace();
System.exit(1);
}
/* Forward exception */
throw e;
}
}
/*logger.info("test script thread exits");*/
}
});
scriptThread.start(); /* Starts by acquiring semaphore (blocks) */
while (!semaphoreScript.hasQueuedThreads()) {
Thread.yield();
}
/* Setup simulation observers */
gui.addObserver(guiObserver);
if (gui.getSimulation() != null) {
gui.getSimulation().addObserver(simObserver);
}
/* Create script output logger */
engine.put("log", new ScriptLog() { engine.put("log", new ScriptLog() {
public void log(String msg) { public void log(String msg) {
if (scriptLogObserver != null) { if (scriptLogObserver != null) {
@ -212,24 +356,49 @@ public class LogScriptEngine {
if (GUI.isVisualized()) { if (GUI.isVisualized()) {
log("[if test was run without visualization, COOJA would now have been terminated]\n"); log("[if test was run without visualization, COOJA would now have been terminated]\n");
if (LogScriptEngine.this.gui.getSimulation() != null) { stopSimulation = true;
LogScriptEngine.this.gui.getSimulation().stopSimulation();
}
} else { } else {
gui.doQuit(false); quitCooja = true;
} }
/* Make sure simulation is actually stopped */
gui.getSimulation().scheduleEvent(new TimeEvent(0) {
public void execute(long time) {
if (stopSimulation) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
stopSimulation = false;
}
if (quitCooja) {
LogScriptEngine.this.gui.doQuit(false);
quitCooja = false;
}
}
}, gui.getSimulation().getSimulationTime());
} }
public void testFailed() { public void testFailed() {
log("TEST FAILED\n"); log("TEST FAILED\n");
if (GUI.isVisualized()) { if (GUI.isVisualized()) {
log("[if test was run without visualization, COOJA would now have been terminated]\n"); log("[if test was run without visualization, COOJA would now have been terminated]\n");
if (LogScriptEngine.this.gui.getSimulation() != null) { stopSimulation = true;
LogScriptEngine.this.gui.getSimulation().stopSimulation();
}
} else { } else {
gui.doQuit(false); quitCooja = true;
} }
/* Make sure simulation is actually stopped */
gui.getSimulation().scheduleEvent(new TimeEvent(0) {
public void execute(long time) {
if (stopSimulation) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
stopSimulation = false;
}
if (quitCooja) {
LogScriptEngine.this.gui.doQuit(false);
quitCooja = false;
}
}
}, gui.getSimulation().getSimulationTime());
} }
}); });
@ -239,8 +408,7 @@ public class LogScriptEngine {
scriptMote = new ScriptMote(); scriptMote = new ScriptMote();
engine.put("node", scriptMote); engine.put("node", scriptMote);
/* TODO Test script */ registerLogObserver();
logObserver.update(null, null);
} }
} }