Bug 1546597 - Fixes for the Doorhanger BITS download failure tests. r=bytesized
authorRobert Strong <robert.bugzilla@gmail.com>
Mon, 29 Apr 2019 21:48:48 +0000
changeset 530650 7f757830df66f7dd2a865da304fbd45dee6921a9
parent 530649 7b2d2da6fba84a364a07fc273a6447c5dfd22a06
child 530651 fc1bc4be406596533e3ce90de530a7e0b139e5c0
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbytesized
bugs1546597
milestone68.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 1546597 - Fixes for the Doorhanger BITS download failure tests. r=bytesized Makes the last 10 doorhanger tests that download updates also run using BITS to download updates. Replaces the two functions for doorhanger tests with a new function and changes the doorhanger tests so they use it. Added an optional checkInterval to the update object for startup processing tests that submit telemetry to fix a telemetry warning. Turned off UpdateService logging for debugging since these tests have been very stable. Differential Revision: https://phabricator.services.mozilla.com/D29253
toolkit/mozapps/update/tests/browser/browser.bits.ini
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js
toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js
toolkit/mozapps/update/tests/browser/head.js
toolkit/mozapps/update/tests/data/sharedUpdateXML.js
--- a/toolkit/mozapps/update/tests/browser/browser.bits.ini
+++ b/toolkit/mozapps/update/tests/browser/browser.bits.ini
@@ -39,20 +39,30 @@ prefs =
 [browser_aboutPrefs_fc_patch_completeBadSize.js]
 [browser_aboutPrefs_fc_patch_partialBadSize.js]
 [browser_aboutPrefs_fc_patch_partialBadSize_complete.js]
 [browser_aboutPrefs_fc_patch_partialBadSize_completeBadSize.js]
 
 # Doorhanger Application Update Tests
 [browser_doorhanger_bc_downloaded.js]
 [browser_doorhanger_bc_downloaded_staged.js]
+[browser_doorhanger_bc_downloadAutoFailures.js]
+[browser_doorhanger_bc_downloadAutoFailures_bgWin.js]
 [browser_doorhanger_bc_downloadOptIn.js]
+[browser_doorhanger_bc_downloadOptIn_bgWin.js]
 [browser_doorhanger_bc_downloadOptIn_staging.js]
+[browser_doorhanger_bc_patch_completeBadSize.js]
+[browser_doorhanger_bc_patch_partialBadSize.js]
+[browser_doorhanger_bc_patch_partialBadSize_complete.js]
+[browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js]
+[browser_doorhanger_sp_patch_completeApplyFailure.js]
+[browser_doorhanger_sp_patch_partialApplyFailure.js]
 [browser_doorhanger_sp_patch_partialApplyFailure_complete.js]
 [browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js]
+[browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js]
 
 # Telemetry Application Update Tests
 [browser_telemetry_completeBadSize.js]
 [browser_telemetry_partialBadSize_completeBadSize.js]
 [browser_telemetry_complete_stageFailure.js]
 [browser_telemetry_partial_stageFailure_complete_stageFailure.js]
 [browser_telemetry_complete_applyFailure.js]
 [browser_telemetry_partial_applyFailure_complete_applyFailure.js]
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_cantApply.js
@@ -1,19 +1,19 @@
-add_task(async function testBasicPrompt() {
-  SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_SERVICE_ENABLED, false]]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_check_cantApply() {
   lockWriteTestFile();
 
-  let updateParams = "promptWaitTime=0";
-
-  await runUpdateTest(updateParams, 1, [
+  let updateParams = "&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-manual",
       button: "button",
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDetailsURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_check_malformedXML.js
@@ -1,28 +1,26 @@
-add_task(async function testMalformedXml() {
-  const updateDetailsUrl = "http://example.com/details";
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_check_malformedXML() {
   const maxBackgroundErrors = 10;
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
-    [PREF_APP_UPDATE_URL_DETAILS, updateDetailsUrl],
-  ]});
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
+    ],
+  });
 
