Bug 985537 - Add runEmulatorShell to Marionette. r=mdas, a=test-only
authorVicamo Yang <vyang@mozilla.com>
Thu, 20 Mar 2014 13:01:25 +0800
changeset 192543 102de3568ed555eca0f918cdf2c434b84bd757d1
parent 192542 965dcb2e8059cdfc62c5f438d0e815baddf2dc23
child 192544 89bbecef9a590ffac244492faa8cdec7215b99bd
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmdas, test-only
bugs985537
milestone30.0a2
Bug 985537 - Add runEmulatorShell to Marionette. r=mdas, a=test-only
testing/marionette/client/marionette/emulator.py
testing/marionette/client/marionette/marionette.py
testing/marionette/client/marionette/tests/unit/test_emulator.py
testing/marionette/marionette-frame-manager.js
testing/marionette/marionette-listener.js
testing/marionette/marionette-server.js
testing/marionette/marionette-simpletest.js
--- a/testing/marionette/client/marionette/emulator.py
+++ b/testing/marionette/client/marionette/emulator.py
@@ -220,16 +220,20 @@ class Emulator(object):
                 raise Exception('bad telnet response: %s' % line)
 
     def _run_telnet(self, command):
         if not self.telnet:
             self.telnet = Telnet('localhost', self.port)
             self._get_telnet_response()
         return self._get_telnet_response(command)
 
+    def _run_shell(self, args):
+        args.insert(0, 'shell')
+        return self._run_adb(args).split('\r\n')
+
     def close(self):
         if self.is_running and self._emulator_launched:
             self.proc.kill()
         if self._adb_started:
             self._run_adb(['kill-server'])
             self._adb_started = False
         if self.proc:
             retcode = self.proc.poll()
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -603,34 +603,52 @@ class Marionette(object):
             self.session = None
             self.window = None
             self.client.close()
             raise TimeoutException(
                 "Connection timed out", status=ErrorCodes.TIMEOUT)
 
         # Process any emulator commands that are sent from a script
         # while it's executing.
-        while response.get("emulator_cmd"):
-            response = self._handle_emulator_cmd(response)
+        while True:
+            if response.get("emulator_cmd"):
+                response = self._handle_emulator_cmd(response)
+                continue;
+
+            if response.get("emulator_shell"):
+                response = self._handle_emulator_shell(response)
+                continue;
+
+            break;
 
         if response_key in response:
             return response[response_key]
         self._handle_error(response)
 
     def _handle_emulator_cmd(self, response):
         cmd = response.get("emulator_cmd")
         if not cmd or not self.emulator:
             raise MarionetteException(
                 "No emulator in this test to run command against")
         cmd = cmd.encode("ascii")
         result = self.emulator._run_telnet(cmd)
         return self.client.send({"name": "emulatorCmdResult",
                                  "id": response.get("id"),
                                  "result": result})
 
+    def _handle_emulator_shell(self, response):
+        args = response.get("emulator_shell")
+        if not isinstance(args, list) or not self.emulator:
+            raise MarionetteException(
+                "No emulator in this test to run shell command against")
+        result = self.emulator._run_shell(args)
+        return self.client.send({"name": "emulatorCmdResult",
+                                 "id": response.get("id"),
+                                 "result": result})
+
     def _handle_error(self, response):
         if 'error' in response and isinstance(response['error'], dict):
             status = response['error'].get('status', 500)
             message = response['error'].get('message')
             stacktrace = response['error'].get('stacktrace')
             # status numbers come from
             # http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes
             if status == ErrorCodes.NO_SUCH_ELEMENT:
