Bug 1274408: Remove emulator code from Marionette python client r?maja_zf draft
authorDavid Burns <dburns@mozilla.com>
Tue, 24 May 2016 00:11:18 +0100
changeset 370530 2e4a111ad891e6bcacb941dbacd5c0d6cbb01879
parent 370529 9a1f5c66a7f71f83d282dddea84e672b4d1e1b11
child 370531 d672da42d731d1aea8eb639bbcb96180a0342326
push id19087
push userdburns@mozilla.com
push dateTue, 24 May 2016 22:03:13 +0000
reviewersmaja_zf
bugs1274408
milestone49.0a1
Bug 1274408: Remove emulator code from Marionette python client r?maja_zf The emulator code has created a lot of hacky code in the Marionette and by removing it, we are removing a lot of really bad technical debt. MozReview-Commit-ID: D8wxdKPp6zW
testing/marionette/client/marionette_driver/marionette.py
testing/marionette/client/marionette_driver/transport.py
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -11,18 +11,16 @@ import StringIO
 import traceback
 import warnings
 
 from contextlib import contextmanager
 
 from decorators import do_crash_check
 from keys import Keys
 
-from mozrunner import B2GEmulatorRunner
-
 import geckoinstance
 import errors
 import transport
 
 WEBELEMENT_KEY = "ELEMENT"
 W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
 
 
@@ -536,45 +534,37 @@ class Marionette(object):
     CONTEXT_CHROME = 'chrome' # non-browser content: windows, dialogs, etc.
     CONTEXT_CONTENT = 'content' # browser content: iframes, divs, etc.
     TIMEOUT_SEARCH = 'implicit'
     TIMEOUT_SCRIPT = 'script'
     TIMEOUT_PAGE = 'page load'
     DEFAULT_SOCKET_TIMEOUT = 360
     DEFAULT_STARTUP_TIMEOUT = 60
 
