Backed out 8 changesets (bug 1726465) for causing failures on browser_preferences_usage.js. CLOSED TREE

Backed out changeset 4b57310622a0 (bug 1726465)
Backed out changeset 0c6c4a15621a (bug 1726465)
Backed out changeset 081a0f91e0a7 (bug 1726465)
Backed out changeset 60bceb18ff57 (bug 1726465)
Backed out changeset f241655ea876 (bug 1726465)
Backed out changeset 7bc0a3aeb254 (bug 1726465)
Backed out changeset b2f7c710daef (bug 1726465)
Backed out changeset e9b90fd1b4ec (bug 1726465)
This commit is contained in:
criss 2022-05-10 13:59:54 +03:00
Родитель 5e5b3f791c
Коммит 70783e1c31
18 изменённых файлов: 259 добавлений и 386 удалений

Просмотреть файл

@ -8403,16 +8403,6 @@ const gRemoteControl = {
},
updateVisualCue() {
// Disable updating the remote control cue for performance tests,
// because these could fail due to an early initialization of Marionette.
const disableRemoteControlCue = Services.prefs.getBoolPref(
"browser.chrome.disableRemoteControlCueForTests",
false
);
if (disableRemoteControlCue && Cu.isInAutomation) {
return;
}
const mainWindow = document.documentElement;
const remoteControlComponent = this.getRemoteControlComponent();
if (remoteControlComponent) {

Просмотреть файл

@ -15,9 +15,6 @@ prefs =
extensions.formautofill.addresses.available='on'
extensions.formautofill.creditCards.available='on'
browser.urlbar.disableExtendForTests=true
# For perfomance tests do not enable the remote control cue, which gets set
# when Marionette is enabled, but users normally don't see.
browser.chrome.disableRemoteControlCueForTests=true
# The Screenshots extension is disabled by default in Mochitests. We re-enable
# it here, since it's a more realistic configuration.
extensions.screenshots.disabled=false

Просмотреть файл

@ -112,25 +112,6 @@ XPCOMUtils.defineLazyServiceGetters(this, {
PushService: ["@mozilla.org/push/Service;1", "nsIPushService"],
});
if (AppConstants.ENABLE_WEBDRIVER) {
XPCOMUtils.defineLazyServiceGetter(
this,
"Marionette",
"@mozilla.org/remote/marionette;1",
"nsIMarionette"
);
XPCOMUtils.defineLazyServiceGetter(
this,
"RemoteAgent",
"@mozilla.org/remote/agent;1",
"nsIRemoteAgent"
);
} else {
this.Marionette = { running: false };
this.RemoteAgent = { running: false };
}
const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state";
const PREF_DFPI_ENABLED_BY_DEFAULT =
"privacy.restrict3rdpartystorage.rollout.enabledByDefault";
@ -2699,8 +2680,10 @@ BrowserGlue.prototype = {
// `UpdateService.disabledForTesting`, but without creating the
// service, which can perform a good deal of I/O in order to log its
// state. Since this is in the startup path, we avoid all of that.
// We also don't test for Marionette and Remote Agent since they are
// not yet initialized.
let disabledForTesting =
(Cu.isInAutomation || Marionette.running || RemoteAgent.running) &&
Cu.isInAutomation &&
Services.prefs.getBoolPref("app.update.disabledForTesting", false);
if (!disabledForTesting) {
BackgroundUpdate.maybeScheduleBackgroundUpdateTask();
@ -2749,7 +2732,10 @@ BrowserGlue.prototype = {
},
},
// WebDriver components (Marionette) need to be
// initialized as very last step.
{
condition: AppConstants.ENABLE_WEBDRIVER,
task: () => {
// Use idleDispatch a second time to run this after the per-window
// idle tasks.
@ -2758,10 +2744,12 @@ BrowserGlue.prototype = {
null,
"browser-startup-idle-tasks-finished"
);
Services.obs.notifyObservers(null, "marionette-startup-requested");
});
},
},
// Do NOT add anything after idle tasks finished.
// Do NOT add anything after WebDriver initialization.
];
for (let task of idleTasks) {

Просмотреть файл

@ -32,8 +32,6 @@ async function runFirefox(args) {
environment: {
ASAN_OPTIONS:
"detect_leaks=0:quarantine_size=50331648:malloc_context_size=5",
// Don't enable Marionette.
MOZ_MARIONETTE: null,
},
});
let stdout;