--- a/testing/marionette/client/marionette/tests/unit/test_emulator.py
+++ b/testing/marionette/client/marionette/tests/unit/test_emulator.py
@@ -12,16 +12,24 @@ class TestEmulatorContent(MarionetteTest
         self.marionette.set_script_timeout(10000)
         expected = ["<build>",
                     "OK"]
         result = self.marionette.execute_async_script("""
         runEmulatorCmd("avd name", marionetteScriptFinished)
         """);
         self.assertEqual(result, expected)
 
+    def test_emulator_shell(self):
+        self.marionette.set_script_timeout(10000)
+        expected = ["Hello World!", ""]
+        result = self.marionette.execute_async_script("""
+        runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
+        """);
+        self.assertEqual(result, expected)
+
     def test_emulator_order(self):
         self.marionette.set_script_timeout(10000)
         self.assertRaises(MarionetteException,
                           self.marionette.execute_async_script,
         """runEmulatorCmd("gsm status", function(result) {});
            marionetteScriptFinished(true);
         """);
 
--- a/testing/marionette/marionette-frame-manager.js
+++ b/testing/marionette/marionette-frame-manager.js
@@ -158,16 +158,17 @@ FrameManager.prototype = {
   addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) {
     messageManager.addWeakMessageListener("Marionette:ok", this.server);
     messageManager.addWeakMessageListener("Marionette:done", this.server);
     messageManager.addWeakMessageListener("Marionette:error", this.server);
     messageManager.addWeakMessageListener("Marionette:log", this.server);
     messageManager.addWeakMessageListener("Marionette:shareData", this.server);
     messageManager.addWeakMessageListener("Marionette:register", this.server);
     messageManager.addWeakMessageListener("Marionette:runEmulatorCmd", this.server);
+    messageManager.addWeakMessageListener("Marionette:runEmulatorShell", this.server);
     messageManager.addWeakMessageListener("Marionette:switchToModalOrigin", this.server);
     messageManager.addWeakMessageListener("Marionette:switchToFrame", this.server);
     messageManager.addWeakMessageListener("Marionette:switchedToFrame", this.server);
     messageManager.addWeakMessageListener("MarionetteFrame:handleModal", this);
     messageManager.addWeakMessageListener("MarionetteFrame:getInterruptedState", this);
   },
 
   /**
@@ -185,14 +186,15 @@ FrameManager.prototype = {
   removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) {
     messageManager.removeWeakMessageListener("Marionette:ok", this.server);
     messageManager.removeWeakMessageListener("Marionette:done", this.server);
     messageManager.removeWeakMessageListener("Marionette:error", this.server);
     messageManager.removeWeakMessageListener("Marionette:log", this.server);
     messageManager.removeWeakMessageListener("Marionette:shareData", this.server);
     messageManager.removeWeakMessageListener("Marionette:register", this.server);
     messageManager.removeWeakMessageListener("Marionette:runEmulatorCmd", this.server);
+    messageManager.removeWeakMessageListener("Marionette:runEmulatorShell", this.server);
     messageManager.removeWeakMessageListener("Marionette:switchToFrame", this.server);
     messageManager.removeWeakMessageListener("Marionette:switchedToFrame", this.server);
     messageManager.removeWeakMessageListener("MarionetteFrame:handleModal", this);
   },
 
 };
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -2014,16 +2014,24 @@ let _emu_cbs = {};
 function runEmulatorCmd(cmd, callback) {
   if (callback) {
     _emu_cbs[_emu_cb_id] = callback;
   }
   sendAsyncMessage("Marionette:runEmulatorCmd", {emulator_cmd: cmd, id: _emu_cb_id});
   _emu_cb_id += 1;
 }
 
+function runEmulatorShell(args, callback) {
+  if (callback) {
+    _emu_cbs[_emu_cb_id] = callback;
+  }
+  sendAsyncMessage("Marionette:runEmulatorShell", {emulator_shell: args, id: _emu_cb_id});
+  _emu_cb_id += 1;
+}
+
 function emulatorCmdResult(msg) {
   let message = msg.json;
   if (!sandbox) {
     return;
   }
   let cb = _emu_cbs[message.id];
   delete _emu_cbs[message.id];
   if (!cb) {
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2123,16 +2123,27 @@ MarionetteServerConnection.prototype = {
         this._emu_cbs = {};
       }
       this._emu_cbs[this._emu_cb_id] = callback;
     }
     this.sendToClient({emulator_cmd: cmd, id: this._emu_cb_id}, -1);
     this._emu_cb_id += 1;
   },
 
+  runEmulatorShell: function runEmulatorShell(args, callback) {
+    if (callback) {
+      if (!this._emu_cbs) {
+        this._emu_cbs = {};
+      }
+      this._emu_cbs[this._emu_cb_id] = callback;
+    }
+    this.sendToClient({emulator_shell: args, id: this._emu_cb_id}, -1);
+    this._emu_cb_id += 1;
+  },
+
   emulatorCmdResult: function emulatorCmdResult(message) {
     if (this.context != "chrome") {
       this.sendAsync("emulatorCmdResult", message, -1);
       return;
     }
 
     if (!this._emu_cbs) {
       return;
@@ -2320,16 +2331,17 @@ MarionetteServerConnection.prototype = {
         break;
       case "Marionette:shareData":
         //log messages from tests
         if (message.json.log) {
           this.marionetteLog.addLogs(message.json.log);
         }
         break;
       case "Marionette:runEmulatorCmd":
+      case "Marionette:runEmulatorShell":
         this.sendToClient(message.json, -1);
         break;
       case "Marionette:switchToFrame":
         this.curBrowser.frameManager.switchToFrame(message);
         this.messageManager = this.curBrowser.frameManager.currentRemoteFrame.messageManager.get();
         break;
       case "Marionette:switchToModalOrigin":
         this.curBrowser.frameManager.switchToModalOrigin(message);
--- a/testing/marionette/marionette-simpletest.js
+++ b/testing/marionette/marionette-simpletest.js
@@ -17,17 +17,17 @@ this.Marionette = function Marionette(sc
   this.testName = testName;
   this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL";
   this.TEST_PASS = "TEST-PASS";
   this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL";
 }
 
 Marionette.prototype = {
   exports: ['ok', 'is', 'isnot', 'log', 'getLogs', 'generate_results', 'waitFor',
-            'runEmulatorCmd', 'TEST_PASS', 'TEST_KNOWN_FAIL',
+            'runEmulatorCmd', 'runEmulatorShell', 'TEST_PASS', 'TEST_KNOWN_FAIL',
             'TEST_UNEXPECTED_FAIL'],
 
   ok: function Marionette__ok(condition, name, passString, failString, diag) {
     this.heartbeatCallback();
     if (typeof(diag) == "undefined") {
       diag = this.repr(condition) + " was " + !!condition + ", expected true";
     }
     let test = {'result': !!condition, 'name': name, 'diag': diag};
@@ -158,10 +158,15 @@ Marionette.prototype = {
       this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline - now);
   },
 
   runEmulatorCmd: function runEmulatorCmd(cmd, callback) {
     this.heartbeatCallback();
     this.scope.runEmulatorCmd(cmd, callback);
   },
 
+  runEmulatorShell: function runEmulatorShell(args, callback) {
+    this.heartbeatCallback();
+    this.scope.runEmulatorShell(args, callback);
+  },
+
 };