Skip to content

Commit

Permalink
Bug 1726465 - [marionette-client] Add silent restart option on MacOS …
Browse files Browse the repository at this point in the history
…to Marionette client. r=webdriver-reviewers,jdescottes

Depends on D134277

Differential Revision: https://phabricator.services.mozilla.com/D134387
  • Loading branch information
whimboo committed May 10, 2022
1 parent 09b7954 commit c408cc7
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 19 deletions.
32 changes: 24 additions & 8 deletions remote/marionette/driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -2065,10 +2065,13 @@ GeckoDriver.prototype.close = async function() {
assert.open(this.getBrowsingContext({ context: Context.Content, top: true }));
await this._handleUserPrompts();

// If there is only one window left, do not close it. Instead return
// a faked empty array of window handles. This will instruct geckodriver
// to terminate the application.
if (TabManager.getTabCount() === 1) {
// If there is only one window left, do not close unless windowless mode is
// enabled. Instead return a faked empty array of window handles.
// This will instruct geckodriver to terminate the application.
if (
TabManager.getTabCount() === 1 &&
!this.currentSession.capabilities.get("moz:windowless")
) {
return [];
}

Expand Down Expand Up @@ -2102,10 +2105,10 @@ GeckoDriver.prototype.closeChromeWindow = async function() {
nwins++;
}

// If there is only one window left, do not close it. Instead return
// a faked empty array of window handles. This will instruct geckodriver
// to terminate the application.
if (nwins == 1) {
// If there is only one window left, do not close unless windowless mode is
// enabled. Instead return a faked empty array of window handles.
// This will instruct geckodriver to terminate the application.
if (nwins == 1 && !this.currentSession.capabilities.get("moz:windowless")) {
return [];
}

Expand Down Expand Up @@ -2627,6 +2630,19 @@ GeckoDriver.prototype.quit = async function(cmd) {
);
}

if (flags.includes("eSilently")) {
if (!this.currentSession.capabilities.get("moz:windowless")) {
throw new error.UnsupportedOperationError(
`Silent restarts only allowed with "moz:windowless" capability set`
);
}
if (!flags.includes("eRestart")) {
throw new error.InvalidArgumentError(
`"silently" only works with restart flag`
);
}
}

let quitSeen;
let mode = 0;
if (flags.length > 0) {
Expand Down
7 changes: 7 additions & 0 deletions remote/shared/webdriver/Capabilities.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,13 @@ class Capabilities extends Map {

case "moz:windowless":
assert.boolean(v, pprint`Expected ${k} to be boolean, got ${v}`);

// Only supported on MacOS
if (v && !AppInfo.isMac) {
throw new error.InvalidArgumentError(
"moz:windowless only supported on MacOS"
);
}
break;
}

Expand Down
28 changes: 22 additions & 6 deletions testing/marionette/client/marionette_driver/marionette.py
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,9 @@ def quit(self, clean=False, in_app=False, callback=None):
return quit_details

@do_process_check
def restart(self, callback=None, clean=False, in_app=False, safe_mode=False):
def restart(
self, callback=None, clean=False, in_app=False, safe_mode=False, silent=False
):
"""
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.
Expand All @@ -1069,6 +1071,10 @@ def restart(self, callback=None, clean=False, in_app=False, safe_mode=False):
:param safe_mode: Optional flag to indicate that the application has to
be restarted in safe mode.
:param silent: Optional flag to indicate that the application should
not open any window after a restart. Note that this flag is only
supported on MacOS.
:returns: A dictionary containing details of the application restart.
The `cause` property reflects the reason, and `forced` indicates
that something prevented the shutdown and the application had
Expand All @@ -1083,8 +1089,8 @@ def restart(self, callback=None, clean=False, in_app=False, safe_mode=False):
context = self._send_message("Marionette:GetContext", key="value")
restart_details = {"cause": "restart", "forced": False}

# Safe mode is only available with in_app restarts.
if safe_mode:
# Safe mode and the silent flag require in_app restarts.
if safe_mode or silent:
in_app = True

if in_app:
Expand All @@ -1106,9 +1112,19 @@ def restart(self, callback=None, clean=False, in_app=False, safe_mode=False):
if callback is not None:
callback()
else:
restart_details = self._request_in_app_shutdown(
flags=["eRestart"], safe_mode=safe_mode
)
flags = ["eRestart"]
if silent:
flags.append("eSilently")

try:
restart_details = self._request_in_app_shutdown(
flags=flags, safe_mode=safe_mode
)
except Exception as e:
self._send_message(
"Marionette:AcceptConnections", {"value": True}
)
raise e

except IOError:
# A possible IOError should be ignored at this point, given that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,14 @@ def test_valid_uuid4_when_creating_a_session(self):
"Session ID has {{}} in it: {}".format(self.marionette.session_id),
)

def test_windowless_false(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:windowless": False})
caps = self.marionette.session_capabilities
self.assertFalse(caps["moz:windowless"])

@unittest.skipUnless(sys.platform.startswith("darwin"), "Only supported on MacOS")
def test_windowless(self):
def test_windowless_true(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:windowless": True})
caps = self.marionette.session_capabilities
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ def test_incompatible_quit_flags(self):
with self.assertRaises(errors.InvalidArgumentException):
self.quit(("eAttemptQuit", "eForceQuit"))

def test_safe_mode_requires_restart(self):
with self.assertRaises(errors.InvalidArgumentException):
self.quit(("eAttemptQuit",), True)

def test_attempt_quit(self):
cause = self.quit(("eAttemptQuit",))
self.assertEqual("shutdown", cause)
Expand All @@ -79,6 +75,15 @@ def test_force_quit(self):
cause = self.quit(("eForceQuit",))
self.assertEqual("shutdown", cause)

def test_safe_mode_requires_restart(self):
with self.assertRaises(errors.InvalidArgumentException):
self.quit(("eAttemptQuit",), True)

@unittest.skipUnless(sys.platform.startswith("darwin"), "Only supported on MacOS")
def test_silent_quit_missing_windowless_capability(self):
with self.assertRaises(errors.UnsupportedOperationException):
self.quit(("eSilently",))


class TestQuitRestart(MarionetteTestCase):
def setUp(self):
Expand Down Expand Up @@ -297,6 +302,36 @@ def test_in_app_restart_preserves_requested_capabilities(self):
self.marionette.restart(in_app=True)
self.assertEqual(self.marionette.session.get("moz:fooBar"), True)

@unittest.skipUnless(sys.platform.startswith("darwin"), "Only supported on MacOS")
def test_in_app_silent_restart_fails_without_windowless_flag_on_mac_os(self):
self.marionette.delete_session()
self.marionette.start_session()

with self.assertRaises(errors.UnsupportedOperationException):
self.marionette.restart(silent=True)

@unittest.skipUnless(sys.platform.startswith("darwin"), "Only supported on MacOS")
def test_in_app_silent_restart_windowless_flag_on_mac_os(self):
self.marionette.delete_session()
self.marionette.start_session(capabilities={"moz:windowless": True})

self.marionette.restart(silent=True)
self.assertTrue(self.marionette.session_capabilities["moz:windowless"])

self.marionette.restart(in_app=True)
self.assertTrue(self.marionette.session_capabilities["moz:windowless"])

self.marionette.delete_session()

@unittest.skipIf(
sys.platform.startswith("darwin"), "Not supported on other platforms than MacOS"
)
def test_in_app_silent_restart_windowless_flag_unsupported_platforms(self):
self.marionette.delete_session()

with self.assertRaises(errors.SessionNotCreatedException):
self.marionette.start_session(capabilities={"moz:windowless": True})

def test_in_app_quit(self):
details = self.marionette.quit(in_app=True)

Expand Down

0 comments on commit c408cc7

Please sign in to comment.