From 00930b72c3759662dadcaa02991988d8070b63fb Mon Sep 17 00:00:00 2001 From: fros4943 Date: Wed, 17 Sep 2008 15:22:39 +0000 Subject: [PATCH] added "export contiki test" functionality. still needs testing --- .../se/sics/cooja/plugins/ScriptRunner.java | 315 +++++++++++++++++- 1 file changed, 310 insertions(+), 5 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java b/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java index a3aff34ff..64fe4fdab 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java +++ b/tools/cooja/java/se/sics/cooja/plugins/ScriptRunner.java @@ -26,23 +26,44 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ScriptRunner.java,v 1.1 2008/04/22 10:12:16 fros4943 Exp $ + * $Id: ScriptRunner.java,v 1.2 2008/09/17 15:22:39 fros4943 Exp $ */ package se.sics.cooja.plugins; import java.awt.BorderLayout; import java.awt.Insets; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.StringReader; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.*; + import org.apache.log4j.Logger; +import org.jdom.Document; import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; import se.sics.cooja.*; +import se.sics.cooja.dialogs.MessageList; -@ClassDescription("Script Runner (Log)") +@ClassDescription("(GUI) Test Script Editor") @PluginType(PluginType.COOJA_PLUGIN) public class ScriptRunner extends VisPlugin { private static final long serialVersionUID = 1L; @@ -65,7 +86,20 @@ public class ScriptRunner extends VisPlugin { scriptTextArea.setMargin(new Insets(5,5,5,5)); scriptTextArea.setEditable(true); scriptTextArea.setCursor(null); - scriptTextArea.setText("log.log('ID=' + id + ': ' + msg);"); + scriptTextArea.setText( + "/* Script is called once for every node log output. */\n" + + "/* Input variables: Mote mote, int id, String msg. */\n" + + "\n" + + "log.log('MOTE=' + mote + '\\n');\n" + + "log.log('ID=' + id + '\\n');\n" + + "log.log('TIME=' + mote.getSimulation().getSimulationTime() + '\\n');\n" + + "log.log('MSG=' + msg + '\\n');\n" + + "\n" + + "log.log('TEST OK\\n'); /* Report test success */\n" + + "//mote.getSimulation().getGUI().doQuit(false); /* Quit simulator (to end test run)*/\n" + + "\n" + + "//mote.getSimulation().getGUI().reloadCurrentSimulation(true); /* Reload simulation */\n" + ); logTextArea = new JTextArea(8,50); logTextArea.setMargin(new Insets(5,5,5,5)); @@ -97,15 +131,286 @@ public class ScriptRunner extends VisPlugin { } }); + JButton exportButton = new JButton("Export as Contiki test"); + exportButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + Simulation simulation = ScriptRunner.this.gui.getSimulation(); + if (simulation == null) { + JOptionPane.showMessageDialog(GUI.getTopParentContainer(), + "No simulation loaded. Aborting.", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + + /* Confirm test directory */ + File testDir = new File(GUI.getExternalToolsSetting("PATH_CONTIKI") + "/tools/cooja/contiki_tests"); + String s1 = "Ok"; + String s2 = "Cancel"; + Object[] options = { s1, s2 }; + int n = JOptionPane.showOptionDialog(GUI.getTopParentContainer(), + "Export current simulation config (.csc) and test script (.js)\n" + + "to directory '" + testDir.getPath() + "'?", + "Export Contiki test", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + if (!testDir.exists()) { + logger.fatal("Test directory does not exist: " + testDir.getPath()); + return; + } + + /* Name test to export */ + String testName = (String) JOptionPane.showInputDialog(GUI.getTopParentContainer(), + "Enter test name. No spaces or strange chars allowed.", + "Test name", JOptionPane.PLAIN_MESSAGE, null, null, + "mytest"); + if (testName == null) { + return; + } + if (testName.equals("") || testName.contains(" ")) { + JOptionPane.showMessageDialog(GUI.getTopParentContainer(), + "Bad test name: '" + testName + "'", "Bad test name", JOptionPane.ERROR_MESSAGE); + return; + } + + File cscFile = new File(testDir, testName + ".csc"); + File jsFile = new File(testDir, testName + ".js"); + File infoFile = new File(testDir, testName + ".info"); + final File logFile = new File(testDir, testName + ".log"); + + /* Overwrite existing test */ + if (cscFile.exists() || jsFile.exists() || infoFile.exists()) { + s1 = "Overwrite"; + s2 = "Cancel"; + n = JOptionPane.showOptionDialog(GUI.getTopParentContainer(), + "Some output files already exist. Overwrite?", + "Test already exist", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + + if (cscFile.exists()) { + cscFile.delete(); + } + if (jsFile.exists()) { + jsFile.delete(); + } + if (infoFile.exists()) { + infoFile.delete(); + } + + /* Get current simulation configuration */ + Element root = new Element("simconf"); + Element simulationElement = new Element("simulation"); + simulationElement.addContent(simulation.getConfigXML()); + root.addContent(simulationElement); + + /* Strip plugins */ + Collection pluginsConfig = ScriptRunner.this.gui.getPluginsConfigXML(); + if (pluginsConfig != null) { + JOptionPane.showMessageDialog(GUI.getTopParentContainer(), + "Stripping plugin configuration.\n" + + "(Exporting non-GUI plugins not implemented.)", + "Plugins detected", JOptionPane.WARNING_MESSAGE); + } + + /* Fix simulation delay */ + root.detach(); + String configString = new XMLOutputter().outputString(new Document(root)); + String identifierExtraction = "([^<]*)"; + Matcher matcher = Pattern.compile(identifierExtraction).matcher(configString); + while (matcher.find()) { + int delay = Integer.parseInt(matcher.group(1)); + if (delay != 0) { + JOptionPane.showMessageDialog(GUI.getTopParentContainer(), + "Simulation delay currently set to " + delay + ".\n" + + "Changing delay time to 0 in exported test.", + "Non-zero delay time detected", JOptionPane.WARNING_MESSAGE); + } + configString = configString.replace( + "" + matcher.group(1) + "", + "0"); + } + + /* Export .csc */ + try { + Element newRoot = new SAXBuilder().build(new StringReader(configString)).getRootElement(); + newRoot.detach(); + Document doc = new Document(newRoot); + FileOutputStream out = new FileOutputStream(cscFile); + XMLOutputter outputter = new XMLOutputter(); + outputter.setFormat(Format.getPrettyFormat()); + outputter.output(doc, out); + out.close(); + } catch (JDOMException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + /* Export .js */ + try { + BufferedWriter writer = + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(jsFile))); + writer.write(scriptTextArea.getText()); + writer.close(); + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + /* Export .info (optional) */ + try { + String info = JOptionPane.showInputDialog(GUI.getTopParentContainer(), + "(OPTIONAL) Enter test description", + "Optional test info", JOptionPane.QUESTION_MESSAGE); + if (info != null && !info.equals("")) { + BufferedWriter writer = + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(infoFile))); + writer.write(info); + writer.close(); + } + } catch (Exception ex) { + ex.printStackTrace(); + return; + } + + /* Run exported test (optional) */ + s1 = "Run test"; + s2 = "No"; + n = JOptionPane.showOptionDialog(GUI.getTopParentContainer(), + "Run exported test in forked Cooja now?", + "Run test?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + + try { + final Process externalCoojaProcess; + MessageList testOutput = new MessageList(); + final PrintStream normal = testOutput.getInputStream(MessageList.NORMAL); + final PrintStream error = testOutput.getInputStream(MessageList.ERROR); + + JPanel progressPanel = new JPanel(new BorderLayout()); + final JDialog progressDialog = new JDialog((Window)GUI.getTopParentContainer(), (String) null); + progressDialog.setTitle("Running test..."); + + String command[] = { + "java", + "-jar", + "../dist/cooja.jar", + "-nogui", + "-test=" + testName + }; + externalCoojaProcess = Runtime.getRuntime().exec(command, null, testDir); + final BufferedReader input = new BufferedReader(new InputStreamReader(externalCoojaProcess.getInputStream())); + final BufferedReader err = new BufferedReader(new InputStreamReader(externalCoojaProcess.getErrorStream())); + + JButton button = new JButton("Abort test/Close dialog"); + button.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (externalCoojaProcess != null) { + externalCoojaProcess.destroy(); + } + if (progressDialog != null && progressDialog.isDisplayable()) { + progressDialog.dispose(); + } + } + }); + + progressPanel.add(BorderLayout.CENTER, new JScrollPane(testOutput)); + progressPanel.add(BorderLayout.SOUTH, button); + progressPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + progressPanel.setVisible(true); + + progressDialog.getContentPane().add(progressPanel); + progressDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + progressDialog.pack(); + + progressDialog.getRootPane().setDefaultButton(button); + progressDialog.setLocationRelativeTo(ScriptRunner.this); + progressDialog.setVisible(true); + + Thread readInput = new Thread(new Runnable() { + public void run() { + String readLine; + try { + while ((readLine = input.readLine()) != null) { + if (normal != null && readLine != null) { + normal.println(readLine); + } + } + + } catch (IOException e) { + logger.warn("Error while reading from process"); + } + + /* Parse log file for success info */ + try { + BufferedReader in = new BufferedReader(new InputStreamReader( + new FileInputStream(logFile))); + boolean testSucceeded = false; + while (in.ready()) { + String line = in.readLine(); + if (line.contains("TEST OK")) { + testSucceeded = true; + break; + } + } + if (testSucceeded) { + progressDialog.setTitle("Test run completed. Test succeeded!"); + } else { + progressDialog.setTitle("Test run completed. Test failed!"); + } + } catch (FileNotFoundException e) { + logger.fatal("File not found: " + e); + } catch (IOException e) { + logger.fatal("IO error: " + e); + } + + } + }, "read input stream thread"); + + Thread readError = new Thread(new Runnable() { + public void run() { + String readLine; + try { + while ((readLine = err.readLine()) != null) { + if (error != null && readLine != null) { + error.println(readLine); + } + } + } catch (IOException e) { + logger.warn("Error while reading from process"); + } + } + }, "read input stream thread"); + + readInput.start(); + readError.start(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + JPanel centerPanel = new JPanel(new BorderLayout()); centerPanel.add(BorderLayout.CENTER, new JScrollPane(scriptTextArea)); centerPanel.add(BorderLayout.SOUTH, new JScrollPane(logTextArea)); JPanel buttonPanel = new JPanel(new BorderLayout()); - buttonPanel.add(BorderLayout.EAST, toggleButton); + buttonPanel.add(BorderLayout.WEST, toggleButton); + buttonPanel.add(BorderLayout.EAST, exportButton); + + JPanel southPanel = new JPanel(new BorderLayout()); + southPanel.add(BorderLayout.EAST, buttonPanel); getContentPane().add(BorderLayout.CENTER, centerPanel); - getContentPane().add(BorderLayout.SOUTH, buttonPanel); + getContentPane().add(BorderLayout.SOUTH, southPanel); pack();