made test editor plugin a simulation plugin: it now depends on a specific simulation

this change enables multiple simultaneous scripts in a simulation, and also makes it easier to create tests since they will be stored with the simulation config

since the plugin now depends on a simulation it is no longer possible to create/reload simulations from the test scripts (this was however not often used)
This commit is contained in:
fros4943 2009-06-09 09:47:04 +00:00
parent 5bac672099
commit 02733e15ab
3 changed files with 473 additions and 766 deletions

View file

@ -24,7 +24,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: GUI.java,v 1.131 2009/06/02 15:04:49 fros4943 Exp $
* $Id: GUI.java,v 1.132 2009/06/09 09:47:04 fros4943 Exp $
*/
package se.sics.cooja;
@ -1026,16 +1026,34 @@ public class GUI extends Observable {
}
private static boolean quickStartSimulationConfig(String source) {
private static Simulation quickStartSimulationConfig(File config, boolean vis) {
logger.info("> Starting COOJA");
JDesktopPane desktop = new JDesktopPane();
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
frame = new JFrame("COOJA Simulator");
if (vis) {
frame = new JFrame("COOJA Simulator");
}
GUI gui = new GUI(desktop);
configureFrame(gui, false);
if (vis) {
configureFrame(gui, false);
}
gui.doLoadConfig(false, true, new File(source));
return true;
if (vis) {
gui.doLoadConfig(false, true, config);
return gui.getSimulation();
} else {
try {
Simulation newSim = gui.loadSimulationConfig(config, true);
if (newSim == null) {
return null;
}
gui.setSimulation(newSim, false);
return newSim;
} catch (Exception e) {
logger.fatal("Exception when loading simulation: ", e);
return null;
}
}
}
/**
@ -1060,7 +1078,7 @@ public class GUI extends Observable {
logger.fatal("No simulation, aborting quickstart");
System.exit(1);
}
gui.setSimulation(simulation);
gui.setSimulation(simulation, true);
logger.info("> Creating mote type");
ContikiMoteType moteType = new ContikiMoteType();
@ -1840,7 +1858,7 @@ public class GUI extends Observable {
return mySimulation;
}
public void setSimulation(Simulation sim) {
public void setSimulation(Simulation sim, boolean startPlugins) {
if (sim != null) {
doRemoveSimulation(false);
}
@ -1853,7 +1871,7 @@ public class GUI extends Observable {
}
// Open standard plugins (if none opened already)
if (startedPlugins.size() == 0) {
if (startPlugins) {
for (Class<? extends Plugin> pluginClass : pluginClasses) {
int pluginType = pluginClass.getAnnotation(PluginType.class).value();
if (pluginType == PluginType.SIM_STANDARD_PLUGIN) {
@ -2128,7 +2146,7 @@ public class GUI extends Observable {
shouldRetry = false;
myGUI.doRemoveSimulation(false);
newSim = loadSimulationConfig(fileToLoad, quick);
myGUI.setSimulation(newSim);
myGUI.setSimulation(newSim, false);
addToFileHistory(fileToLoad);
} catch (UnsatisfiedLinkError e) {
shouldRetry = showErrorDialog(GUI.getTopParentContainer(), "Simulation load error", e, true);
@ -2178,7 +2196,7 @@ public class GUI extends Observable {
shouldRetry = false;
myGUI.doRemoveSimulation(false);
Simulation newSim = loadSimulationConfig(root, true);
myGUI.setSimulation(newSim);
myGUI.setSimulation(newSim, false);
myGUI.getSimulation().setRandomSeed(randomSeed);
if (autoStart) {
@ -2257,59 +2275,62 @@ public class GUI extends Observable {
* @param askForConfirmation
* Ask for confirmation before overwriting file
*/
public void doSaveConfig(boolean askForConfirmation) {
public File doSaveConfig(boolean askForConfirmation) {
if (isVisualizedInApplet()) {
return;
return null;
}
if (mySimulation != null) {
mySimulation.stopSimulation();
if (mySimulation == null) {
return null;
}
JFileChooser fc = new JFileChooser();
mySimulation.stopSimulation();
fc.setFileFilter(GUI.SAVED_SIMULATIONS_FILES);
JFileChooser fc = new JFileChooser();
// Suggest file using history
File suggestedFile = getLastOpenedFile();
if (suggestedFile != null) {
fc.setSelectedFile(suggestedFile);
fc.setFileFilter(GUI.SAVED_SIMULATIONS_FILES);
// Suggest file using history
File suggestedFile = getLastOpenedFile();
if (suggestedFile != null) {
fc.setSelectedFile(suggestedFile);
}
int returnVal = fc.showSaveDialog(myDesktopPane);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File saveFile = fc.getSelectedFile();
if (!fc.accept(saveFile)) {
saveFile = new File(saveFile.getParent(), saveFile.getName()
+ SAVED_SIMULATIONS_FILES);
}
int returnVal = fc.showSaveDialog(myDesktopPane);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File saveFile = fc.getSelectedFile();
if (!fc.accept(saveFile)) {
saveFile = new File(saveFile.getParent(), saveFile.getName()
+ SAVED_SIMULATIONS_FILES);
}
if (saveFile.exists()) {
if (askForConfirmation) {
String s1 = "Overwrite";
String s2 = "Cancel";
Object[] options = { s1, s2 };
int n = JOptionPane.showOptionDialog(
GUI.getTopParentContainer(),
"A file with the same name already exists.\nDo you want to remove it?",
"Overwrite existing file?", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, s1);
if (n != JOptionPane.YES_OPTION) {
return;
}
if (saveFile.exists()) {
if (askForConfirmation) {
String s1 = "Overwrite";
String s2 = "Cancel";
Object[] options = { s1, s2 };
int n = JOptionPane.showOptionDialog(
GUI.getTopParentContainer(),
"A file with the same name already exists.\nDo you want to remove it?",
"Overwrite existing file?", JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, options, s1);
if (n != JOptionPane.YES_OPTION) {
return null;
}
}
if (!saveFile.exists() || saveFile.canWrite()) {
saveSimulationConfig(saveFile);
addToFileHistory(saveFile);
} else {
logger.fatal("No write access to file");
}
} else {
logger.info("Save command cancelled by user...");
}
if (!saveFile.exists() || saveFile.canWrite()) {
saveSimulationConfig(saveFile);
addToFileHistory(saveFile);
return saveFile;
} else {
logger.fatal("No write access to file");
}
} else {
logger.info("Save command cancelled by user...");
}
return null;
}
/**
@ -2348,7 +2369,7 @@ public class GUI extends Observable {
Simulation newSim = new Simulation(this);
boolean createdOK = CreateSimDialog.showDialog(GUI.getTopParentContainer(), newSim);
if (createdOK) {
myGUI.setSimulation(newSim);
myGUI.setSimulation(newSim, true);
}
}
@ -2885,7 +2906,7 @@ public class GUI extends Observable {
boolean ok = false;
if (contikiApp.endsWith(".csc")) {
ok = quickStartSimulationConfig(contikiApp);
ok = quickStartSimulationConfig(new File(contikiApp), true) != null;
} else {
if (contikiApp.endsWith(".cooja")) {
@ -2902,67 +2923,44 @@ public class GUI extends Observable {
System.exit(1);
}
} else if (args.length > 0 && args[0].startsWith("-nogui")) {
} else if (args.length > 0 && args[0].startsWith("-nogui=")) {
/* Parse optional script argument */
String tmpTest=null;
for (int i=1; i < args.length; i++) {
if (args[i].startsWith("-test=")) {
tmpTest = args[i].substring("-test=".length());
/* Load simulation */
String config = args[0].substring("-nogui=".length());
final File configFile = new File(config);
Simulation sim = quickStartSimulationConfig(configFile, false);
if (sim == null) {
System.exit(1);
}
GUI gui = sim.getGUI();
/* Make sure at least one test editor is controlling the simulation */
boolean hasEditor = false;
for (Plugin startedPlugin : gui.startedPlugins) {
if (startedPlugin instanceof ScriptRunner) {
hasEditor = true;
break;
}
}
/* Backwards compatibility:
* simulation has no test editor, but has external (old style) test script.
* We will manually start a test editor from here. */
if (!hasEditor) {
File scriptFile = new File(config.substring(0, config.length()-4) + ".js");
if (scriptFile.exists()) {
logger.info("Detected old simulation test, starting test editor manually from: " + scriptFile);
ScriptRunner plugin = (ScriptRunner) gui.startPlugin(ScriptRunner.class, gui, sim, null);
plugin.updateScript(scriptFile);
plugin.setScriptActive(true);
sim.setDelayTime(0);
sim.startSimulation();
} else {
logger.fatal("Unknown argument: " + args[i]);
logger.fatal("No test editor controlling simulation, aborting");
System.exit(1);
}
}
final File scriptFile;
final File configFile;
final File logFile;
if (tmpTest != null) {
/* Locate script and simulation config files */
scriptFile = new File(tmpTest + ".js");
configFile = new File(tmpTest + ".csc");
logFile = new File(tmpTest + ".log");
if (!scriptFile.exists()) {
logger.fatal("Can't locate script: " + scriptFile);
System.exit(1);
}
if (!configFile.exists()) {
logger.fatal("Can't locate simulation config: " + configFile);
System.exit(1);
}
if (logFile.exists()) {
logFile.delete();
}
if (logFile.exists() && !logFile.canWrite()) {
logger.fatal("Can't write to log file: " + logFile);
System.exit(1);
}
} else {
scriptFile = null;
configFile = null;
logFile = null;
}
/* No GUI start-up */
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JDesktopPane desktop = new JDesktopPane();
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
GUI gui = new GUI(desktop);
if (scriptFile != null && configFile != null) {
/* Load and start script plugin (no-GUI version) */
ScriptRunner scriptPlugin =
(ScriptRunner) gui.startPlugin(ScriptRunner.class, gui, null, null);
/* Activate test */
scriptPlugin.activateTest(configFile, scriptFile, logFile);
}
}
});
} else if (args.length > 0 && args[0].startsWith("-applet")) {
String tmpWebPath=null, tmpBuildPath=null, tmpEsbFirmware=null, tmpSkyFirmware=null;
@ -3041,7 +3039,7 @@ public class GUI extends Observable {
logger.fatal("Config not wellformed: " + e.getMessage());
return null;
} catch (IOException e) {
logger.fatal("IOException: " + e.getMessage());
logger.fatal("Load simulation error: " + e.getMessage());
return null;
}
}
@ -3329,6 +3327,7 @@ public class GUI extends Observable {
if (pluginClassName.equals("se.sics.cooja.plugins.VisUDGM") ||
pluginClassName.equals("se.sics.cooja.plugins.VisBattery") ||
pluginClassName.equals("se.sics.cooja.plugins.VisTraffic") ||
pluginClassName.equals("se.sics.cooja.plugins.VisState") ||
pluginClassName.equals("se.sics.cooja.plugins.VisUDGM")) {
logger.warn("Old simulation config detected: visualizers have been remade");
pluginClassName = "se.sics.cooja.plugins.Visualizer";

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* Copyright (c) 2009, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: LogScriptEngine.java,v 1.13 2009/06/03 17:26:31 fros4943 Exp $
* $Id: LogScriptEngine.java,v 1.14 2009/06/09 09:47:04 fros4943 Exp $
*/
package se.sics.cooja.plugins;
@ -34,53 +34,41 @@ package se.sics.cooja.plugins;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.*;
import java.util.concurrent.Semaphore;
import javax.swing.*;
import javax.script.*;
import org.apache.log4j.Logger;
import se.sics.cooja.*;
/**
* Executes Contiki test scripts.
* Loads and executes a Contiki test script.
* A Contiki test script is a Javascript that depends on a single simulation,
* and reacts to mote log output (such as printf()s).
*
* @see ScriptRunner
*
* @author Fredrik Osterlind
*/
public class LogScriptEngine {
private static final long DEFAULT_TIMEOUT = 20*60*1000*1000; /* 1200s = 20 minutes */
private static Logger logger = Logger.getLogger(LogScriptEngine.class);
private static final long DEFAULT_TIMEOUT = 20*60*1000*Simulation.MILLISECOND; /* 1200s = 20 minutes */
private ScriptEngineManager factory = new ScriptEngineManager();
private ScriptEngine engine = factory.getEngineByName("JavaScript");
private ScriptEngine engine =
new ScriptEngineManager().getEngineByName("JavaScript");
private Observer logObserver = null;
private Observer simObserver = null;
private Observer guiObserver = null;
private GUI gui;
private Thread scriptThread = null;
private Observer logObserver = null; /* Detect mote log output */
private Observer simObserver = null; /* Detect added/removed motes */
private Semaphore semaphoreScript = null; /* Semaphores blocking script/simulation */
private Semaphore semaphoreSim = null;
private Thread scriptThread = null; /* Script thread */
private Observer scriptLogObserver = null;
private ScriptMote scriptMote;
private boolean stopSimulation = false, quitCooja = false;
private Semaphore semaphoreScript = null;
private Semaphore semaphoreSim = null;
private Simulation simulation;
private boolean scriptActive = false;
private TimeEvent timeoutEvent = new TimeEvent(0) {
public void execute(long t) {
engine.put("TIMEOUT", true);
stepScript();
}
};
private interface ScriptLog {
public void log(String log);
public void testOK();
@ -88,6 +76,7 @@ public class LogScriptEngine {
public void generateMessage(long delay, String msg);
}
/* Only called from the simulation loop */
private void stepScript() {
/* Release script - halt simulation */
semaphoreScript.release();
@ -104,28 +93,17 @@ public class LogScriptEngine {
/* Check if test script requested us to stop */
if (stopSimulation) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
stopSimulationEvent.execute(0);
stopSimulation = false;
}
if (quitCooja) {
LogScriptEngine.this.gui.doQuit(false);
quitEvent.execute(0);
quitCooja = false;
}
}
public LogScriptEngine(GUI gui) {
this.gui = gui;
/* Create GUI observer: keeps track of new simulations */
guiObserver = new Observer() {
public void update(Observable obs, Object obj) {
if (LogScriptEngine.this.gui.getSimulation() != null) {
LogScriptEngine.this.gui.getSimulation().addObserver(simObserver);
}
registerLogObserver();
}
};
public LogScriptEngine(Simulation simulation) {
this.simulation = simulation;
/* Create simulation observer: keeps track of newly added nodes */
simObserver = new Observer() {
@ -148,11 +126,12 @@ public class LogScriptEngine {
};
}
/* Only called from the simulation loop */
private void handleNewMoteOutput(Mote mote, int id, long time, String msg) {
try {
if (scriptThread == null ||
!scriptThread.isAlive()) {
logger.info("script thread not alive. try deactivating script.");
logger.warn("No script thread, deactivate script.");
/*scriptThread.isInterrupted()*/
return;
}
@ -164,16 +143,15 @@ public class LogScriptEngine {
engine.put("msg", msg);
stepScript();
} catch (UndeclaredThrowableException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
"See console for more information.",
"Script error", JOptionPane.ERROR_MESSAGE);
unregisterLogObserver();
if (LogScriptEngine.this.gui.getSimulation() != null) {
LogScriptEngine.this.gui.getSimulation().stopSimulation();
logger.fatal("Exception: " + e.getMessage(), e);
if (GUI.isVisualized()) {
GUI.showErrorDialog(GUI.getTopParentContainer(),
e.getMessage(),
e, false);
}
unregisterLogObserver();
simulation.stopSimulation();
}
}
@ -185,7 +163,7 @@ public class LogScriptEngine {
* @param mote Mote
*/
public void fakeMoteLogOutput(final String msg, final Mote mote) {
gui.getSimulation().scheduleEvent(new TimeEvent(0) {
simulation.scheduleEvent(new TimeEvent(0) {
public void execute(long time) {
handleNewMoteOutput(
mote,
@ -194,7 +172,7 @@ public class LogScriptEngine {
msg
);
}
}, gui.getSimulation().getSimulationTime());
}, simulation.getSimulationTime());
}
public void setScriptLogObserver(Observer observer) {
@ -203,24 +181,18 @@ public class LogScriptEngine {
private void unregisterLogObserver() {
/* Unregister mote log observer */
if (logObserver != null && gui.getSimulation() != null) {
for (int i=0; i < gui.getSimulation().getMotesCount(); i++) {
Mote mote = gui.getSimulation().getMote(i);
if (mote.getInterfaces().getLog() != null) {
mote.getInterfaces().getLog().deleteObserver(logObserver);
}
for (Mote mote: simulation.getMotes()) {
if (mote.getInterfaces().getLog() != null) {
mote.getInterfaces().getLog().deleteObserver(logObserver);
}
}
}
private void registerLogObserver() {
/* Register mote log observer */
if (logObserver != null && gui.getSimulation() != null) {
for (int i=0; i < gui.getSimulation().getMotesCount(); i++) {
Mote mote = gui.getSimulation().getMote(i);
if (mote.getInterfaces().getLog() != null) {
mote.getInterfaces().getLog().addObserver(logObserver);
}
for (Mote mote: simulation.getMotes()) {
if (mote.getInterfaces().getLog() != null) {
mote.getInterfaces().getLog().addObserver(logObserver);
}
}
}
@ -244,16 +216,9 @@ public class LogScriptEngine {
/*logger.warn("scriptThread is not initialized");*/
}
if (timeoutEvent != null) {
timeoutEvent.remove();
timeoutEvent = null;
}
timeoutEvent.remove();
gui.deleteObserver(guiObserver);
if (gui.getSimulation() != null) {
gui.getSimulation().deleteObserver(simObserver);
}
simulation.deleteObserver(simObserver);
unregisterLogObserver();
@ -272,7 +237,8 @@ public class LogScriptEngine {
semaphoreSim = null;
}
if (scriptThread != null && scriptThread != Thread.currentThread()) {
if (scriptThread != null &&
scriptThread != Thread.currentThread() /* XXX May deadlock */ ) {
try {
scriptThread.join();
} catch (InterruptedException e) {
@ -305,16 +271,16 @@ public class LogScriptEngine {
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);
}
if (timeoutTime > 0) {
simulation.scheduleEvent(
timeoutEvent,
simulation.getSimulationTime() + timeoutTime);
} else {
logger.info("No timeout defined, using default: " +
simulation.getSimulationTime() + DEFAULT_TIMEOUT);
simulation.scheduleEvent(
timeoutEvent,
simulation.getSimulationTime() + DEFAULT_TIMEOUT);
}
engine.eval(jsCode);
@ -368,7 +334,7 @@ public class LogScriptEngine {
logger.fatal("Script error:", e);
deactivateScript();
gui.getSimulation().stopSimulation();
simulation.stopSimulation();
if (GUI.isVisualized()) {
GUI.showErrorDialog(GUI.getTopParentContainer(),
"Script error", e, false);
@ -384,11 +350,7 @@ public class LogScriptEngine {
}
/* Setup simulation observers */
gui.addObserver(guiObserver);
if (gui.getSimulation() != null) {
gui.getSimulation().addObserver(simObserver);
}
simulation.addObserver(simObserver);
/* Create script output logger */
engine.put("log", new ScriptLog() {
@ -403,24 +365,12 @@ public class LogScriptEngine {
if (GUI.isVisualized()) {
log("[if test was run without visualization, COOJA would now have been terminated]\n");
stopSimulation = true;
simulation.scheduleEvent(stopSimulationEvent, simulation.getSimulationTime());
} else {
quitCooja = true;
simulation.scheduleEvent(quitEvent, simulation.getSimulationTime());
}
/* 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());
if (timeoutEvent != null) {
timeoutEvent.remove();
}
@ -434,26 +384,10 @@ public class LogScriptEngine {
if (GUI.isVisualized()) {
log("[if test was run without visualization, COOJA would now have been terminated]\n");
stopSimulation = true;
simulation.scheduleEvent(stopSimulationEvent, simulation.getSimulationTime());
} else {
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());
if (timeoutEvent != null) {
timeoutEvent.remove();
simulation.scheduleEvent(quitEvent, simulation.getSimulationTime());
}
semaphoreSim.release(100);
@ -481,9 +415,9 @@ public class LogScriptEngine {
stepScript();
}
};
gui.getSimulation().scheduleEvent(
simulation.scheduleEvent(
generateEvent,
gui.getSimulation().getSimulationTime() + delay);
simulation.getSimulationTime() + delay);
}
});
@ -496,4 +430,23 @@ public class LogScriptEngine {
registerLogObserver();
}
private TimeEvent timeoutEvent = new TimeEvent(0) {
public void execute(long t) {
logger.info("Timeout event @ " + t);
engine.put("TIMEOUT", true);
stepScript();
}
};
private TimeEvent stopSimulationEvent = new TimeEvent(0) {
public void execute(long time) {
simulation.stopSimulation();
timeoutEvent.remove();
}
};
private TimeEvent quitEvent = new TimeEvent(0) {
public void execute(long time) {
simulation.getGUI().doQuit(false);
}
};
}

File diff suppressed because it is too large Load diff