-    def __init__(self, host='localhost', port=2828, app=None, app_args=None, bin=None,
-                 profile=None, addons=None, emulator=None, sdcard=None, emulator_img=None,
-                 emulator_binary=None, emulator_res=None, connect_to_running_emulator=False,
-                 gecko_log=None, homedir=None, baseurl=None, no_window=False, logdir=None,
-                 busybox=None, symbols_path=None, timeout=None,
-                 socket_timeout=DEFAULT_SOCKET_TIMEOUT, device_serial=None, adb_path=None,
-                 process_args=None, adb_host=None, adb_port=None, prefs=None,
+    def __init__(self, host='localhost', port=2828, app=None, app_args=None,
+                 bin=None, profile=None, addons=None,
+                 gecko_log=None, baseurl=None,
+                 symbols_path=None, timeout=None,
+                 socket_timeout=DEFAULT_SOCKET_TIMEOUT,
+                 process_args=None, prefs=None,
                  startup_timeout=None, workspace=None, verbose=0):
         self.host = host
         self.port = self.local_port = port
         self.bin = bin
         self.profile = profile
         self.addons = addons
         self.instance = None
         self.session = None
         self.session_id = None
         self.window = None
         self.chrome_window = None
-        self.runner = None
-        self.emulator = None
-        self.extra_emulators = []
         self.baseurl = baseurl
-        self.no_window = no_window
         self._test_name = None
         self.timeout = timeout
         self.socket_timeout = socket_timeout
-        self.device_serial = device_serial
-        self.adb_host = adb_host
-        self.adb_port = adb_port
 
         startup_timeout = startup_timeout or self.DEFAULT_STARTUP_TIMEOUT
 
         if bin:
             port = int(self.port)
             if not Marionette.is_port_available(port, host=self.host):
                 ex_msg = "%s:%d is unavailable." % (self.host, port)
                 raise errors.MarionetteException(message=ex_msg)
@@ -592,86 +582,41 @@ class Marionette(object):
                     app = config.get('App', 'Name')
                     instance_class = geckoinstance.apps[app.lower()]
                 except (ConfigParser.NoOptionError,
                         ConfigParser.NoSectionError,
                         KeyError):
                     instance_class = geckoinstance.GeckoInstance
             self.instance = instance_class(host=self.host, port=self.port,
                                            bin=self.bin, profile=self.profile,
-                                           app_args=app_args,
                                            symbols_path=symbols_path,
                                            gecko_log=gecko_log, prefs=prefs,
                                            addons=self.addons,
                                            workspace=workspace,
                                            verbose=verbose)
             self.instance.start()
             self.raise_for_port(self.wait_for_port(timeout=startup_timeout))
 
-        if emulator:
-            self.runner = B2GEmulatorRunner(b2g_home=homedir,
-                                            no_window=self.no_window,
-                                            logdir=logdir,
-                                            arch=emulator,
-                                            sdcard=sdcard,
-                                            symbols_path=symbols_path,
-                                            binary=emulator_binary,
-                                            userdata=emulator_img,
-                                            resolution=emulator_res,
-                                            profile=self.profile,
-                                            addons=self.addons,
-                                            adb_path=adb_path,
-                                            process_args=process_args)
-            self.emulator = self.runner.device
-            self.emulator.start()
-            self.port = self.emulator.setup_port_forwarding(remote_port=self.port)
-            self.raise_for_port(self.emulator.wait_for_port(self.port))
-
-        if connect_to_running_emulator:
-            self.runner = B2GEmulatorRunner(b2g_home=homedir,
-                                            logdir=logdir,
-                                            process_args=process_args)
-            self.emulator = self.runner.device
-            self.emulator.connect()
-            self.port = self.emulator.setup_port_forwarding(remote_port=self.port)
-            self.raise_for_port(self.emulator.wait_for_port(self.port))
-
-        if emulator:
-            if busybox:
-                self.emulator.install_busybox(busybox=busybox)
-            self.emulator.wait_for_system_message(self)
-
-        # for callbacks from a protocol level 2 or lower remote,
-        # we store the callback ID so it can be used by _send_emulator_result
-        self.emulator_callback_id = None
-
     @property
     def profile_path(self):
         if self.instance and self.instance.profile:
             return self.instance.profile.profile
-        elif self.runner and self.runner.profile:
-            return self.runner.profile.profile
-
 
     def cleanup(self):
         if self.session:
             try:
                 self.delete_session()
             except (errors.MarionetteException, socket.error, IOError):
                 # These exceptions get thrown if the Marionette server
                 # hit an exception/died or the connection died. We can
                 # do no further server-side cleanup in this case.
                 pass
             self.session = None
-        if self.runner:
-            self.runner.cleanup()
         if self.instance:
             self.instance.close()
-        for qemu in self.extra_emulators:
-            qemu.emulator.close()
 
     def __del__(self):
         self.cleanup()
 
     @staticmethod
     def is_port_available(port, host=''):
         port = int(port)
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -697,23 +642,16 @@ class Marionette(object):
     @do_crash_check
     def _send_message(self, name, params=None, key=None):
         """Send a blocking message to the server.
 
         Marionette provides an asynchronous, non-blocking interface and
         this attempts to paper over this by providing a synchronous API
         to the user.
 
-        In particular, the Python client can be instructed to carry out
-        a sequence of instructions on the connected emulator.  For this
-        reason, if ``execute_script``, ``execute_js_script``, or
-        ``execute_async_script`` is called, it will loop until all
-        commands requested from the server have been exhausted, and we
-        receive our expected response.
-
         :param name: Requested command key.
         :param params: Optional dictionary of key/value arguments.
         :param key: Optional key to extract from response.
 
         :returns: Full response from the server, or if `key` is given,
             the value of said key in the response.
         """
 
@@ -740,28 +678,16 @@ class Marionette(object):
             raise
 
         except socket.timeout:
             self.session = None
             self.window = None
             self.client.close()
             raise errors.TimeoutException("Connection timed out")
 
-        # support execution of commands on the client,
-        # loop until we receive our expected response
-        while isinstance(msg, transport.Command):
-            if msg.name == "runEmulatorCmd":
-                self.emulator_callback_id = msg.params.get("id")
-                msg = self._emulator_cmd(msg.params["emulator_cmd"])
-            elif msg.name == "runEmulatorShell":
-                self.emulator_callback_id = msg.params.get("id")
-                msg = self._emulator_shell(msg.params["emulator_shell"])
-            else:
-                raise IOError("Unknown command: %s" % msg)
-
         res, err = msg.result, msg.error
         if err:
             self._handle_error(err)
 
         if key is not None:
             return self._unwrap_response(res.get(key))
         else:
             return self._unwrap_response(res)
@@ -773,44 +699,16 @@ class Marionette(object):
                 return HTMLElement(self, value.get(WEBELEMENT_KEY))
             else:
                 return HTMLElement(self, value.get(W3C_WEBELEMENT_KEY))
         elif isinstance(value, list):
             return list(self._unwrap_response(item) for item in value)
         else:
             return value
 
-    def _emulator_cmd(self, cmd):
-        if not self.emulator:
-            raise errors.MarionetteException(
-                "No emulator in this test to run command against")
-        payload = cmd.encode("ascii")
-        result = self.emulator._run_telnet(payload)
-        return self._send_emulator_result(result)
-
-    def _emulator_shell(self, args):
-        if not isinstance(args, list) or not self.emulator:
-            raise errors.MarionetteException(
-                "No emulator in this test to run shell command against")
-        buf = StringIO.StringIO()
-        self.emulator.dm.shell(args, buf)
-        result = str(buf.getvalue()[0:-1]).rstrip().splitlines()
-        buf.close()
-        return self._send_emulator_result(result)
-
-    def _send_emulator_result(self, result):
-        if self.protocol < 3:
-            body = {"name": "emulatorCmdResult",
-                    "id": self.emulator_callback_id,
-                    "result": result}
-            self.client.send(body)
-            return self.client.receive()
-        else:
-            return self.client.respond(result)
-
     def _handle_error(self, obj):
         if self.protocol == 1:
             if "error" not in obj or not isinstance(obj["error"], dict):
                 raise errors.MarionetteException(
                     "Malformed packet, expected key 'error' to be a dict: %s" % obj)
             error = obj["error"].get("status")
             message = obj["error"].get("message")
             stacktrace = obj["error"].get("stacktrace")
@@ -829,22 +727,17 @@ class Marionette(object):
             self.timeouts(self.TIMEOUT_PAGE, self.timeout)
         else:
             self.timeouts(self.TIMEOUT_PAGE, 30000)
 
     def check_for_crash(self):
         returncode = None
         name = None
         crashed = False
-        if self.runner:
-            if self.runner.check_for_crashes(test_name=self.test_name):
-                returncode = self.emulator.proc.returncode
-                name = 'emulator'
-                crashed = True
-        elif self.instance:
+        if self.instance:
             if self.instance.runner.check_for_crashes(
                     test_name=self.test_name):
                 crashed = True
         if returncode is not None:
             print ('PROCESS-CRASH | %s | abnormal termination with exit code %d' %
                 (name, returncode))
         return crashed
 
@@ -1176,17 +1069,16 @@ class Marionette(object):
         self.wait_for_port(timeout=timeout)
         self.protocol, _ = self.client.connect()
 
         body = {"capabilities": desired_capabilities, "sessionId": session_id}
         resp = self._send_message("newSession", body)
 
         self.session_id = resp["sessionId"]
         self.session = resp["value"] if self.protocol == 1 else resp["capabilities"]
-        self.b2g = "b2g" in self.session
 
         return self.session
 
     @property
     def test_name(self):
         return self._test_name
 
     @test_name.setter
@@ -1989,18 +1881,16 @@ class Marionette(object):
         back to "portrait-primary" and "landscape-primary"
         respectively, and "portrait-secondary" as well as
         "landscape-secondary".
 
         :param orientation: The orientation to lock the screen in.
         """
         body = {"orientation": orientation}
         self._send_message("setScreenOrientation", body)
-        if self.emulator:
-            self.emulator.screen.orientation = orientation.lower()
 
     @property
     def window_size(self):
         """Get the current browser window size.
 
         Will return the current browser window size in pixels. Refers to
         window outerWidth and outerHeight values, which include scroll bars,
         title bars, etc.
--- a/testing/marionette/client/marionette_driver/transport.py
+++ b/testing/marionette/client/marionette_driver/transport.py
@@ -80,26 +80,16 @@ class Response(Message):
 class Proto2Command(Command):
     """Compatibility shim that marshals messages from a protocol level
     2 and below remote into ``Command`` objects.
     """
 
     def __init__(self, name, params):
         Command.__init__(self, None, name, params)
 
-    @staticmethod
-    def from_data(data):
-        if "emulator_cmd" in data:
-            name = "runEmulatorCmd"
-        elif "emulator_shell" in data:
-            name = "runEmulatorShell"
-        else:
-            raise ValueError
-        return Proto2Command(name, data)
-
 
 class Proto2Response(Response):
     """Compatibility shim that marshals messages from a protocol level
     2 and below remote into ``Response`` objects.
     """
 
     def __init__(self, error, result):
         Response.__init__(self, None, error, result)
@@ -156,23 +146,17 @@ class TcpTransport(object):
                 msg = Command.from_msg(packet)
             elif typ == Response.TYPE:
                 msg = Response.from_msg(packet)
 
         # protocol 2 and below
         else:
             data = json.loads(packet)
 
-            # emulator callbacks
-            if isinstance(data, dict) and any(k in data for k in ("emulator_cmd", "emulator_shell")):
-                msg = Proto2Command.from_data(data)
-
-            # everything else
-            else:
-                msg = Proto2Response.from_data(data)
+            msg = Proto2Response.from_data(data)
 
         return msg
 
     def receive(self, unmarshal=True):
         """Wait for the next complete response from the remote.
 
         :param unmarshal: Default is to deserialise the packet and
             return a ``Message`` type.  Setting this to false will return