-  let updateParams = "xmlMalformed=1";
-
-  await runUpdateTest(updateParams, maxBackgroundErrors, [
+  let updateParams = "&xmlMalformed=1";
+  await runDoorhangerUpdateTest(updateParams, maxBackgroundErrors, [
     {
-      // if we fail 10 check attempts, then we want to just show the user a manual update
-      // workflow.
+      // If the update check fails 10 consecutive attempts then the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new", updateDetailsUrl);
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDetailsURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures.js
@@ -1,30 +1,40 @@
-add_task(async function testDownloadFailures() {
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_downloadAutoFailures() {
   const maxBackgroundErrors = 5;
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
-  ]});
-  let updateParams = "badURL=1";
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
+    ],
+  });
 
-  await runUpdateTest(updateParams, 1, [
+  let updateParams = "&badURL=1";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
-      // if we fail maxBackgroundErrors download attempts, then we want to
-      // first show the user an update available prompt.
+      // If the update download fails maxBackgroundErrors download attempts then
+      // show the update available prompt.
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadAutoFailures_bgWin.js
@@ -1,46 +1,54 @@
-add_task(async function testBackgroundWindowFailures() {
-  const maxBackgroundErrors = 5;
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
-  ]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  let updateParams = "badURL=1";
-  let extraWindow = await BrowserTestUtils.openNewBrowserWindow();
-  await SimpleTest.promiseFocus(extraWindow);
+"use strict";
 
+add_task(async function doorhanger_bc_downloadAutoFailures_bgWin() {
   function getBackgroundWindowHandler(destroyWindow) {
     return async function() {
       await TestUtils.waitForCondition(() =>
         PanelUI.menuButton.hasAttribute("badge-status"),
         "Background window has a badge.");
       is(PanelUI.notificationPanel.state, "closed",
          "The doorhanger is not showing for the background window");
       is(PanelUI.menuButton.getAttribute("badge-status"), "update-available",
          "The badge is showing for the background window");
 
-      checkWhatsNewLink(extraWindow, "update-available-whats-new");
-      let buttonEl = getNotificationButton(extraWindow, "update-available", "button");
+      checkWhatsNewLink(extraWindow, "update-available-whats-new",
+                        gDefaultWhatsNewURL);
+      let buttonEl =
+        getNotificationButton(extraWindow, "update-available", "button");
       buttonEl.click();
 
       if (destroyWindow) {
         await BrowserTestUtils.closeWindow(extraWindow);
         await SimpleTest.promiseFocus(window);
       }
     };
   }
 
-  await runUpdateTest(updateParams, 1, [
+  const maxBackgroundErrors = 5;
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
+    ],
+  });
+
+  let extraWindow = await BrowserTestUtils.openNewBrowserWindow();
+  await SimpleTest.promiseFocus(extraWindow);
+
+  let updateParams = "&badURL=1";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     getBackgroundWindowHandler(false),
     getBackgroundWindowHandler(true),
     {
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn.js
@@ -1,25 +1,23 @@
-add_task(async function testBasicPromptNoStaging() {
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_STAGING_ENABLED, false],
-  ]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_downloadOptIn() {
   await UpdateUtils.setAppUpdateAutoEnabled(false);
 
-  let updateParams = "promptWaitTime=0";
-
-  await runUpdateTest(updateParams, 1, [
+  let updateParams = "&invalidCompleteSize=1&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-available",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-available-whats-new");
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_PENDING},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_bgWin.js
@@ -1,38 +1,44 @@
-add_task(async function testUpdatesBackgroundWindow() {
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_STAGING_ENABLED, false],
-  ]});
-  await UpdateUtils.setAppUpdateAutoEnabled(false);
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  let updateParams = "promptWaitTime=0";
-  let extraWindow = await BrowserTestUtils.openNewBrowserWindow();
-  await SimpleTest.promiseFocus(extraWindow);
+"use strict";
 
-  await runUpdateTest(updateParams, 1, [
-    async function() {
+add_task(async function doorhanger_bc_downloadOptIn_bgWin() {
+  function getBackgroundWindowHandler() {
+    return async function() {
       await TestUtils.waitForCondition(() =>
         PanelUI.menuButton.hasAttribute("badge-status"),
         "Background window has a badge.");
       is(PanelUI.notificationPanel.state, "closed",
          "The doorhanger is not showing for the background window");
       is(PanelUI.menuButton.getAttribute("badge-status"), "update-available",
          "The badge is showing for the background window");
-      let popupShownPromise = BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
+      let popupShownPromise =
+        BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
       await BrowserTestUtils.closeWindow(extraWindow);
       await SimpleTest.promiseFocus(window);
       await popupShownPromise;
 
-      checkWhatsNewLink(window, "update-available-whats-new");
-      let buttonEl = getNotificationButton(window, "update-available", "button");
+      checkWhatsNewLink(window, "update-available-whats-new",
+                        gDefaultWhatsNewURL);
+      let buttonEl =
+        getNotificationButton(window, "update-available", "button");
       buttonEl.click();
-    },
+    };
+  }
+
+  await UpdateUtils.setAppUpdateAutoEnabled(false);
+
+  let extraWindow = await BrowserTestUtils.openNewBrowserWindow();
+  await SimpleTest.promiseFocus(extraWindow);
+
+  let updateParams = "&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
+    getBackgroundWindowHandler(),
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_PENDING},
     },
   ]);
 });
-
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloadOptIn_staging.js
@@ -1,25 +1,28 @@
-add_task(async function testBasicPrompt() {
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_STAGING_ENABLED, true],
-  ]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_downloadOptIn_staging() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_STAGING_ENABLED, true],
+    ],
+  });
   await UpdateUtils.setAppUpdateAutoEnabled(false);
 
-  let updateParams = "promptWaitTime=0";
-
-  await runUpdateTest(updateParams, 1, [
+  let updateParams = "&invalidCompleteSize=1&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-available",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-available-whats-new");
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_APPLIED},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded.js
@@ -1,13 +1,15 @@
-add_task(async function testCompleteAndPartialPatchesWithBadCompleteSize() {
-  let updateParams = "invalidCompleteSize=1&promptWaitTime=0";
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  await runUpdateTest(updateParams, 1, [
+"use strict";
+
+add_task(async function doorhanger_bc_downloaded() {
+  let updateParams = "&invalidCompleteSize=1&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_PENDING},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_downloaded_staged.js
@@ -1,16 +1,21 @@
-add_task(async function testCompleteAndPartialPatchesWithBadCompleteSize() {
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_STAGING_ENABLED, true],
-  ]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
 
-  let updateParams = "invalidCompleteSize=1&promptWaitTime=0";
-  await runUpdateTest(updateParams, 1, [
+add_task(async function doorhanger_bc_downloaded_staged() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_STAGING_ENABLED, true],
+    ],
+  });
+
+  let updateParams = "&invalidCompleteSize=1&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_APPLIED},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_completeBadSize.js
@@ -1,31 +1,33 @@
-add_task(async function testCompletePatchWithBadCompleteSize() {
-  let updateParams = "completePatchOnly=1&invalidCompleteSize=1";
-  await runUpdateTest(updateParams, 1, [
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_patch_completeBadSize() {
+  let updateParams = "&completePatchOnly=1&invalidCompleteSize=1";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
-      // if we fail maxBackgroundErrors download attempts, then we want to
-      // first show the user an update available prompt.
+      // If the update download fails maxBackgroundErrors download attempts then
+      // show the update available prompt.
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize.js
@@ -1,31 +1,33 @@
-add_task(async function testPartialPatchWithBadPartialSize() {
-  let updateParams = "partialPatchOnly=1&invalidPartialSize=1";
-  await runUpdateTest(updateParams, 1, [
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_patch_partialBadSize() {
+  let updateParams = "&partialPatchOnly=1&invalidPartialSize=1";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
-      // if we fail maxBackgroundErrors download attempts, then we want to
-      // first show the user an update available prompt.
+      // If the update download fails maxBackgroundErrors download attempts then
+      // show the update available prompt.
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_complete.js
@@ -1,13 +1,15 @@
-add_task(async function testCompleteAndPartialPatchesWithBadPartialSize() {
-  let updateParams = "invalidPartialSize=1&promptWaitTime=0";
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-  await runUpdateTest(updateParams, 1, [
+"use strict";
+
+add_task(async function doorhanger_bc_patch_partialBadSize_complete() {
+  let updateParams = "&invalidPartialSize=1&promptWaitTime=0";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_PENDING},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_bc_patch_partialBadSize_completeBadSize.js
@@ -1,31 +1,33 @@
-add_task(async function testCompleteAndPartialPatchesWithBadSizes() {
-  let updateParams = "invalidPartialSize=1&invalidCompleteSize=1";
-  await runUpdateTest(updateParams, 1, [
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_bc_patch_partialBadSize_completeBadSize() {
+  let updateParams = "&invalidPartialSize=1&invalidCompleteSize=1";
+  await runDoorhangerUpdateTest(updateParams, 1, [
     {
-      // if we fail maxBackgroundErrors download attempts, then we want to
-      // first show the user an update available prompt.
+      // If the update download fails maxBackgroundErrors download attempts then
+      // show the update available prompt.
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
       notificationId: "update-available",
       button: "button",
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL},
     },
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_completeApplyFailure.js
@@ -1,24 +1,25 @@
-add_task(async function testCompletePatchApplyFailure() {
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_sp_patch_completeApplyFailure() {
   let patchProps = {state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
-  let updates = getLocalUpdateString({}, patches);
+  let updateProps = {checkInterval: "1"};
+  let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
-  await runUpdateProcessingTest(updates, [
+  let updateParams = "";
+  await runDoorhangerUpdateTest(updateParams, 0, [
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If the update process is unable to install the update show the manual
+      // update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure.js
@@ -1,26 +1,26 @@
-add_task(async function testPartialPatchApplyFailure() {
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_sp_patch_partialApplyFailure() {
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
-  let updateProps = {isCompleteUpdate: "false"};
+  let updateProps = {isCompleteUpdate: "false",
+                     checkInterval: "1"};
   let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
-  await runUpdateProcessingTest(updates, [
+  let updateParams = "";
+  await runDoorhangerUpdateTest(updateParams, 0, [
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If there is only an invalid patch show the manual update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete.js
@@ -1,20 +1,25 @@
-add_task(async function testPartialPatchApplyFailureWithCompleteAvailable() {
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_sp_patch_partialApplyFailure_complete() {
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {selected: "false"};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false",
                      promptWaitTime: "0"};
   let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
-  await runUpdateProcessingTest(updates, [
+  let updateParams = "";
+  await runDoorhangerUpdateTest(updateParams, 0, [
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_PENDING},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_completeBadSize.js
@@ -1,37 +1,36 @@
-add_task(async function testPartialPatchApplyFailureWithCompleteValidationFailure() {
-  // because of the way we're simulating failure, we have to just pretend we've already
-  // retried.
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_sp_patch_partialApplyFailure_completeBadSize() {
+  // Because of the way the test is simulating failure it has to pretend it has
+  // already retried.
   await SpecialPowers.pushPrefEnv({
     set: [
       [PREF_APP_UPDATE_DOWNLOAD_MAXATTEMPTS, 0],
     ],
   });
 
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {size: "1234",
                 selected: "false"};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false"};
   let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
-  await runUpdateProcessingTest(updates, [
+  let updateParams = "";
+  await runDoorhangerUpdateTest(updateParams, 0, [
     {
-      // if we have only an invalid patch, then something's wrong and we don't
-      // have an automatic way to fix it, so show the manual update
-      // doorhanger.
+      // If there is only an invalid patch show the manual update doorhanger.
       notificationId: "update-manual",
       button: "button",
-      beforeClick() {
-        checkWhatsNewLink(window, "update-manual-whats-new");
-      },
-      async cleanup() {
-        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
-        is(gBrowser.selectedBrowser.currentURI.spec,
-           URL_MANUAL_UPDATE, "Landed on manual update page.");
-        gBrowser.removeTab(gBrowser.selectedTab);
-      },
+      checkActiveUpdate: null,
+      pageURLs: {whatsNew: gDefaultWhatsNewURL,
+                 manual: URL_MANUAL_UPDATE},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js
+++ b/toolkit/mozapps/update/tests/browser/browser_doorhanger_sp_patch_partialApplyFailure_complete_staging.js
@@ -1,24 +1,31 @@
-add_task(async function testPartialPatchApplyFailureWithCompleteAvailable() {
-  SpecialPowers.pushPrefEnv({set: [
-    [PREF_APP_UPDATE_STAGING_ENABLED, true],
-  ]});
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function doorhanger_sp_patch_partialApplyFailure_complete_staging() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_STAGING_ENABLED, true],
+    ],
+  });
 
   let patchProps = {type: "partial",
                     state: STATE_PENDING};
   let patches = getLocalPatchString(patchProps);
   patchProps = {selected: "false"};
   patches += getLocalPatchString(patchProps);
   let updateProps = {isCompleteUpdate: "false",
                      promptWaitTime: "0"};
   let updates = getLocalUpdateString(updateProps, patches);
+  writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
 
-  await runUpdateProcessingTest(updates, [
+  let updateParams = "";
+  await runDoorhangerUpdateTest(updateParams, 0, [
     {
       notificationId: "update-restart",
       button: "secondaryButton",
-      cleanup() {
-        AppMenuNotifications.removeNotification(/.*/);
-      },
+      checkActiveUpdate: {state: STATE_APPLIED},
     },
   ]);
 });
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -29,20 +29,25 @@ const URL_MANUAL_UPDATE = gURLData + "do
 
 const gBadSizeResult = Cr.NS_ERROR_UNEXPECTED.toString();
 
 /* import-globals-from ../data/shared.js */
 Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this);
 
 let gOriginalUpdateAutoValue = null;
 
+// Some elements append a trailing /. After the chrome tests are removed this
+// code can be changed so URL_HOST already has a trailing /.
+const gDetailsURL = URL_HOST + "/";
+const gDefaultWhatsNewURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS";
+
 // Set to true to log additional information for debugging. To log additional
-// information for individual tests set gDebugTest to false here and to true in
-// the test's onload function.
-gDebugTest = true;
+// information for individual tests set gDebugTest to false here and to true
+// globally in the test.
+gDebugTest = false;
 
 // This is to accommodate the TV task which runs the tests with --verify.
 requestLongerTimeout(10);
 
 /**
  * Common tasks to perform for all tests before each one has started.
  */
 add_task(async function setupTestCommon() {
@@ -241,172 +246,48 @@ async function setAppUpdateAutoEnabledHe
     registerCleanupFunction(async () => {
       await UpdateUtils.setAppUpdateAutoEnabled(gOriginalUpdateAutoValue);
     });
   }
   await UpdateUtils.setAppUpdateAutoEnabled(enabled);
 }
 
 /**
- * Runs a typical update test. Will set various common prefs for using the
- * updater doorhanger, runs the provided list of steps, and makes sure
- * everything is cleaned up afterwards.
- *
- * @param  updateParams
- *         Params which will be sent to app_update.sjs.
- * @param  checkAttempts
- *         How many times to check for updates. Useful for testing the UI
- *         for check failures.
- * @param  steps
- *         A list of test steps to perform, specifying expected doorhangers
- *         and additional validation/cleanup callbacks.
- * @return A promise which will resolve once all of the steps have been run
- *         and cleanup has been performed.
- */
-function runUpdateTest(updateParams, checkAttempts, steps) {
-  return (async function() {
-    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
-    await SpecialPowers.pushPrefEnv({
-      set: [
-        [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
-        [PREF_APP_UPDATE_IDLETIME, 0],
-        [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
-      ],
-    });
-
-    await setupTestUpdater();
-
-    let url = URL_HTTP_UPDATE_SJS +
-              "?" + updateParams +
-              getVersionParams();
-
-    setUpdateURL(url);
-
-    executeSoon(() => {
-      (async function() {
-        gAUS.checkForBackgroundUpdates();
-        for (var i = 0; i < checkAttempts - 1; i++) {
-          await waitForEvent("update-error", "check-attempt-failed");
-          gAUS.checkForBackgroundUpdates();
-        }
-      })();
-    });
-
-    for (let step of steps) {
-      await processStep(step);
-    }
-  })();
-}
-
-/**
- * Runs a test which processes an update. Similar to runUpdateTest.
- *
- * @param  updates
- *         A list of updates to process.
- * @param  steps
- *         A list of test steps to perform, specifying expected doorhangers
- *         and additional validation/cleanup callbacks.
- * @return A promise which will resolve once all of the steps have been run
- *         and cleanup has been performed.
- */
-function runUpdateProcessingTest(updates, steps) {
-  return (async function() {
-    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
-    await SpecialPowers.pushPrefEnv({
-      set: [
-        [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
-        [PREF_APP_UPDATE_IDLETIME, 0],
-        [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
-      ],
-    });
-
-    await setupTestUpdater();
-
-    writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-    writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
-    writeStatusFile(STATE_FAILED_CRC_ERROR);
-    reloadUpdateManagerData();
-
-    testPostUpdateProcessing();
-
-    for (let step of steps) {
-      await processStep(step);
-    }
-  })();
-}
-
-function processStep(step) {
-  if (typeof(step) == "function") {
-    return step();
-  }
-
-  const {notificationId, button, beforeClick, cleanup} = step;
-  return (async function() {
-    await BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
-    const shownNotification = AppMenuNotifications.activeNotification.id;
-
-    is(shownNotification, notificationId, "The right notification showed up.");
-    if (shownNotification != notificationId) {
-      if (cleanup) {
-        await cleanup();
-      }
-      return;
-    }
-
-    let buttonEl = getNotificationButton(window, notificationId, button);
-    if (beforeClick) {
-      await beforeClick();
-    }
-
-
-    buttonEl.click();
-
-    if (cleanup) {
-      await cleanup();
-    }
-  })();
-}
-
-/**
  * Gets the specified button for the notification.
  *
  * @param  win
  *         The window to get the notification button for.
  * @param  notificationId
  *         The ID of the notification to get the button for.
  * @param  button
  *         The anonid of the button to get.
  * @return The button element.
  */
 function getNotificationButton(win, notificationId, button) {
   let notification =
     win.document.getElementById(`appMenu-${notificationId}-notification`);
-  is(notification.hidden, false, `${notificationId} notification is showing`);
+  ok(!notification.hidden, `${notificationId} notification is showing`);
   return notification[button];
 }
 
 /**
  * Ensures that the "What's new" link with the provided ID is displayed and
- * matches the url parameter provided. If no URL is provided, it will instead
- * ensure that the link matches the default link URL.
+ * matches the url parameter provided.
  *
  * @param  win
  *         The window to get the "What's new" link for.
  * @param  id
  *         The ID of the "What's new" link element.
- * @param  url (optional)
- *         The URL to check against. If none is provided, a default will be used.
+ * @param  url
+ *         The URL to check against.
  */
 function checkWhatsNewLink(win, id, url) {
   let whatsNewLink = win.document.getElementById(id);
-  is(whatsNewLink.href,
-     url || URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS",
-     "What's new link points to the test_details URL");
-  is(whatsNewLink.hidden, false, "What's new link is not hidden.");
+  ok(!whatsNewLink.hidden, "What's new link is not hidden.");
+  is(whatsNewLink.href, url, `What's new link href should equal ${url}`);
 }
 
 /**
  * For staging tests the test updater must be used and this restores the backed
  * up real updater if it exists and tries again on failure since Windows debug
  * builds at times leave the file in use. After success moveRealUpdater is
  * called to continue the setup of the test updater.
  */
@@ -620,33 +501,125 @@ function getPatchOfType(type) {
         return patch;
       }
     }
   }
   return null;
 }
 
 /**
+ * Runs a Doorhanger update test. This will set various common prefs for
+ * updating and runs the provided list of steps.
+ *
+ * @param  updateParams
+ *         Params which will be sent to app_update.sjs.
+ * @param  checkAttempts
+ *         How many times to check for updates. Useful for testing the UI
+ *         for check failures. If this is 0 then a startup processing test will
+ *         be performed.
+ * @param  steps
+ *         An array of test steps to perform. A step will either be an object
+ *         containing expected conditions and actions or a function to call.
+ * @return A promise which will resolve once all of the steps have been run.
+ */
+function runDoorhangerUpdateTest(updateParams, checkAttempts, steps) {
+  function processDoorhangerStep(step) {
+    if (typeof(step) == "function") {
+      return step();
+    }
+
+    const {notificationId, button, checkActiveUpdate, pageURLs} = step;
+    return (async function() {
+      await BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
+      const shownNotificationId = AppMenuNotifications.activeNotification.id;
+      is(shownNotificationId, notificationId,
+         "The right notification showed up.");
+
+      if (checkActiveUpdate) {
+        ok(!!gUpdateManager.activeUpdate,
+           "There should be an active update");
+        is(gUpdateManager.activeUpdate.state, checkActiveUpdate.state,
+           `The active update state should equal ${checkActiveUpdate.state}`);
+      } else {
+        ok(!gUpdateManager.activeUpdate,
+           "There should not be an active update");
+      }
+
+      if (pageURLs && pageURLs.whatsNew !== undefined) {
+        checkWhatsNewLink(window, `${notificationId}-whats-new`,
+                          pageURLs.whatsNew);
+      }
+
+      let buttonEl = getNotificationButton(window, notificationId, button);
+      buttonEl.click();
+
+      if (pageURLs && pageURLs.manual !== undefined) {
+        await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+        is(gBrowser.selectedBrowser.currentURI.spec, pageURLs.manual,
+           `The page's url should equal ${pageURLs.manual}`);
+        gBrowser.removeTab(gBrowser.selectedTab);
+      }
+    })();
+  }
+
+  return (async function() {
+    gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
+    await SpecialPowers.pushPrefEnv({
+      set: [
+        [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
+        [PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
+        [PREF_APP_UPDATE_URL_DETAILS, gDetailsURL],
+      ],
+    });
+
+    await setupTestUpdater();
+
+    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + gDetailsURL +
+                    updateParams + getVersionParams();
+    setUpdateURL(updateURL);
+
+    if (checkAttempts) {
+      // Perform a background check doorhanger test.
+      executeSoon(() => {
+        (async function() {
+          gAUS.checkForBackgroundUpdates();
+          for (var i = 0; i < checkAttempts - 1; i++) {
+            await waitForEvent("update-error", "check-attempt-failed");
+            gAUS.checkForBackgroundUpdates();
+          }
+        })();
+      });
+    } else {
+      // Perform a startup processing doorhanger test.
+      reloadUpdateManagerData();
+      writeStatusFile(STATE_FAILED_CRC_ERROR);
+      testPostUpdateProcessing();
+    }
+
+    for (let step of steps) {
+      await processDoorhangerStep(step);
+    }
+  })();
+}
+
+/**
  * Runs an About Dialog update test. This will set various common prefs for
  * updating and runs the provided list of steps.
  *
  * @param  updateParams
  *         Params which will be sent to app_update.sjs.
  * @param  backgroundUpdate
  *         If true a background check will be performed before opening the About
  *         Dialog.
  * @param  steps
  *         An array of test steps to perform. A step will either be an object
  *         containing expected conditions and actions or a function to call.
  * @return A promise which will resolve once all of the steps have been run.
  */
 function runAboutDialogUpdateTest(updateParams, backgroundUpdate, steps) {
-  // Some elements append a trailing /. After the chrome tests are removed this
-  // code can be changed so URL_HOST already has a trailing /.
-  let detailsURL = URL_HOST + "/";
   let aboutDialog;
   function processAboutDialogStep(step) {
     if (typeof(step) == "function") {
       return step();
     }
 
     const {panelId, checkActiveUpdate, continueFile, downloadInfo} = step;
     return (async function() {
@@ -703,18 +676,18 @@ function runAboutDialogUpdateTest(update
       }
 
       let linkPanels = ["downloadFailed", "manualUpdate", "unsupportedSystem"];
       if (linkPanels.includes(panelId)) {
         // The unsupportedSystem panel uses the update's detailsURL and the
         // downloadFailed and manualUpdate panels use the app.update.url.manual
         // preference.
         let link = selectedPanel.querySelector("label.text-link");
-        is(link.href, detailsURL,
-           "The panel's link href should equal the expected value");
+        is(link.href, gDetailsURL,
+           `The panel's link href should equal ${gDetailsURL}`);
       }
 
       let buttonPanels = ["downloadAndInstall", "apply"];
       if (buttonPanels.includes(panelId)) {
         let buttonEl = selectedPanel.querySelector("button");
         await TestUtils.waitForCondition(() =>
           (aboutDialog.document.activeElement == buttonEl),
           "The button should receive focus");
@@ -728,23 +701,23 @@ function runAboutDialogUpdateTest(update
     })();
   }
 
   return (async function() {
     gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
-        [PREF_APP_UPDATE_URL_MANUAL, detailsURL],
+        [PREF_APP_UPDATE_URL_MANUAL, gDetailsURL],
       ],
     });
 
     await setupTestUpdater();
 
-    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
+    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + gDetailsURL +
                     updateParams + getVersionParams();
     if (backgroundUpdate) {
       if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
         // Since MOZ_TEST_SKIP_UPDATE_STAGE is checked before
         // MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
         // for the continue file to continue staging the update.
         gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
       }
@@ -777,19 +750,16 @@ function runAboutDialogUpdateTest(update
  *         If true a background check will be performed before opening the About
  *         Dialog.
  * @param  steps
  *         An array of test steps to perform. A step will either be an object
  *         containing expected conditions and actions or a function to call.
  * @return A promise which will resolve once all of the steps have been run.
  */
 function runAboutPrefsUpdateTest(updateParams, backgroundUpdate, steps) {
-  // Some elements append a trailing /. After the chrome tests are removed this
-  // code can be changed so URL_HOST already has a trailing /.
-  let detailsURL = URL_HOST + "/";
   let tab;
   function processAboutPrefsStep(step) {
     if (typeof(step) == "function") {
       return step();
     }
 
     const {panelId, checkActiveUpdate, continueFile, downloadInfo} = step;
     return (async function() {
@@ -843,34 +813,34 @@ function runAboutPrefsUpdateTest(updateP
                "The patch property " + resultName + " value should equal " +
                info[resultName]);
           }
         }
       } else if (continueFile) {
         await continueFileHandler(continueFile);
       }
 
-      await ContentTask.spawn(tab.linkedBrowser, {panelId, detailsURL},
-                              async ({panelId, detailsURL}) => {
+      await ContentTask.spawn(tab.linkedBrowser, {panelId, gDetailsURL},
+                              async ({panelId, gDetailsURL}) => {
         let linkPanels = ["downloadFailed", "manualUpdate", "unsupportedSystem"];
         if (linkPanels.includes(panelId)) {
           let selectedPanel =
             content.document.getElementById("updateDeck").selectedPanel;
           // The unsupportedSystem panel uses the update's detailsURL and the
           // downloadFailed and manualUpdate panels use the app.update.url.manual
           // preference.
           let selector = "label.text-link";
           // The downloadFailed panel in about:preferences uses an anchor
           // instead of a label for the link.
           if (selectedPanel.id == "downloadFailed") {
             selector = "a.text-link";
           }
           let link = selectedPanel.querySelector(selector);
-          is(link.href, detailsURL,
-             "The panel's link href should equal the expected value");
+          is(link.href, gDetailsURL,
+             `The panel's link href should equal ${gDetailsURL}`);
         }
 
         let buttonPanels = ["downloadAndInstall", "apply"];
         if (buttonPanels.includes(panelId)) {
           let selectedPanel =
             content.document.getElementById("updateDeck").selectedPanel;
           let buttonEl = selectedPanel.querySelector("button");
           // Note: The about:preferences doesn't focus the button like the
@@ -886,23 +856,23 @@ function runAboutPrefsUpdateTest(updateP
     })();
   }
 
   return (async function() {
     gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
-        [PREF_APP_UPDATE_URL_MANUAL, detailsURL],
+        [PREF_APP_UPDATE_URL_MANUAL, gDetailsURL],
       ],
     });
 
     await setupTestUpdater();
 
-    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
+    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + gDetailsURL +
                     updateParams + getVersionParams();
     if (backgroundUpdate) {
       if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
         // Since MOZ_TEST_SKIP_UPDATE_STAGE is checked before
         // MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
         // for the continue file to continue staging the update.
         gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
       }
@@ -954,35 +924,32 @@ function removeUpdateSettingsIni() {
  * @param  event
  *         The observer notification to wait for before proceeding.
  * @param  stageFailure (optional)
  *         Whether to force a staging failure by removing the modified
  *         update-settings.ini file.
  * @return A promise which will resolve after the .
  */
 function runTelemetryUpdateTest(updateParams, event, stageFailure = false) {
-  // Some elements append a trailing /. After the chrome tests are removed this
-  // code can be changed so URL_HOST already has a trailing /.
-  let detailsURL = URL_HOST + "/";
   return (async function() {
     Services.telemetry.clearScalars();
     gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
       ],
     });
 
     await setupTestUpdater();
 
     if (stageFailure) {
       removeUpdateSettingsIni();
     }
 
-    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
+    let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + gDetailsURL +
                     updateParams + getVersionParams();
     setUpdateURL(updateURL);
     if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
       // Since MOZ_TEST_SKIP_UPDATE_STAGE is checked before
       // MOZ_TEST_SLOW_SKIP_UPDATE_STAGE in updater.cpp this removes the need
       // for the continue file to continue staging the update.
       gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
     }
--- a/toolkit/mozapps/update/tests/data/sharedUpdateXML.js
+++ b/toolkit/mozapps/update/tests/data/sharedUpdateXML.js
@@ -239,30 +239,33 @@ function getLocalUpdateString(aUpdatePro
     statusText: "Install Pending",
     type: "major",
   };
 
   for (let name in aUpdateProps) {
     updateProps[name] = aUpdateProps[name];
   }
 
+  let checkInterval = updateProps.checkInterval ?
+    "checkInterval=\"" + updateProps.checkInterval + "\" " : "";
   let channel = "channel=\"" + updateProps.channel + "\" ";
   let isCompleteUpdate =
     "isCompleteUpdate=\"" + updateProps.isCompleteUpdate + "\" ";
   let foregroundDownload = updateProps.foregroundDownload ?
     "foregroundDownload=\"" + updateProps.foregroundDownload + "\" " : "";
   let installDate = "installDate=\"" + updateProps.installDate + "\" ";
   let previousAppVersion = updateProps.previousAppVersion ?
     "previousAppVersion=\"" + updateProps.previousAppVersion + "\" " : "";
   let statusText = updateProps.statusText ?
     "statusText=\"" + updateProps.statusText + "\" " : "";
   let serviceURL = "serviceURL=\"" + updateProps.serviceURL + "\">";
 
   return getUpdateString(updateProps) +
          " " +
+         checkInterval +
          channel +
          isCompleteUpdate +
          foregroundDownload +
          installDate +
          previousAppVersion +
          statusText +
          serviceURL +
          aPatches +