Bug 1526747 - Consolidate the calls to registerCleanupFunction where possible in app update's browser chrome tests. r=mhowell
authorRobert Strong <robert.bugzilla@gmail.com>
Mon, 11 Feb 2019 18:17:53 +0000
changeset 458556 6d8e6f960446fe8145ccb028d6644db879f2caa6
parent 458555 ef4325327e46517ba3cfd72a9b4e02c6ccbf9080
child 458557 b9187fa10f13a7b84f21c973d33d2fdb0f37bbb0
child 458569 c2784634bafabee48fcd70e22570568391c7187a
push id111855
push userbtara@mozilla.com
push dateMon, 11 Feb 2019 22:01:49 +0000
treeherdermozilla-inbound@42a097167d36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmhowell
bugs1526747
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 1526747 - Consolidate the calls to registerCleanupFunction where possible in app update's browser chrome tests. r=mhowell Adds a common registerCleanupFunction for all tests Moves several common test setup calls to the add_task used for common test setup Also clean up several of the comments and formatting Differential Revision: https://phabricator.services.mozilla.com/D19327
toolkit/mozapps/update/tests/browser/head.js
toolkit/mozapps/update/tests/diff_base_service.bash
--- a/toolkit/mozapps/update/tests/browser/head.js
+++ b/toolkit/mozapps/update/tests/browser/head.js
@@ -6,24 +6,26 @@
 const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AppMenuNotifications",
                                "resource://gre/modules/AppMenuNotifications.jsm");
 ChromeUtils.defineModuleGetter(this, "UpdateListener",
                                "resource://gre/modules/UpdateListener.jsm");
 
 const BIN_SUFFIX = (AppConstants.platform == "win" ? ".exe" : "");
-const FILE_UPDATER_BIN = "updater" + (AppConstants.platform == "macosx" ? ".app" : BIN_SUFFIX);
+const FILE_UPDATER_BIN =
+  "updater" + (AppConstants.platform == "macosx" ? ".app" : BIN_SUFFIX);
 const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak";
 
 const LOG_FUNCTION = info;
 
 const MAX_UPDATE_COPY_ATTEMPTS = 10;
 
-const DATA_URI_SPEC = "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/";
+const DATA_URI_SPEC =
+  "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/";
 /* import-globals-from testConstants.js */
 Services.scriptloader.loadSubScript(DATA_URI_SPEC + "testConstants.js", this);
 
 var gURLData = URL_HOST + "/" + REL_PATH_DATA;
 const URL_MANUAL_UPDATE = gURLData + "downloadPage.html";
 
 /* import-globals-from ../data/shared.js */
 Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this);
