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
--- 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.