Bug 1520966 - Make toolkit/components/passwordmgr/test/text_xhr.html work with e10s. r=MattN
authorJared Wein <jwein@mozilla.com>
Fri, 01 Feb 2019 20:15:02 +0000
changeset 456530 365e026a163adcc3a86b7ce4e1da477af78ae822
parent 456529 a36422c1abbc543755c84500e530433dc3b9e242
child 456531 520b19bd2109e8ed4a7153cf918e08b4785c8ef9
push id35488
push userdvarga@mozilla.com
push dateSat, 02 Feb 2019 09:44:51 +0000
treeherdermozilla-central@d8cebb3b46cf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1520966
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1520966 - Make toolkit/components/passwordmgr/test/text_xhr.html work with e10s. r=MattN I didn't use the checkPromptModal function because the implementation in chromeScript was getting a null document reference. Since handlePrompt already has access to this information it made sense to extend handlePrompt to cover more cases. Differential Revision: https://phabricator.services.mozilla.com/D18267
dom/plugins/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html
toolkit/components/passwordmgr/moz.build
toolkit/components/passwordmgr/test/mochitest.ini
toolkit/components/passwordmgr/test/mochitest/mochitest.ini
toolkit/components/passwordmgr/test/mochitest/test_xhr.html
toolkit/components/passwordmgr/test/prompt_common.js
toolkit/components/passwordmgr/test/test_xhr.html
toolkit/components/prompts/test/chromeScript.js
toolkit/components/prompts/test/prompt_common.js
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -22,17 +22,16 @@ support-files =
   mixed_case_mime.sjs
   neverending.sjs
   npruntime_identifiers_subpage.html
   plugin-stream-referer.sjs
   plugin_window.html
   pluginstream.js
   post.sjs
   plugin-utils.js
-  !/toolkit/components/passwordmgr/test/authenticate.sjs
 
 [test_bug1028200-1.html]
 skip-if = !crashreporter
 [test_bug1028200-2.html]
 skip-if = !crashreporter
 [test_bug1028200-3.html]
 skip-if = !crashreporter
 [test_bug1028200-4.html]
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_auth.html
@@ -10,17 +10,17 @@
   <script type="text/javascript" src="head.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 <script>
 "use strict";
 
 // This file defines content scripts.
 /* eslint-env mozilla/frame-script */
 
