Bug 1350897 - Tested quit shutdown/restart cause in Marionette Python client. r=whimboo draft bug_1305897
authorVedant Chakravadhanula <vedantc98@gmail.com>
Tue, 03 Oct 2017 10:48:30 +0530
branchbug_1305897
changeset 674051 7f01fe55444b034a5f07e42acac0224a981be881
parent 670404 bc56729898954e32d3a3731d03d178ed78924c33
child 734215 d1815a8a907d909e9aee1c847862e77ba6e089a8
push id82713
push userbmo:vedantc98@gmail.com
push dateTue, 03 Oct 2017 05:19:57 +0000
reviewerswhimboo
bugs1350897
milestone58.0a1
Bug 1350897 - Tested quit shutdown/restart cause in Marionette Python client. r=whimboo The Marionette server now returns a JSON containing the cause of shutdown which isn't included in previous Firefoxen. We needed to test this JSON in the quit and restart methods in the python client. MozReview-Commit-ID: 8uL9tbNszcm
testing/marionette/client/marionette_driver/marionette.py
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1043,16 +1043,17 @@ class Marionette(object):
 
         :param shutdown_flags: Optional additional quit masks to include.
             Duplicates are removed, and `"eAttemptQuit"` is added if no
             flags ending with `"Quit"` are present.
 
         :throws InvalidArgumentException: If there are multiple
             `shutdown_flags` ending with `"Quit"`.
 
+        :returns: The cause of shutdown.
         """
 
         # The vast majority of this function was implemented inside
         # the quit command as part of bug 1337743, and can be
         # removed from here in Firefox 55 at the earliest.
 
         # remove duplicates
         flags = set(shutdown_flags)
@@ -1075,17 +1076,17 @@ class Marionette(object):
             if canceled:
                 raise errors.MarionetteException(
                     "Something cancelled the quit application request")
 
         body = None
         if len(flags) > 0:
             body = {"flags": list(flags)}
 
-        self._send_message("quitApplication", body)
+        return self._send_message("quitApplication", body, key="cause")
 
     @do_process_check
     def quit(self, clean=False, in_app=False, callback=None):
         """Terminate the currently running instance.
 
         This command will delete the active marionette session. It also allows
         manipulation of eg. the profile data while the application is not running.
         To start the application again, :func:`start_session` has to be called.
@@ -1098,22 +1099,23 @@ class Marionette(object):
                        by killing the process.
         :param callback: If provided and `in_app` is True, the callback will
                          be used to trigger the shutdown.
         """
         if not self.instance:
             raise errors.MarionetteException("quit() can only be called "
                                              "on Gecko instances launched by Marionette")
 
+        cause = None
         if in_app:
             if callable(callback):
                 self._send_message("acceptConnections", {"value": False})
                 callback()
             else:
-                self._request_in_app_shutdown()
+                cause = self._request_in_app_shutdown()
 
             # Ensure to explicitely mark the session as deleted
             self.delete_session(send_request=False, reset_session_id=True)
 
             # Give the application some time to shutdown
             returncode = self.instance.runner.wait(timeout=self.DEFAULT_SHUTDOWN_TIMEOUT)
             if returncode is None:
                 # This will force-close the application without sending any other message.
@@ -1122,16 +1124,20 @@ class Marionette(object):
                 message = ("Process killed because a requested application quit did not happen "
                            "within {}s. Check gecko.log for errors.")
                 raise IOError(message.format(self.DEFAULT_SHUTDOWN_TIMEOUT))
 
         else:
             self.delete_session(reset_session_id=True)
             self.instance.close(clean=clean)
 
+        if cause not in (None, "shutdown"):
+            raise errors.MarionetteException("Unexpected shutdown reason '{}' for "
+                                             "quitting the process.".format(cause))
+
     @do_process_check
     def restart(self, clean=False, in_app=False, callback=None):
         """
         This will terminate the currently running instance, and spawn a new instance
         with the same profile and then reuse the session id when creating a session again.
 
         :param clean: If False the same profile will be used after the restart. Note
                       that the in app initiated restart always maintains the same
@@ -1141,25 +1147,27 @@ class Marionette(object):
                        by killing the process.
         :param callback: If provided and `in_app` is True, the callback will be
                          used to trigger the restart.
         """
         if not self.instance:
             raise errors.MarionetteException("restart() can only be called "
                                              "on Gecko instances launched by Marionette")
         context = self._send_message("getContext", key="value")
+
+        cause = None
         if in_app:
             if clean:
                 raise ValueError("An in_app restart cannot be triggered with the clean flag set")
 
             if callable(callback):
                 self._send_message("acceptConnections", {"value": False})
                 callback()
             else:
-                self._request_in_app_shutdown("eRestart")
+                cause = self._request_in_app_shutdown("eRestart")
 
             # Ensure to explicitely mark the session as deleted
             self.delete_session(send_request=False, reset_session_id=True)
 
             try:
                 timeout = self.DEFAULT_SHUTDOWN_TIMEOUT + self.DEFAULT_STARTUP_TIMEOUT
                 self.raise_for_port(timeout=timeout)
             except socket.timeout:
@@ -1167,16 +1175,21 @@ class Marionette(object):
                     exc, val, tb = sys.exc_info()
                     self.cleanup()
                     raise exc, "Requested restart of the application was aborted", tb
 
         else:
             self.delete_session()
             self.instance.restart(clean=clean)
             self.raise_for_port(timeout=self.DEFAULT_STARTUP_TIMEOUT)
+
+        if cause not in (None, "restart"):
+            raise errors.MarionetteException("Unexpected shutdown reason '{}' for "
+                                             "restarting the process".format(cause))
+
         self.start_session()
         # Restore the context as used before the restart
         self.set_context(context)
 
         if in_app and self.process_id:
             # In some cases Firefox restarts itself by spawning into a new process group.
             # As long as mozprocess cannot track that behavior (bug 1284864) we assist by
             # informing about the new process id.