@@ -31,23 +33,58 @@ Services.scriptloader.loadSubScript(DATA
 let gOriginalUpdateAutoValue = null;
 
 // 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;
 
 /**
+ * Common tasks to perform for all tests before each one has started.
+ */
+add_task(async function setupTestCommon() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      [PREF_APP_UPDATE_LOG, gDebugTest],
+    ],
+  });
+
+  setUpdateTimerPrefs();
+  removeUpdateFiles(true);
+  // Most app update mochitest-browser-chrome tests expect auto update to be
+  // enabled. Those that don't will explicitly change this.
+  await setAppUpdateAutoEnabledHelper(true);
+});
+
+/**
+ * Common tasks to perform for all tests after each one has finished.
+ */
+registerCleanupFunction(async () => {
+  gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
+  gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
+  UpdateListener.reset();
+  reloadUpdateManagerData(true);
+  // Pass false when the log files are needed for troubleshooting the tests.
+  removeUpdateFiles(true);
+  // Always try to restore the original updater files. If none of the updater
+  // backup files are present then this is just a no-op.
+  await finishTestRestoreUpdaterBackup();
+});
+
+/**
  * Creates the continue file used to signal that update staging or the mock http
  * server should continue. The delay this creates allows the tests to verify the
- * user interfaces before they auto advance to phases of an update. The continue
- * file for staging will be deleted by the test updater and the continue file
- * for update check and update download requests will be deleted by the test
- * http server handler implemented in app_update.sjs. The test returns a promise
- * so the test can wait on the deletion of the continue file when necessary.
+ * user interfaces before they auto advance to other phases of an update. The
+ * continue file for staging will be deleted by the test updater and the
+ * continue file for the update check and update download requests will be
+ * deleted by the test http server handler implemented in app_update.sjs. The
+ * test returns a promise so the test can wait on the deletion of the continue
+ * file when necessary. If the continue file still exists at the end of a test
+ * it will be removed to prevent it from affecting tests that run after the test
+ * that created it.
  *
  * @param  leafName
  *         The leafName of the file to create. This should be one of the
  *         folowing constants that are defined in testConstants.js:
  *         CONTINUE_CHECK
  *         CONTINUE_DOWNLOAD
  *         CONTINUE_STAGING
  * @return Promise
@@ -79,16 +116,26 @@ async function continueFileHandler(leafN
       continueFile.append(continuePathParts[i]);
     }
   }
   if (continueFile.exists()) {
     throw new Error("The continue file should not exist, path: " +
                     continueFile.path);
   }
   continueFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
+  // If for whatever reason the continue file hasn't been removed when a test
+  // has finished remove it during cleanup so it doesn't affect tests that run
+  // after the test that created it.
+  registerCleanupFunction(() => {
+    if (continueFile.exists()) {
+      logTestInfo("Removing continue file during test cleanup, path: " +
+                  continueFile.path);
+      continueFile.remove(false);
+    }
+  });
   return BrowserTestUtils.waitForCondition(() =>
     (!continueFile.exists()),
     "Waiting for file to be deleted, path: " + continueFile.path,
     undefined, retries);
 }
 
 /**
  * Creates and locks the app update write test file so it is possible to test
@@ -115,16 +162,23 @@ function lockWriteTestFile() {
   file.fileAttributesWin &= ~file.WFA_READWRITE;
   registerCleanupFunction(() => {
     file.fileAttributesWin |= file.WFA_READWRITE;
     file.fileAttributesWin &= ~file.WFA_READONLY;
     file.remove(false);
   });
 }
 
+/**
+ * Closes the update mutex handle in nsUpdateService.js if it exists and then
+ * creates a new update mutex handle so the update code thinks there is another
+ * instance of the application handling updates.
+ *
+ * @throws If the function is called on a platform other than Windows.
+ */
 function setOtherInstanceHandlingUpdates() {
   if (AppConstants.platform != "win") {
     throw new Error("Windows only test function called");
   }
   gAUS.observe(null, "test-close-handle-update-mutex", "");
   let handle = createMutex(getPerInstallationMutexName());
   registerCleanupFunction(() => {
     closeHandle(handle);
@@ -142,62 +196,44 @@ function setOtherInstanceHandlingUpdates
  *         to app_update.sjs.
  */
 function getVersionParams(aAppVersion) {
   let appInfo = Services.appinfo;
   return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version);
 }
 
 /**
- * Clean up updates list and the updates directory.
- */
-function cleanUpUpdates() {
-  reloadUpdateManagerData(true);
-  removeUpdateFiles(true);
-}
-
-/**
  * Prevent nsIUpdateTimerManager from notifying nsIApplicationUpdateService
  * to check for updates by setting the app update last update time to the
  * current time minus one minute in seconds and the interval time to 12 hours
  * in seconds.
  */
 function setUpdateTimerPrefs() {
   let now = Math.round(Date.now() / 1000) - 60;
   Services.prefs.setIntPref(PREF_APP_UPDATE_LASTUPDATETIME, now);
   Services.prefs.setIntPref(PREF_APP_UPDATE_INTERVAL, 43200);
 }
 
 /*
- * In addition to changing the value of the Auto Update setting, this function
- * also takes care of cleaning up after itself.
+ * Sets the value of the App Auto Update setting and sets it back to the
+ * original value at the start of the test when the test finishes.
+ *
+ * @param  enabled
+ *         The value to set App Auto Update to.
  */
 async function setAppUpdateAutoEnabledHelper(enabled) {
   if (gOriginalUpdateAutoValue == null) {
     gOriginalUpdateAutoValue = await UpdateUtils.getAppUpdateAutoEnabled();
     registerCleanupFunction(async () => {
       await UpdateUtils.setAppUpdateAutoEnabled(gOriginalUpdateAutoValue);
     });
   }
   await UpdateUtils.setAppUpdateAutoEnabled(enabled);
 }
 
-add_task(async function setDefaults() {
-  await SpecialPowers.pushPrefEnv({
-    set: [
-      [PREF_APP_UPDATE_LOG, gDebugTest],
-      // See bug 1505790 - uses a very large value to prevent the sync code
-      // from running since it has nothing to do with these tests.
-      ["services.sync.autoconnectDelay", 600000],
-    ]});
-  // Most tests in this directory expect auto update to be enabled. Those that
-  // don't will explicitly change this.
-  await setAppUpdateAutoEnabledHelper(true);
-});
-
 /**
  * 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
@@ -206,32 +242,25 @@ add_task(async function setDefaults() {
  * @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() {
-    registerCleanupFunction(() => {
-      gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
-      UpdateListener.reset();
-      cleanUpUpdates();
-    });
-
     gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
-    setUpdateTimerPrefs();
-    removeUpdateFiles(true);
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [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);
@@ -244,66 +273,55 @@ function runUpdateTest(updateParams, che
           gAUS.checkForBackgroundUpdates();
         }
       })();
     });
 
     for (let step of steps) {
       await processStep(step);
     }
-
-    await finishTestRestoreUpdaterBackup();
   })();
 }
 
 /**
  * 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() {
-    registerCleanupFunction(() => {
-      gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
-      UpdateListener.reset();
-      cleanUpUpdates();
-    });
-
     gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "1");
-    setUpdateTimerPrefs();
-    removeUpdateFiles(true);
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
         [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);
     }
-
-    await finishTestRestoreUpdaterBackup();
   })();
 }
 
 function processStep(step) {
   if (typeof(step) == "function") {
     return step();
   }
 
@@ -361,17 +379,18 @@ function waitForEvent(topic, status = nu
  *         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`);
+  let notification =
+    win.document.getElementById(`appMenu-${notificationId}-notification`);
   is(notification.hidden, false, `${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.
@@ -487,19 +506,21 @@ function copyTestUpdater(attempt = 0) {
         await TestUtils.waitForTick();
         await copyTestUpdater(attempt++);
       }
     }
   })();
 }
 
 /**
- * Restores the updater that was backed up. This is called in setupTestUpdater
- * before the backup of the real updater is done in case the previous test
- * failed to restore the updater when the test has finished.
+ * Restores the updater and updater related file that if there a backup exists.
+ * This is called in setupTestUpdater before the backup of the real updater is
+ * done in case the previous test failed to restore the file when a test has
+ * finished. This is also called in finishTestRestoreUpdaterBackup to restore
+ * the files when a test finishes.
  */
 function restoreUpdaterBackup() {
   let greBinDir = getGREBinDir();
   let updater = greBinDir.clone();
   let updaterBackup = greBinDir.clone();
   updater.append(FILE_UPDATER_BIN);
   updaterBackup.append(FILE_UPDATER_BIN_BAK);
   if (updaterBackup.exists()) {
@@ -533,33 +554,31 @@ function restoreUpdaterBackup() {
   } else if (precomplete.exists()) {
     if (readFile(precomplete) == PRECOMPLETE_CONTENTS) {
       precomplete.remove(false);
     }
   }
 }
 
 /**
- * When a staging test finishes this will repeatedly attempt to restore the real
- * updater.
+ * When a test finishes this will repeatedly attempt to restore the real updater
+ * and the other files for the updater if a backup of the file exists.
  */
 function finishTestRestoreUpdaterBackup() {
   return (async function() {
-    if (Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED)) {
-      try {
-        // Windows debug builds keep the updater file in use for a short period of
-        // time after the updater process exits.
-        restoreUpdaterBackup();
-      } catch (e) {
-        logTestInfo("Attempt to restore the backed up updater failed... " +
-                    "will try again, Exception: " + e);
+    try {
+      // Windows debug builds keep the updater file in use for a short period of
+      // time after the updater process exits.
+      restoreUpdaterBackup();
+    } catch (e) {
+      logTestInfo("Attempt to restore the backed up updater failed... " +
+                  "will try again, Exception: " + e);
 
-        await TestUtils.waitForTick();
-        await finishTestRestoreUpdaterBackup();
-      }
+      await TestUtils.waitForTick();
+      await finishTestRestoreUpdaterBackup();
     }
   })();
 }
 
 /**
  * Waits for the About Dialog to load.
  *
  * @return A promise that returns the domWindow for the About Dialog and
@@ -570,17 +589,18 @@ function waitForAboutDialog() {
     var listener = {
       onOpenWindow: aXULWindow => {
         debugDump("About dialog shown...");
         Services.wm.removeListener(listener);
 
          async function aboutDialogOnLoad() {
           domwindow.removeEventListener("load", aboutDialogOnLoad, true);
           let chromeURI = "chrome://browser/content/aboutDialog.xul";
-          is(domwindow.document.location.href, chromeURI, "About dialog appeared");
+          is(domwindow.document.location.href, chromeURI,
+             "About dialog appeared");
           resolve(domwindow);
         }
 
         var domwindow = aXULWindow.docShell.domWindow;
         domwindow.addEventListener("load", aboutDialogOnLoad, true);
       },
       onCloseWindow: aXULWindow => {},
     };
@@ -659,49 +679,35 @@ function runAboutDialogUpdateTest(update
         if (panelId != "apply") {
           buttonEl.click();
         }
       }
     })();
   }
 
   return (async function() {
+    gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_SERVICE_ENABLED, false],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_URL_MANUAL, detailsURL],
       ],
     });
-    registerCleanupFunction(() => {
-      gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
-      UpdateListener.reset();
-      cleanUpUpdates();
-    });
-
-    gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
-    setUpdateTimerPrefs();
-    removeUpdateFiles(true);
 
     await setupTestUpdater();
-    registerCleanupFunction(async () => {
-      await finishTestRestoreUpdaterBackup();
-    });
 
     let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
                     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");
-        registerCleanupFunction(() => {
-          gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
-        });
       }
       setUpdateURL(updateURL);
       gAUS.checkForBackgroundUpdates();
       await waitForEvent("update-downloaded");
     } else {
       updateURL += "&slowUpdateCheck=1&useSlowDownloadMar=1";
       setUpdateURL(updateURL);
     }
@@ -738,17 +744,18 @@ function runAboutPrefsUpdateTest(updateP
   let tab;
   function processAboutPrefsStep(step) {
     if (typeof(step) == "function") {
       return step();
     }
 
     const {panelId, checkActiveUpdate, continueFile} = step;
     return (async function() {
-      await ContentTask.spawn(tab.linkedBrowser, {panelId}, async ({panelId}) => {
+      await ContentTask.spawn(tab.linkedBrowser, {panelId},
+                              async ({panelId}) => {
         let updateDeck = content.document.getElementById("updateDeck");
         await ContentTaskUtils.waitForCondition(() =>
           (updateDeck.selectedPanel && updateDeck.selectedPanel.id == panelId),
           "Waiting for expected panel ID - got: \"" +
           updateDeck.selectedPanel.id + "\", expected \"" + panelId + "\"");
         is(updateDeck.selectedPanel.id, panelId,
            "The panel ID should equal " + panelId);
       });
@@ -761,17 +768,18 @@ function runAboutPrefsUpdateTest(updateP
         ok(!gUpdateManager.activeUpdate,
            "There should not be an active update");
       }
 
       if (continueFile) {
         await continueFileHandler(continueFile);
       }
 
-      await ContentTask.spawn(tab.linkedBrowser, {panelId, detailsURL}, async ({panelId, detailsURL}) => {
+      await ContentTask.spawn(tab.linkedBrowser, {panelId, detailsURL},
+                              async ({panelId, detailsURL}) => {
         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";
@@ -782,75 +790,63 @@ function runAboutPrefsUpdateTest(updateP
           }
           let link = selectedPanel.querySelector(selector);
           is(link.href, detailsURL,
              "The panel's link href should equal the expected value");
         }
 
         let buttonPanels = ["downloadAndInstall", "apply"];
         if (buttonPanels.includes(panelId)) {
-          let selectedPanel = content.document.getElementById("updateDeck").selectedPanel;
+          let selectedPanel =
+            content.document.getElementById("updateDeck").selectedPanel;
           let buttonEl = selectedPanel.querySelector("button");
           // Note: The about:preferences doesn't focus the button like the
           // About Dialog does.
           ok(!buttonEl.disabled, "The button should be enabled");
-          // Don't click the button on the apply panel since this will restart the
-          // application.
+          // Don't click the button on the apply panel since this will restart
+          // the application.
           if (selectedPanel.id != "apply") {
             buttonEl.click();
           }
         }
       });
     })();
   }
 
   return (async function() {
+    gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
     await SpecialPowers.pushPrefEnv({
       set: [
         [PREF_APP_UPDATE_SERVICE_ENABLED, false],
         [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
         [PREF_APP_UPDATE_URL_MANUAL, detailsURL],
       ],
     });
-    registerCleanupFunction(() => {
-      gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "");
-      UpdateListener.reset();
-      cleanUpUpdates();
-    });
-
-    gEnv.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
-    setUpdateTimerPrefs();
-    removeUpdateFiles(true);
 
     await setupTestUpdater();
-    registerCleanupFunction(async () => {
-      await finishTestRestoreUpdaterBackup();
-    });
 
     let updateURL = URL_HTTP_UPDATE_SJS + "?detailsURL=" + detailsURL +
                     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");
-        registerCleanupFunction(() => {
-          gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
-        });
       }
       setUpdateURL(updateURL);
       gAUS.checkForBackgroundUpdates();
       await waitForEvent("update-downloaded");
     } else {
       updateURL += "&slowUpdateCheck=1&useSlowDownloadMar=1";
       setUpdateURL(updateURL);
     }
 
-    tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
+    tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
+                                                      "about:preferences");
     registerCleanupFunction(async () => {
       await BrowserTestUtils.removeTab(tab);
     });
 
     for (let step of steps) {
       await processAboutPrefsStep(step);
     }
   })();
--- a/toolkit/mozapps/update/tests/diff_base_service.bash
+++ b/toolkit/mozapps/update/tests/diff_base_service.bash
@@ -104,9 +104,10 @@ marStageSuccessCompleteSvc.js
 marStageSuccessPartial.js
 marStageSuccessPartialSvc.js
 
 marSuccessComplete.js
 marSuccessCompleteSvc.js
 
 marSuccessPartial.js
 marSuccessPartialSvc.js
+
 END