-let baseUrl = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/authenticate.sjs";
+let baseUrl = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/test/mochitest/authenticate.sjs";
 function testXHR(url) {
   return new Promise((resolve, reject) => {
     let xhr = new XMLHttpRequest();
     xhr.open("GET", url);
     xhr.onload = resolve;
     xhr.onabort = reject;
     xhr.onerror = reject;
     xhr.send();
--- a/toolkit/components/passwordmgr/moz.build
+++ b/toolkit/components/passwordmgr/moz.build
@@ -2,17 +2,17 @@
 # vim: set filetype=python:
 # 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/.
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
 
-MOCHITEST_MANIFESTS += ['test/mochitest.ini', 'test/mochitest/mochitest.ini']
+MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 
 TESTING_JS_MODULES += [
     # Make this file available from the "resource:" URI of the test environment.
     'test/browser/form_basic.html',
     'test/LoginTestUtils.jsm',
 ]
deleted file mode 100644
--- a/toolkit/components/passwordmgr/test/mochitest.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[DEFAULT]
-prefs =
-  signon.rememberSignons=true
-  signon.autofillForms.http=true
-  security.insecure_field_warning.contextual.enabled=false
-  network.auth.non-web-content-triggered-resources-http-auth-allow=true
-skip-if = e10s
-support-files =
-  authenticate.sjs
-  blank.html
-  formsubmit.sjs
-  prompt_common.js
-  pwmgr_common.js
-
-[test_xhr.html]
-skip-if = toolkit == 'android' # Tests desktop prompts
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
@@ -88,12 +88,14 @@ skip-if = os == "linux" || toolkit == 'a
 skip-if = e10s || toolkit == 'android' # Tests desktop prompts. e10s: bug 1217876
 [test_prompt_promptAuth.html]
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_prompt_promptAuth_proxy.html]
 skip-if = e10s || os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_recipe_login_fields.html]
 [test_username_focus.html]
 skip-if = toolkit == 'android' # android:autocomplete.
+[test_xhr.html]
+skip-if = toolkit == 'android' # Tests desktop prompts
 [test_xhr_2.html]
 [test_xml_load.html]
 skip-if = toolkit == 'android' # Tests desktop prompts
 
rename from toolkit/components/passwordmgr/test/test_xhr.html
rename to toolkit/components/passwordmgr/test/mochitest/test_xhr.html
--- a/toolkit/components/passwordmgr/test/test_xhr.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_xhr.html
@@ -1,199 +1,172 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Test for XHR prompts</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script>
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <script type="text/javascript" src="prompt_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Login Manager test: XHR prompt
 <p id="display"></p>
 
 <div id="content" style="display: none">
   <iframe id="iframe"></iframe>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Login Manager: XHR prompts. **/
-var login1, login2;
-
-function initLogins() {
-  login1 = Cc["@mozilla.org/login-manager/loginInfo;1"].
-            createInstance(Ci.nsILoginInfo);
-  login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].
-            createInstance(Ci.nsILoginInfo);
-
-  login1.init("http://mochi.test:8888", null, "xhr",
-              "xhruser1", "xhrpass1", "", "");
-  login2.init("http://mochi.test:8888", null, "xhr2",
-              "xhruser2", "xhrpass2", "", "");
-
-  SpecialPowers.Services.logins.addLogin(login1);
-  SpecialPowers.Services.logins.addLogin(login2);
-}
-
-function finishTest() {
-  ok(true, "finishTest removing testing logins...");
-  SpecialPowers.Services.logins.removeLogin(login1);
-  SpecialPowers.Services.logins.removeLogin(login2);
-
-  SimpleTest.finish();
+function makeRequest(uri) {
+  return new Promise((resolve, reject) => {
+    let request = new XMLHttpRequest();
+    request.open("GET", uri, true);
+    request.addEventListener("loadend", function onLoadEnd() {
+      let result = xhrLoad(request.responseXML);
+      resolve(result);
+    });
+    request.send(null);
+  });
 }
 
-function handleDialog(doc, testNum) {
-  ok(true, "handleDialog running for test " + testNum);
-
-  var clickOK = true;
-  var userfield = doc.getElementById("loginTextbox");
-  var passfield = doc.getElementById("password1Textbox");
-  var username = userfield.getAttribute("value");
-  var password = passfield.getAttribute("value");
-  var dialog    = doc.getElementById("commonDialog");
-
-  switch (testNum) {
-    case 1:
-      is(username, "xhruser1", "Checking provided username");
-      is(password, "xhrpass1", "Checking provided password");
-      break;
-
-    case 2:
-      is(username, "xhruser2", "Checking provided username");
-      is(password, "xhrpass2", "Checking provided password");
-
-      // Check that the dialog is modal, chrome and dependent;
-      // We can't just check window.opener because that'll be
-      // a content window, which therefore isn't exposed (it'll lie and
-      // be null).
-      var win = doc.defaultView;
-      var Ci = SpecialPowers.Ci;
-      var treeOwner = win.docShell.treeOwner;
-      treeOwner.QueryInterface(Ci.nsIInterfaceRequestor);
-      var flags = treeOwner.getInterface(Ci.nsIXULWindow).chromeFlags;
-      var wbc = treeOwner.getInterface(Ci.nsIWebBrowserChrome);
-      info("Flags: " + flags);
-      ok((flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME) != 0,
-         "Dialog should be opened as chrome");
-      ok((flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) != 0,
-         "Dialog should be opened as a dialog");
-      ok((flags & Ci.nsIWebBrowserChrome.CHROME_DEPENDENT) != 0,
-         "Dialog should be opened as dependent.");
-      ok(wbc.isWindowModal(), "Dialog should be modal");
-
-      // Check that the right tab is focused:
-      var browserWin = SpecialPowers.Services.wm.getMostRecentWindow("navigator:browser");
-      var spec = browserWin.gBrowser.selectedBrowser.currentURI.spec;
-      ok(spec.startsWith("http://mochi.test:8888"),
-         "Tab with remote URI (rather than about:blank) should be focused (" + spec + ")");
-
-
-      break;
-
-    default:
-      ok(false, "Uhh, unhandled switch for testNum #" + testNum);
-      break;
-  }
-
-  // Explicitly cancel the dialog and report a fail in this failure
-  // case, rather than letting the dialog get stuck due to an auth
-  // failure and having the test timeout.
-  if (!username && !password) {
-    ok(false, "No values prefilled");
-    clickOK = false;
-  }
-
-  if (clickOK) {
-    dialog.acceptDialog();
-  } else {
-    dialog.cancelDialog();
-  }
-
-  ok(true, "handleDialog done");
-  didDialog = true;
-}
-
-var newWin;
 function xhrLoad(xmlDoc) {
-  ok(true, "xhrLoad running for test " + testNum);
-
   // The server echos back the user/pass it received.
   var username = xmlDoc.getElementById("user").textContent;
   var password = xmlDoc.getElementById("pass").textContent;
   var authok = xmlDoc.getElementById("ok").textContent;
-
-
-  switch (testNum) {
-    case 1:
-      is(username, "xhruser1", "Checking provided username");
-      is(password, "xhrpass1", "Checking provided password");
-      break;
-
-    case 2:
-      is(username, "xhruser2", "Checking provided username");
-      is(password, "xhrpass2", "Checking provided password");
-
-      newWin.close();
-      break;
-
-    default:
-      ok(false, "Uhh, unhandled switch for testNum #" + testNum);
-      break;
-  }
-
-  doTest();
+  return {username, password, authok};
 }
 
-function doTest() {
-  switch (++testNum) {
-    case 1:
-      startCallbackTimer();
-      makeRequest("authenticate.sjs?user=xhruser1&pass=xhrpass1&realm=xhr");
-      break;
+// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
+isTabModal = false;
+
+let prompterParent = runInParent(() => {
+  const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+  const promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].
+                    getService(Ci.nsIPromptFactory);
+
+  let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
+  let prompt = promptFac.getPrompt(chromeWin, Ci.nsIAuthPrompt);
+
+  addMessageListener("proxyPrompter", function onMessage(msg) {
+    let rv = prompt[msg.methodName](...msg.args);
+    return {
+      rv,
+      // Send the args back to content so out/inout args can be checked.
+      args: msg.args,
+    };
+  });
+});
 
-    case 2:
-      // Test correct parenting, by opening another tab in the foreground,
-      // and making sure the prompt re-focuses the original tab when shown:
-      newWin = window.open();
-      newWin.focus();
-      startCallbackTimer();
-      makeRequest("authenticate.sjs?user=xhruser2&pass=xhrpass2&realm=xhr2");
-      break;
+let prompter1 = new PrompterProxy(prompterParent);
 
-    default:
-      finishTest();
-  }
-}
+add_task(function setup() {
+  runInParent(function initLogins() {
+    const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
+    let nsLoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
+                                             Ci.nsILoginInfo, "init");
+    let login1 = new nsLoginInfo("http://mochi.test:8888", null, "xhr",
+                                 "xhruser1", "xhrpass1", "", "");
+    let login2 = new nsLoginInfo("http://mochi.test:8888", null, "xhr2",
+                                 "xhruser2", "xhrpass2", "", "");
+
+    try {
+      Services.logins.addLogin(login1);
+      Services.logins.addLogin(login2);
+    } catch (e) {
+      assert.ok(false, "addLogin threw: " + e);
+    }
+  });
+});
 