Просмотреть файл

@ -851,6 +851,16 @@ function startup() {
"browser-idle-startup-tasks-finished"
)
);
InitLater(() => {
// This lets Marionette start listening (when enabled).
// Both GeckoView and this remote protocol do most of their
// initialization in "profile-after-change", and there is no order enforced
// between them. Therefore we defer asking the Marionette component to
// startup until after all "profile-after-change" handlers (including this
// one) have completed.
Services.obs.notifyObservers(null, "marionette-startup-requested");
});
});
// Move focus to the content window at the end of startup,

Просмотреть файл

@ -98,7 +98,7 @@ class CDP {
// to find any available target. Also when closing the application while
// it's still starting up can cause shutdown hangs. As such CDP will be
// started when the initial application window has finished initializing.
logger.debug(`Waiting for initial application window`);
logger.debug(`Waiting for initial application window to be loaded`);
await this.agent.browserStartupFinished;
Cu.printStderr(`DevTools listening on ${this.address}\n`);

Просмотреть файл

@ -12,7 +12,6 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
Deferred: "chrome://remote/content/shared/Sync.jsm",
EnvironmentPrefs: "chrome://remote/content/marionette/prefs.js",
Log: "chrome://remote/content/shared/Log.jsm",
MarionettePrefs: "chrome://remote/content/marionette/prefs.js",
@ -35,6 +34,9 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIEnvironment"
);
const XMLURI_PARSE_ERROR =
"http://www.mozilla.org/newlayout/xml/parsererror.xml";
const NOTIFY_LISTENING = "marionette-listening";
// Complements -marionette flag for starting the Marionette server.
@ -66,8 +68,6 @@ const isRemote =
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
class MarionetteParentProcess {
#browserStartupFinished;
constructor() {
this.server = null;
this._activePortPath;
@ -75,22 +75,18 @@ class MarionetteParentProcess {
this.classID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
this.helpInfo = " --marionette Enable remote control server.\n";
// holds reference to ChromeWindow
// used to run GFX sanity tests on Windows
this.gfxWindow = null;
// indicates that all pending window checks have been completed
// and that we are ready to start the Marionette server
this.finalUIStartup = false;
// Initially set the enabled state based on the environment variable.
this.enabled = env.exists(ENV_ENABLED);
Services.ppmm.addMessageListener("Marionette:IsRunning", this);
this.#browserStartupFinished = Deferred();
}
/**
* A promise that resolves when the initial application window has been opened.
*
* @returns {Promise}
* Promise that resolves when the initial application window is open.
*/
get browserStartupFinished() {
return this.#browserStartupFinished.promise;
}
get enabled() {
@ -153,14 +149,8 @@ class MarionetteParentProcess {
this.enabled = subject.handleFlag("marionette", false);
if (this.enabled) {
// Marionette needs to be initialized before any window is shown.
Services.obs.addObserver(this, "final-ui-startup");
// We want to suppress the modal dialog that's shown
// when starting up in safe-mode to enable testing.
if (Services.appinfo.inSafeMode) {
Services.obs.addObserver(this, "domwindowopened");
}
Services.obs.addObserver(this, "toplevel-window-ready");
Services.obs.addObserver(this, "marionette-startup-requested");
RecommendedPreferences.applyPreferences(RECOMMENDED_PREFS);
@ -169,6 +159,25 @@ class MarionetteParentProcess {
for (let [pref, value] of EnvironmentPrefs.from(ENV_PRESERVE_PREFS)) {
Preferences.set(pref, value);
}
// We want to suppress the modal dialog that's shown
// when starting up in safe-mode to enable testing.
if (Services.appinfo.inSafeMode) {
Services.obs.addObserver(this, "domwindowopened");
}
}
break;
case "domwindowclosed":
if (this.gfxWindow === null || subject === this.gfxWindow) {
Services.obs.removeObserver(this, topic);
Services.obs.removeObserver(this, "toplevel-window-ready");
Services.obs.addObserver(this, "quit-application");
this.finalUIStartup = true;
await this.init();
}
break;
@ -177,29 +186,57 @@ class MarionetteParentProcess {
this.suppressSafeModeDialog(subject);
break;
case "final-ui-startup":
Services.obs.removeObserver(this, topic);
case "toplevel-window-ready":
subject.addEventListener(
"load",
async ev => {
if (ev.target.documentElement.namespaceURI == XMLURI_PARSE_ERROR) {
Services.obs.removeObserver(this, topic);
Services.obs.addObserver(this, "browser-idle-startup-tasks-finished");
Services.obs.addObserver(this, "mail-idle-startup-tasks-finished");
Services.obs.addObserver(this, "quit-application");
await this.init();
let parserError = ev.target.querySelector("parsererror");
logger.fatal(parserError.textContent);
await this.uninit();
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
}
},
{ once: true }
);
break;
// Used to wait until the initial application window has been opened.
case "browser-idle-startup-tasks-finished":
case "mail-idle-startup-tasks-finished":
Services.obs.removeObserver(
this,
"browser-idle-startup-tasks-finished"
);
Services.obs.removeObserver(this, "mail-idle-startup-tasks-finished");
this.#browserStartupFinished.resolve();
case "marionette-startup-requested":
Services.obs.removeObserver(this, topic);
// When Firefox starts on Windows, an additional GFX sanity test
// window may appear off-screen. Marionette should wait for it
// to close.
for (let win of Services.wm.getEnumerator(null)) {
if (
win.document.documentURI ==
"chrome://gfxsanity/content/sanityparent.html"
) {
this.gfxWindow = win;
break;
}
}
if (this.gfxWindow) {
logger.trace(
"GFX sanity window detected, waiting until it has been closed..."
);
Services.obs.addObserver(this, "domwindowclosed");
} else {
Services.obs.removeObserver(this, "toplevel-window-ready");
Services.obs.addObserver(this, "quit-application");
this.finalUIStartup = true;
await this.init();
}
break;
case "quit-application":
Services.obs.removeObserver(this, topic);
Services.obs.removeObserver(this, "quit-application");
await this.uninit();
break;
}
@ -222,40 +259,56 @@ class MarionetteParentProcess {
);
}
async init() {
if (!this.enabled || this.running) {
async init(quit = true) {
if (this.running || !this.enabled || !this.finalUIStartup) {
logger.debug(
`Init aborted (enabled=${this.enabled}, running=${this.running})`
`Init aborted (running=${this.running}, ` +
`enabled=${this.enabled}, finalUIStartup=${this.finalUIStartup})`
);
return;
}
try {
this.server = new TCPListener(MarionettePrefs.port);
this.server.start();
} catch (e) {
logger.fatal("Marionette server failed to start", e);
await this.uninit();
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
return;
}
env.set(ENV_ENABLED, "1");
Services.obs.notifyObservers(this, NOTIFY_LISTENING, true);
logger.debug("Marionette is listening");
// Write Marionette port to MarionetteActivePort file within the profile.
this._activePortPath = PathUtils.join(
PathUtils.profileDir,
"MarionetteActivePort"
logger.trace(
`Waiting until startup recorder finished recording startup scripts...`
);
Services.tm.idleDispatchToMainThread(async () => {
let startupRecorder = Promise.resolve();
if ("@mozilla.org/test/startuprecorder;1" in Cc) {
startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()
.wrappedJSObject.done;
}
await startupRecorder;
logger.trace(`All scripts recorded.`);
const data = `${this.server.port}`;
try {
await IOUtils.write(this._activePortPath, textEncoder.encode(data));
} catch (e) {
logger.warn(`Failed to create ${this._activePortPath} (${e.message})`);
}
try {
this.server = new TCPListener(MarionettePrefs.port);
this.server.start();
} catch (e) {
logger.fatal("Remote protocol server failed to start", e);
await this.uninit();
if (quit) {
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
}
return;
}
env.set(ENV_ENABLED, "1");
Services.obs.notifyObservers(this, NOTIFY_LISTENING, true);
logger.debug("Marionette is listening");
// Write Marionette port to MarionetteActivePort file within the profile.
this._activePortPath = PathUtils.join(
PathUtils.profileDir,
"MarionetteActivePort"
);
const data = `${this.server.port}`;
try {
await IOUtils.write(this._activePortPath, textEncoder.encode(data));
} catch (e) {
logger.warn(`Failed to create ${this._activePortPath} (${e.message})`);
}
});
}
async uninit() {

Просмотреть файл

@ -44,11 +44,11 @@ const isRemote =
class RemoteAgentParentProcess {
#allowHosts;
#allowOrigins;
#browserStartupFinished;
#classID;
#enabled;
#port;
#server;
#browserStartupFinished;
#cdp;
#webDriverBiDi;
@ -56,11 +56,11 @@ class RemoteAgentParentProcess {
constructor() {
this.#allowHosts = null;
this.#allowOrigins = null;
this.#browserStartupFinished = Deferred();
this.#classID = Components.ID("{8f685a9d-8181-46d6-a71d-869289099c6d}");
this.#enabled = false;
this.#port = DEFAULT_PORT;
this.#server = null;
this.#browserStartupFinished = Deferred();
// Supported protocols
this.#cdp = null;
@ -103,10 +103,11 @@ class RemoteAgentParentProcess {
}
/**
* A promise that resolves when the initial application window has been opened.
* A promise resolved once initialization of the browser has completed and
* all the windows restored.
*
* @returns {Promise}
* Promise that resolves when the initial application window is open.
* Promise that resolves when the application startup has finished.
*/
get browserStartupFinished() {
return this.#browserStartupFinished.promise;
@ -372,7 +373,8 @@ class RemoteAgentParentProcess {
// Listen for application shutdown to also shutdown the Remote Agent
// and a possible running instance of httpd.js.
case "quit-application":
Services.obs.removeObserver(this, topic);
Services.obs.removeObserver(this, "quit-application");
this.#stop();
break;
}

Просмотреть файл

@ -37,7 +37,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
IdlePromise: "chrome://remote/content/marionette/sync.js",
l10n: "chrome://remote/content/marionette/l10n.js",
Log: "chrome://remote/content/shared/Log.jsm",
Marionette: "chrome://remote/content/components/Marionette.jsm",
MarionettePrefs: "chrome://remote/content/marionette/prefs.js",
modal: "chrome://remote/content/marionette/modal.js",
navigate: "chrome://remote/content/marionette/navigate.js",
@ -423,67 +422,56 @@ GeckoDriver.prototype.newSession = async function(cmd) {
this._currentSession.capabilities.delete("webSocketUrl");
}
const win = await windowManager.waitForInitialApplicationWindow();
if (MarionettePrefs.clickToStart) {
Services.prompt.alert(
win,
"",
"Click to start execution of marionette tests"
);
}
this.addBrowser(win);
this.mainFrame = win;
registerCommandsActor();
enableEventsActor();
// Don't wait for the initial window when Marionette is in windowless mode
if (!this.currentSession.capabilities.get("moz:windowless")) {
// Creating a WebDriver session too early can cause issues with
// clients in not being able to find any available window handle.
// Also when closing the application while it's still starting up can
// cause shutdown hangs. As such Marionette will return a new session
// once the initial application window has finished initializing.
logger.debug(`Waiting for initial application window`);
await Marionette.browserStartupFinished;
// Setup observer for modal dialogs
this.dialogObserver = new modal.DialogObserver(() => this.curBrowser);
this.dialogObserver.add(this.handleModalDialog.bind(this));
const appWin = await windowManager.waitForInitialApplicationWindowLoaded();
for (let win of windowManager.windows) {
const tabBrowser = TabManager.getTabBrowser(win);
if (MarionettePrefs.clickToStart) {
Services.prompt.alert(
appWin,
"",
"Click to start execution of marionette tests"
);
}
this.addBrowser(appWin);
this.mainFrame = appWin;
// Setup observer for modal dialogs
this.dialogObserver = new modal.DialogObserver(() => this.curBrowser);
this.dialogObserver.add(this.handleModalDialog.bind(this));
for (let win of windowManager.windows) {
const tabBrowser = TabManager.getTabBrowser(win);
if (tabBrowser) {
for (const tab of tabBrowser.tabs) {
const contentBrowser = TabManager.getBrowserForTab(tab);
this.registerBrowser(contentBrowser);
}
if (tabBrowser) {
for (const tab of tabBrowser.tabs) {
const contentBrowser = TabManager.getBrowserForTab(tab);
this.registerBrowser(contentBrowser);
}
this.registerListenersForWindow(win);
}
if (this.mainFrame) {
this.currentSession.chromeBrowsingContext = this.mainFrame.browsingContext;
this.mainFrame.focus();
}
if (this.curBrowser.tab) {
const browsingContext = this.curBrowser.contentBrowser.browsingContext;
this.currentSession.contentBrowsingContext = browsingContext;
await waitForInitialNavigationCompleted(browsingContext.webProgress);
this.curBrowser.contentBrowser.focus();
}
// Check if there is already an open dialog for the selected browser window.
this.dialog = modal.findModalDialogs(this.curBrowser);
this.registerListenersForWindow(win);
}
if (this.mainFrame) {
this.currentSession.chromeBrowsingContext = this.mainFrame.browsingContext;
this.mainFrame.focus();
}
if (this.curBrowser.tab) {
const browsingContext = this.curBrowser.contentBrowser.browsingContext;
this.currentSession.contentBrowsingContext = browsingContext;
await waitForInitialNavigationCompleted(browsingContext.webProgress);
this.curBrowser.contentBrowser.focus();
}
// Check if there is already an open dialog for the selected browser window.
this.dialog = modal.findModalDialogs(this.curBrowser);
Services.obs.addObserver(this, "browser-delayed-startup-finished");
} catch (e) {
throw new error.SessionNotCreatedError(e);
@ -2065,13 +2053,10 @@ 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 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")
) {
// 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) {
return [];
}
@ -2105,10 +2090,10 @@ GeckoDriver.prototype.closeChromeWindow = async function() {
nwins++;
}
// 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")) {
// 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) {
return [];
}
@ -2630,19 +2615,6 @@ 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) {

Просмотреть файл

@ -245,32 +245,58 @@ class WindowManager {
* @return {Promise<WindowProxy>}
* A promise that resolved to the application window.
*/
waitForInitialApplicationWindowLoaded() {
waitForInitialApplicationWindow() {
return new TimedPromise(
async resolve => {
const windowReadyTopic = AppInfo.isThunderbird
? "mail-delayed-startup-finished"
: "browser-delayed-startup-finished";
resolve => {
const waitForWindow = () => {
let windowTypes;
if (AppInfo.isThunderbird) {
windowTypes = ["mail:3pane"];
} else {
// We assume that an app either has GeckoView windows, or
// Firefox/Fennec windows, but not both.
windowTypes = ["navigator:browser", "navigator:geckoview"];
}
// This call includes a fallback to "mail3:pane" as well.
const win = Services.wm.getMostRecentBrowserWindow();
let win;
for (const windowType of windowTypes) {
win = Services.wm.getMostRecentWindow(windowType);
if (win) {
break;
}
}
const windowLoaded = waitForObserverTopic(windowReadyTopic, {
checkFn: subject => (win !== null ? subject == win : true),
});
if (!win) {
// if the window isn't even created, just poll wait for it
let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(
Ci.nsITimer
);
checkTimer.initWithCallback(
waitForWindow,
100,
Ci.nsITimer.TYPE_ONE_SHOT
);
} else if (win.document.readyState != "complete") {
// otherwise, wait for it to be fully loaded before proceeding
let listener = ev => {
// ensure that we proceed, on the top level document load event
// (not an iframe one...)
if (ev.target != win.document) {
return;
}
win.removeEventListener("load", listener);
waitForWindow();
};
win.addEventListener("load", listener, true);
} else {
resolve(win);
}
};
// The current window has already been finished loading.
if (win && win.document.readyState == "complete") {
resolve(win);
return;
}
// Wait for the next browser/mail window to open and finished loading.
const { subject } = await windowLoaded;
resolve(subject);
waitForWindow();
},
{
errorMessage: "No applicable application window found",
errorMessage: "No applicable application windows found",
}
);
}

Просмотреть файл

@ -457,7 +457,6 @@ class Capabilities extends Map {
],
["moz:useNonSpecCompliantPointerOrigin", false],
["moz:webdriverClick", true],
["moz:windowless", false],
]);
}
@ -587,11 +586,6 @@ class Capabilities extends Map {
assert.boolean(v, pprint`Expected ${k} to be boolean, got ${v}`);
break;
// Don't set the value because it's only used to return the address
// of the Remote Agent's debugger (HTTP server).
case "moz:debuggerAddress":
continue;
case "moz:useNonSpecCompliantPointerOrigin":
assert.boolean(v, pprint`Expected ${k} to be boolean, got ${v}`);
break;
@ -600,16 +594,10 @@ class Capabilities extends Map {
assert.boolean(v, pprint`Expected ${k} to be boolean, got ${v}`);
break;
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;
// Don't set the value because it's only used to return the address
// of the Remote Agent's debugger (HTTP server).
case "moz:debuggerAddress":
continue;
}
matched.set(k, v);

Просмотреть файл

@ -99,7 +99,7 @@ class WebDriverBiDi {
// Also when closing the application while it's still starting up can
// cause shutdown hangs. As such WebDriver BiDi will return a new session
// once the initial application window has finished initializing.
logger.debug(`Waiting for initial application window`);
logger.debug(`Waiting for initial application window to be loaded`);
await this.agent.browserStartupFinished;
this.agent.server.registerPathHandler(session.path, session);

Просмотреть файл

@ -1050,9 +1050,7 @@ class Marionette(object):
return quit_details
@do_process_check
def restart(
self, callback=None, clean=False, in_app=False, safe_mode=False, silent=False
):
def restart(self, callback=None, clean=False, in_app=False, safe_mode=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.
@ -1071,10 +1069,6 @@ class Marionette(object):
: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
@ -1089,8 +1083,8 @@ class Marionette(object):
context = self._send_message("Marionette:GetContext", key="value")
restart_details = {"cause": "restart", "forced": False}
# Safe mode and the silent flag require in_app restarts.
if safe_mode or silent:
# Safe mode is only available with in_app restarts.
if safe_mode:
in_app = True
if in_app:
@ -1112,19 +1106,9 @@ class Marionette(object):
if callback is not None:
callback()
else:
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
restart_details = self._request_in_app_shutdown(
flags=["eRestart"], safe_mode=safe_mode
)
except IOError:
# A possible IOError should be ignored at this point, given that

Просмотреть файл

@ -5,8 +5,6 @@
from __future__ import absolute_import, print_function
import os
import sys
import unittest
from marionette_driver.errors import SessionNotCreatedException
from marionette_harness import MarionetteTestCase
@ -105,9 +103,6 @@ class TestCapabilities(MarionetteTestCase):
self.assertIn("moz:webdriverClick", self.caps)
self.assertTrue(self.caps["moz:webdriverClick"])
self.assertIn("moz:windowless", self.caps)
self.assertFalse(self.caps["moz:windowless"])
def test_disable_webdriver_click(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:webdriverClick": False})
@ -120,26 +115,13 @@ class TestCapabilities(MarionetteTestCase):
caps = self.marionette.session_capabilities
self.assertTrue(caps["moz:useNonSpecCompliantPointerOrigin"])
def test_valid_uuid4_when_creating_a_session(self):
def test_we_get_valid_uuid4_when_creating_a_session(self):
self.assertNotIn(
"{",
self.marionette.session_id,
"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_true(self):
self.marionette.delete_session()
self.marionette.start_session({"moz:windowless": True})
caps = self.marionette.session_capabilities
self.assertTrue(caps["moz:windowless"])
class TestCapabilityMatching(MarionetteTestCase):
def setUp(self):

Просмотреть файл

@ -67,6 +67,10 @@ class TestServerQuitApplication(MarionetteTestCase):
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)
@ -75,15 +79,6 @@ class TestServerQuitApplication(MarionetteTestCase):
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):
@ -302,36 +297,6 @@ class TestQuitRestart(MarionetteTestCase):
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)

Просмотреть файл

@ -1,58 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import
from marionette_driver import errors, Wait
from marionette_harness import MarionetteTestCase
class TestWindowless(MarionetteTestCase):
def setUp(self):
super(TestWindowless, self).setUp()
self.marionette.delete_session()
self.marionette.start_session({"moz:windowless": True})
def tearDown(self):
# Reset the browser and active WebDriver session
self.marionette.restart(in_app=True)
self.marionette.delete_session()
super(TestWindowless, self).tearDown()
def test_last_chrome_window_can_be_closed(self):
with self.marionette.using_context("chrome"):
handles = self.marionette.chrome_window_handles
self.assertGreater(len(handles), 0)
self.marionette.switch_to_window(handles[0])
self.marionette.close_chrome_window()
self.assertEqual(len(self.marionette.chrome_window_handles), 0)
def test_last_content_window_can_be_closed(self):
handles = self.marionette.window_handles
self.assertGreater(len(handles), 0)
self.marionette.switch_to_window(handles[0])
self.marionette.close()
self.assertEqual(len(self.marionette.window_handles), 0)
def test_no_window_handles_after_silent_restart(self):
# Check that windows are present, but not after a silent restart
handles = self.marionette.window_handles
self.assertGreater(len(handles), 0)
self.marionette.restart(silent=True)
with self.assertRaises(errors.TimeoutException):
wait = Wait(
self.marionette,
ignored_exceptions=errors.NoSuchWindowException,
timeout=5,
)
wait.until(lambda _: self.marionette.window_handles)
# After a normal restart a browser window will be opened again
self.marionette.restart(in_app=True)
handles = self.marionette.window_handles
self.assertGreater(len(handles), 0)
self.marionette.switch_to_window(handles[0])

Просмотреть файл

@ -71,8 +71,7 @@ expected = fail
[test_execute_isolate.py]
[test_click_scrolling.py]
[test_profile_management.py]
skip-if =
manage_instance == false || (debug && ((os == 'mac') || (os == 'linux'))) # Bug 1450355
skip-if = manage_instance == false || (debug && ((os == 'mac') || (os == 'linux'))) # Bug 1450355
[test_quit_restart.py]
skip-if = manage_instance == false
[test_context.py]
@ -99,8 +98,7 @@ skip-if = manage_instance == false
[test_select.py]
[test_crash.py]
skip-if =
asan || manage_instance == false
skip-if = asan || manage_instance == false
[test_localization.py]
[test_reftest.py]
@ -111,6 +109,3 @@ skip-if =
[test_sendkeys_menupopup_chrome.py]
[test_get_shadow_root.py]
[test_windowless.py]
skip-if = os != 'mac' # only supported on MacOS

Просмотреть файл

@ -1,19 +0,0 @@
from copy import deepcopy
def test_marionette_fallback_webdriver_session(configuration, geckodriver):
config = deepcopy(configuration)
config["capabilities"]["webSocketUrl"] = True
prefs = config["capabilities"]["moz:firefoxOptions"].get("prefs", {})
prefs.update({"remote.active-protocols": 2})
config["capabilities"]["moz:firefoxOptions"]["prefs"] = prefs
driver = geckodriver(config=config)
driver.new_session()
assert driver.session.capabilities.get("webSocketUrl") is None
# Sanity check that Marionette works as expected and by default returns
# at least one window handle
assert len(driver.session.handles) >= 1