-function makeRequest(uri) {
-  var request = new XMLHttpRequest();
-  request.open("GET", uri, true);
-  request.onreadystatechange = function() {
-    if (request.readyState == 4) {
-      xhrLoad(request.responseXML);
-    }
+add_task(async function test1() {
+  let state = {
+    msg: "http://mochi.test:8888 is requesting your username and password. The site says: “xhr”",
+    title: "Authentication Required",
+    textValue: "xhruser1",
+    passValue: "xhrpass1",
+    iconClass: "authentication-icon question-icon",
+    titleHidden: true,
+    textHidden: false,
+    passHidden: false,
+    checkHidden: true,
+    checkMsg: "",
+    checked: false,
+    focused: "textField",
+    defButton: "button0",
   };
-  request.send(null);
-}
+  let action = {
+    buttonClick: "ok",
+  };
+  let promptDone = handlePrompt(state, action);
+  let requestPromise = makeRequest("authenticate.sjs?user=xhruser1&pass=xhrpass1&realm=xhr");
+  await promptDone;
+  let result = await requestPromise;
 
+  is(result.authok, "PASS", "Checking for successful authentication");
+  is(result.username, "xhruser1", "Checking for username");
+  is(result.password, "xhrpass1", "Checking for password");
+});
+
+add_task(async function test2() {
+  // Test correct parenting, by opening another tab in the foreground,
+  // and making sure the prompt re-focuses the original tab when shown:
+  newWin = window.open();
+  newWin.focus();
 
-initLogins();
+  let state = {
+    msg: "http://mochi.test:8888 is requesting your username and password. The site says: “xhr2”",
+    title: "Authentication Required",
+    textValue: "xhruser2",
+    passValue: "xhrpass2",
+    iconClass: "authentication-icon question-icon",
+    titleHidden: true,
+    textHidden: false,
+    passHidden: false,
+    checkHidden: true,
+    checkMsg: "",
+    checked: false,
+    focused: "textField",
+    defButton: "button0",
+    // Check that the dialog is modal, chrome and dependent;
+    // We can't just check window.opener because that'll be
+    // a content window, which therefore isn't exposed (it'll lie and
+    // be null).
+    chrome: true,
+    dialog: true,
+    chromeDependent: true,
+    isWindowModal: true,
+  };
+  let action = {
+    buttonClick: "ok",
+  };
+  let promptDone = handlePrompt(state, action);
+  let requestPromise = makeRequest("authenticate.sjs?user=xhruser2&pass=xhrpass2&realm=xhr2");
+  await promptDone;
+  let result = await requestPromise;
 
-// clear plain HTTP auth sessions before the test, to allow
-// running them more than once.
-var authMgr = SpecialPowers.Cc["@mozilla.org/network/http-auth-manager;1"]
-                        .getService(SpecialPowers.Ci.nsIHttpAuthManager);
-authMgr.clearAll();
+  runInParent(() => {
+    const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-// start the tests
-testNum = 0;
-doTest();
+    // Check that the right tab is focused:
+    let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
+    let spec = browserWin.gBrowser.selectedBrowser.currentURI.spec;
+    assert.ok(spec.startsWith("http://mochi.test:8888"),
+              `Tab with remote URI (rather than about:blank)
+               should be focused (${spec})`);
+  });
 
-SimpleTest.waitForExplicitFinish();
+  is(result.authok, "PASS", "Checking for successful authentication");
+  is(result.username, "xhruser2", "Checking for username");
+  is(result.password, "xhrpass2", "Checking for password");
+
+  newWin.close();
+});
 </script>
 </pre>
 </body>
 </html>
deleted file mode 100644
--- a/toolkit/components/passwordmgr/test/prompt_common.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * NOTE:
- * This file is currently only being used for tests which haven't been
- * fixed to work with e10s. Favor using the `prompt_common.js` file that
- * is in `toolkit/components/prompts/test/` instead.
- */
-/* eslint-disable mozilla/use-chromeutils-generateqi */
-
-var Ci = SpecialPowers.Ci;
-ok(Ci != null, "Access Ci");
-var Cc = SpecialPowers.Cc;
-ok(Cc != null, "Access Cc");
-
-var didDialog;
-
-var timer; // keep in outer scope so it's not GC'd before firing
-function startCallbackTimer() {
-  didDialog = false;
-
-  // Delay before the callback twiddles the prompt.
-  const dialogDelay = 10;
-
-  // Use a timer to invoke a callback to twiddle the authentication dialog
-  timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-  timer.init(observer, dialogDelay, Ci.nsITimer.TYPE_ONE_SHOT);
-}
-
-
-var observer = SpecialPowers.wrapCallbackObject({
-  QueryInterface(iid) {
-    const interfaces = [Ci.nsIObserver,
-                        Ci.nsISupports, Ci.nsISupportsWeakReference];
-
-    if (!interfaces.some(function(v) {
-      return iid.equals(v);
-    })) {
-      throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
-    }
-    return this;
-  },
-
-  observe(subject, topic, data) {
-    var doc = getDialogDoc();
-    if (doc) {
-      handleDialog(doc, testNum);
-    } else {
-      startCallbackTimer();
-    } // try again in a bit
-  },
-});
-
-function getDialogDoc() {
-  // Find the <browser> which contains notifyWindow, by looking
-  // through all the open windows and all the <browsers> in each.
-  // var enumerator = SpecialPowers.Services.wm.getEnumerator("navigator:browser");
-  for (let {docShell} of SpecialPowers.Services.wm.getXULWindowEnumerator(null)) {
-    var containedDocShells = docShell.getDocShellEnumerator(
-      docShell.typeChrome,
-      docShell.ENUMERATE_FORWARDS);
-    for (let childDocShell of containedDocShells) {
-      // We don't want it if it's not done loading.
-      if (childDocShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) {
-        continue;
-      }
-      var childDoc = childDocShell.contentViewer.DOMDocument;
-
-      // ok(true, "Got window: " + childDoc.location.href);
-      if (childDoc.location.href == "chrome://global/content/commonDialog.xul") {
-        return childDoc;
-      }
-    }
-  }
-
-  return null;
-}
--- a/toolkit/components/prompts/test/chromeScript.js
+++ b/toolkit/components/prompts/test/chromeScript.js
@@ -147,16 +147,28 @@ function getPromptState(ui) {
   } else if (e.isSameNode(ui.password1Textbox.inputField)) {
     state.focused = "passField";
   } else if (ui.infoBody.isSameNode(e)) {
     state.focused = "infoBody";
   } else {
     state.focused = "ERROR: unexpected element focused: " + (e ? e.localName : "<null>");
   }
 
+  let treeOwner = ui.prompt &&
+                  ui.prompt.docShell &&
+                  ui.prompt.docShell.treeOwner;
+  if (treeOwner && treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)) {
+    let flags = treeOwner.getInterface(Ci.nsIXULWindow).chromeFlags;
+    state.chrome = (flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME) != 0;
+    state.dialog = (flags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) != 0;
+    state.chromeDependent = (flags & Ci.nsIWebBrowserChrome.CHROME_DEPENDENT) != 0;
+    let wbc = treeOwner.getInterface(Ci.nsIWebBrowserChrome);
+    state.isWindowModal = wbc.isWindowModal();
+  }
+
   return state;
 }
 
 function dismissSelect(ui, action) {
   let dialog = ui.getElementsByTagName("dialog")[0];
   let listbox = ui.getElementById("list");
 
   if (action.selectItem) {
--- a/toolkit/components/prompts/test/prompt_common.js
+++ b/toolkit/components/prompts/test/prompt_common.js
@@ -87,16 +87,29 @@ function checkPromptState(promptState, e
     is(promptState.defButton1, expectedState.defButton == "button1", "checking button1 default");
     is(promptState.defButton2, expectedState.defButton == "button2", "checking button2 default");
 
     if (isOSX && expectedState.focused && expectedState.focused.startsWith("button")) {
         is(promptState.focused, "infoBody", "buttons don't focus on OS X, but infoBody does instead");
     } else {
         is(promptState.focused, expectedState.focused, "Checking focused element");
     }
+
+    if (expectedState.hasOwnProperty("chrome")) {
+        is(promptState.chrome, expectedState.chrome, "Dialog should be opened as chrome");
+    }
+    if (expectedState.hasOwnProperty("dialog")) {
+        is(promptState.dialog, expectedState.dialog, "Dialog should be opened as a dialog");
+    }
+    if (expectedState.hasOwnProperty("chromeDependent")) {
+        is(promptState.chromeDependent, expectedState.chromeDependent, "Dialog should be opened as dependent");
+    }
+    if (expectedState.hasOwnProperty("isWindowModal")) {
+        is(promptState.isWindowModal, expectedState.isWindowModal, "Dialog should be modal");
+    }
 }
 
 function checkEchoedAuthInfo(expectedState, doc) {
     // The server echos back the HTTP auth info it received.
     let username = doc.getElementById("user").textContent;
     let password = doc.getElementById("pass").textContent;
     let authok = doc.getElementById("ok").textContent;