Part 7 - Bug 951662 - add mock update directory for tests, remove code that is no longer needed, and test cleanup. r=bbondy
authorRobert Strong <robert.bugzilla@gmail.com>
Sun, 12 Jan 2014 13:46:29 -0800
changeset 163067 cc647e2ac09288d06b7e4eec5a3321900791f29d
parent 163066 5e6a9cff371c565227cdf8f1fd17e18e7859ac25
child 163068 b04e74ae3cb7bd3c477749899f60c8598c9f49d4
push id25979
push usercbook@mozilla.com
push dateMon, 13 Jan 2014 11:46:02 +0000
treeherdermozilla-central@ea6657f1d682 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs951662
milestone29.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
Part 7 - Bug 951662 - add mock update directory for tests, remove code that is no longer needed, and test cleanup. r=bbondy
toolkit/mozapps/update/tests/shared.js
toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js
toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js
toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js
toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
toolkit/mozapps/update/tests/unit_aus_update/head_update.js
toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js
toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js
toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js
toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js
toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js
toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marDirLockedStageFailure_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js
toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js
toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateStageSuccessSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateSuccessSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppStageSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marCallbackAppSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marDirLockedStageFailureSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFailurePartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseFallbackStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseStageSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFallbackStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseFallbackStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseStageSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseSuccessPartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marStageFailurePartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marStageSuccessPartialSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marSuccessCompleteSvc.js
toolkit/mozapps/update/tests/unit_service_updater/marSuccessPartialSvc.js
--- a/toolkit/mozapps/update/tests/shared.js
+++ b/toolkit/mozapps/update/tests/shared.js
@@ -53,28 +53,39 @@ const NS_APP_USER_PROFILE_50_DIR   = "Pr
 const NS_GRE_DIR                   = "GreD";
 const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
 const XRE_EXECUTABLE_FILE          = "XREExeF";
 const XRE_UPDATE_ROOT_DIR          = "UpdRootD";
 
 const CRC_ERROR   = 4;
 const WRITE_ERROR = 7;
 
-const DIR_UPDATED                    = "updated";
+const DIR_PATCH                      = "0";
+const DIR_UPDATES                    = "updates";
+#ifdef XP_MACOSX
+const DIR_APP_REL_PATH = "/Contents/MacOS/";
+const DIR_APP_SUFFIX = ".app";
+const DIR_UPDATED = "Updated.app";
+#else
+const DIR_APP_REL_PATH = "/appdir/";
+const DIR_APP_SUFFIX = "";
+const DIR_UPDATED = "updated";
+#endif
+
 const FILE_BACKUP_LOG                = "backup-update.log";
 const FILE_LAST_LOG                  = "last-update.log";
+const FILE_UPDATER_INI               = "updater.ini";
+const FILE_UPDATES_DB                = "updates.xml";
 const FILE_UPDATE_ACTIVE             = "active-update.xml";
 const FILE_UPDATE_ARCHIVE            = "update.mar";
 const FILE_UPDATE_LOG                = "update.log";
 const FILE_UPDATE_SETTINGS_INI       = "update-settings.ini";
 const FILE_UPDATE_SETTINGS_INI_BAK   = "update-settings.ini.bak";
 const FILE_UPDATE_STATUS             = "update.status";
 const FILE_UPDATE_VERSION            = "update.version";
-const FILE_UPDATER_INI               = "updater.ini";
-const FILE_UPDATES_DB                = "updates.xml";
 
 const UPDATE_SETTINGS_CONTENTS = "[Settings]\n" +
                                  "ACCEPTED_MAR_CHANNEL_IDS=xpcshell-test\n"
 
 const PR_RDWR        = 0x04;
 const PR_CREATE_FILE = 0x08;
 const PR_APPEND      = 0x10;
 const PR_TRUNCATE    = 0x20;
@@ -221,60 +232,62 @@ function writeUpdatesToXMLFile(aContent,
  * Writes the current update operation/state to a file in the patch
  * directory, indicating to the patching system that operations need
  * to be performed.
  *
  * @param  aStatus
  *         The status value to write.
  */
 function writeStatusFile(aStatus) {
-  var file = getUpdatesDir();
-  file.append("0");
+  let file = getUpdatesPatchDir();
   file.append(FILE_UPDATE_STATUS);
-  aStatus += "\n";
-  writeFile(file, aStatus);
+  writeFile(file, aStatus + "\n");
 }
 
 /**
  * Writes the current update version to a file in the patch directory,
  * indicating to the patching system the version of the update.
  *
  * @param  aVersion
  *         The version value to write.
  */
 function writeVersionFile(aVersion) {
-  var file = getUpdatesDir();
-  file.append("0");
+  let file = getUpdatesPatchDir();
   file.append(FILE_UPDATE_VERSION);
-  aVersion += "\n";
-  writeFile(file, aVersion);
+  writeFile(file, aVersion + "\n");
 }
 
 /**
- * Gets the updates root directory.
+ * Gets the root directory for the updates directory.
  *
  * @return nsIFile for the updates root directory.
  */
 function getUpdatesRootDir() {
-  try {
-    return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, AUS_Ci.nsIFile);
-  } catch (e) {
-    // Fall back on the current process directory
-    return getCurrentProcessDir();
-  }
+  return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, AUS_Ci.nsIFile);
 }
 
 /**
  * Gets the updates directory.
  *
  * @return nsIFile for the updates directory.
  */
 function getUpdatesDir() {
   var dir = getUpdatesRootDir();
-  dir.append("updates");
+  dir.append(DIR_UPDATES);
+  return dir;
+}
+
+/**
+ * Gets the directory for update patches.
+ *
+ * @return nsIFile for the updates directory.
+ */
+function getUpdatesPatchDir() {
+  let dir = getUpdatesDir();
+  dir.append(DIR_PATCH);
   return dir;
 }
 
 /**
  * Writes text to a file. This will replace existing text if the file exists
  * and create the file if it doesn't exist.
  *
  * @param  aFile
@@ -289,39 +302,54 @@ function writeFile(aFile, aText) {
   if (!aFile.exists())
     aFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
   fos.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
   fos.write(aText, aText.length);
   fos.close();
 }
 
 /**
- * Reads the current update operation/state in a file in the patch
- * directory.
+ * Reads the current update operation/state in the status file in the patch
+ * directory including the error code if it is present.
  *
- * @param  aFile (optional)
- *         nsIFile to read the update status from. If not provided the
- *         application's update status file will be used.
  * @return The status value.
  */
-function readStatusFile(aFile) {
-  var file;
-  if (aFile) {
-    file = aFile.clone();
-    file.append(FILE_UPDATE_STATUS);
+function readStatusFile() {
+  let file = getUpdatesPatchDir();
+  file.append(FILE_UPDATE_STATUS);
+
+  if (!file.exists()) {
+    logTestInfo("update status file does not exists! Path: " + file.path);
+    return STATE_NONE;
   }
-  else {
-    file = getUpdatesDir();
-    file.append("0");
-    file.append(FILE_UPDATE_STATUS);
-  }
+
   return readFile(file).split("\n")[0];
 }
 
 /**
+ * Reads the current update operation/state in the status file in the patch
+ * directory without the error code if it is present.
+ *
+ * @return The state value.
+ */
+function readStatusState() {
+  return readStatusFile().split(": ")[0];
+}
+
+/**
+ * Reads the current update operation/state in the status file in the patch
+ * directory with the error code.
+ *
+ * @return The state value.
+ */
+function readStatusFailedCode() {
+  return readStatusFile().split(": ")[1];
+}
+
+/**
  * Reads text from a file and returns the string.
  *
  * @param  aFile
  *         The file to read from.
  * @return The string of text read from the file.
  */
 function readFile(aFile) {
   var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
@@ -369,18 +397,17 @@ function readFileBytes(aFile) {
 function getStatusText(aErrCode) {
   return getString("check_error-" + aErrCode);
 }
 
 /* Returns a string from the updates.properties bundle */
 function getString(aName) {
   try {
     return gUpdateBundle.GetStringFromName(aName);
-  }
-  catch (e) {
+  } catch (e) {
   }
   return null;
 }
 
 /**
  * Gets the file extension for an nsIFile.
  *
  * @param  aFile
@@ -398,39 +425,36 @@ function getFileExtension(aFile) {
  * This prevents some tests from failing due to files being left behind when the
  * tests are interrupted.
  */
 function removeUpdateDirsAndFiles() {
   var file = getUpdatesXMLFile(true);
   try {
     if (file.exists())
       file.remove(false);
-  }
-  catch (e) {
-    dump("Unable to remove file\npath: " + file.path +
+  } catch (e) {
+    dump("Unable to remove file\nPath: " + file.path +
          "\nException: " + e + "\n");
   }
 
   file = getUpdatesXMLFile(false);
   try {
     if (file.exists())
       file.remove(false);
-  }
-  catch (e) {
-    dump("Unable to remove file\npath: " + file.path +
+  } catch (e) {
+    dump("Unable to remove file\nPath: " + file.path +
          "\nException: " + e + "\n");
   }
 
   // This fails sporadically on Mac OS X so wrap it in a try catch
   var updatesDir = getUpdatesDir();
   try {
     cleanUpdatesDir(updatesDir);
-  }
-  catch (e) {
-    dump("Unable to remove files / directories from directory\npath: " +
+  } catch (e) {
+    dump("Unable to remove files / directories from directory\nPath: " +
          updatesDir.path + "\nException: " + e + "\n");
   }
 }
 
 /**
  * Removes all files and sub-directories in the updates directory except for
  * the "0" sub-directory.
  *
@@ -441,98 +465,93 @@ function cleanUpdatesDir(aDir) {
   if (!aDir.exists())
     return;
 
   var dirEntries = aDir.directoryEntries;
   while (dirEntries.hasMoreElements()) {
     var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
 
     if (entry.isDirectory()) {
-      if (entry.leafName == "0" && entry.parent.leafName == "updates") {
+      if (entry.leafName == DIR_PATCH && entry.parent.leafName == DIR_UPDATES) {
         cleanUpdatesDir(entry);
         entry.permissions = PERMS_DIRECTORY;
-      }
-      else {
+      } else {
         try {
           entry.remove(true);
           return;
-        }
-        catch (e) {
+        } catch (e) {
         }
         cleanUpdatesDir(entry);
         entry.permissions = PERMS_DIRECTORY;
         try {
           entry.remove(true);
-        }
-        catch (e) {
-          dump("cleanUpdatesDir: unable to remove directory\npath: " +
+        } catch (e) {
+          dump("cleanUpdatesDir: unable to remove directory\nPath: " +
                entry.path + "\nException: " + e + "\n");
           throw(e);
         }
       }
-    }
-    else {
+    } else {
       entry.permissions = PERMS_FILE;
       try {
         entry.remove(false);
-      }
-      catch (e) {
-        dump("cleanUpdatesDir: unable to remove file\npath: " + entry.path +
+      } catch (e) {
+        dump("cleanUpdatesDir: unable to remove file\nPath: " + entry.path +
              "\nException: " + e + "\n");
         throw(e);
       }
     }
   }
 }
 
 /**
  * Deletes a directory and its children. First it tries nsIFile::Remove(true).
  * If that fails it will fall back to recursing, setting the appropriate
  * permissions, and deleting the current entry.
  *
  * @param  aDir
  *         nsIFile for the directory to be deleted.
  */
 function removeDirRecursive(aDir) {
-  if (!aDir.exists())
+  if (!aDir.exists()) {
     return;
+  }
+
   try {
+    logTestInfo("attempting to remove directory. Path: " + aDir.path);
     aDir.remove(true);
     return;
-  }
-  catch (e) {
+  } catch (e) {
+    logTestInfo("non-fatal error removing directory. Exception: " + e);
   }
 
   var dirEntries = aDir.directoryEntries;
   while (dirEntries.hasMoreElements()) {
     var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
 
     if (entry.isDirectory()) {
       removeDirRecursive(entry);
-    }
-    else {
+    } else {
       entry.permissions = PERMS_FILE;
       try {
+        logTestInfo("attempting to remove file. Path: " + entry.path);
         entry.remove(false);
-      }
-      catch (e) {
-        dump("removeDirRecursive: unable to remove file\npath: " + entry.path +
-             "\nException: " + e + "\n");
+      } catch (e) {
+        logTestInfo("error removing file. Exception: " + e);
         throw(e);
       }
     }
   }
 
   aDir.permissions = PERMS_DIRECTORY;
   try {
+    logTestInfo("attempting to remove directory. Path: " + aDir.path);
     aDir.remove(true);
-  }
-  catch (e) {
-    dump("removeDirRecursive: unable to remove directory\npath: " + entry.path +
-         "\nException: " + e + "\n");
+  } catch (e) {
+    logTestInfo("error removing directory. Exception: " + e);
     throw(e);
   }
 }
 
 /**
  * Returns the directory for the currently running process. This is used to
  * clean up after the tests and to locate the active-update.xml and updates.xml
  * files.
@@ -561,26 +580,27 @@ function getAppBaseDir() {
  * @return nsIFile for the Gecko Runtime Engine directory.
  */
 function getGREDir() {
   return Services.dirsvc.get(NS_GRE_DIR, AUS_Ci.nsIFile);
 }
 
 /**
  * Get the "updated" directory inside the directory where we apply the
- * background updates.
+ * staged updates.
  * @return The active updates directory inside the updated directory, as a
  *         nsIFile object.
  */
 function getUpdatedDir() {
   let dir = getAppBaseDir();
 #ifdef XP_MACOSX
   dir = dir.parent.parent; // the bundle directory
 #endif
   dir.append(DIR_UPDATED);
+  logTestInfo("updated directory path: " + dir.path);
   return dir;
 }
 
 /**
  * Logs TEST-INFO messages.
  *
  * @param  aText
  *         The text to log.
--- a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   // Verify write access to the custom app dir
   logTestInfo("testing write access to the application directory");
   var testFile = getCurrentProcessDir();
   testFile.append("update_write_access_test");
   testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
   do_check_true(testFile.exists());
   testFile.remove(false);
@@ -20,12 +20,8 @@ function run_test() {
   // Check if available updates can be checked for
   logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates");
   do_check_true(gAUS.canCheckForUpdates);
   // Check if updates can be applied
   logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates");
   do_check_true(gAUS.canApplyUpdates);
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
@@ -1,17 +1,17 @@
 /* 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/.
  */
 
 /* General Update Manager Tests */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing removal of an active update for a channel that is not" +
               "valid due to switching channels (Bug 486275).");
 
   var patches, updates, update;
   patches = getLocalPatchString(null, null, null, null, null, null,
                                 STATE_DOWNLOADING);
   updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0");
@@ -37,12 +37,8 @@ function run_test() {
   // Verify that the active-update.xml file has had the update from the old
   // channel removed.
   file = getUpdatesXMLFile(true);
   logTestInfo("verifying contents of " + FILE_UPDATE_ACTIVE);
   do_check_eq(readFile(file), getLocalUpdatesXMLString(""));
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
@@ -1,16 +1,16 @@
 /* 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/.
  */
 
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing cleanup of an update download in progress for an " +
               "older version of the application on startup (Bug 485624)");
 
   var patches, updates;
 
   patches = getLocalPatchString(null, null, null, null, null, null,
                                 STATE_DOWNLOADING);
@@ -29,12 +29,8 @@ function run_test() {
     do_check_neq(gUpdateManager.activeUpdate, null);
   } else {
     do_check_eq(gUpdateManager.activeUpdate, null);
   }
   do_check_eq(gUpdateManager.updateCount, 0);
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing removal of an update download in progress for the " +
               "same version of the application with the same application " +
               "build id on startup (Bug 536547)");
 
   var patches, updates;
 
   patches = getLocalPatchString(null, null, null, null, null, null,
@@ -30,12 +30,8 @@ function run_test() {
     do_check_neq(gUpdateManager.activeUpdate, null);
   } else {
     do_check_eq(gUpdateManager.activeUpdate, null);
   }
   do_check_eq(gUpdateManager.updateCount, 0);
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing update cleanup when reading the status file returns " +
               "STATUS_NONE and the update xml has an update with " +
               "STATE_DOWNLOADING (Bug 539717).");
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   var patches = getLocalPatchString(null, null, null, null, null, null,
                                     STATE_DOWNLOADING);
@@ -30,12 +30,8 @@ function run_test() {
 
   logTestInfo("testing activeUpdate == null");
   do_check_eq(gUpdateManager.activeUpdate, null);
   logTestInfo("testing updateCount == 0");
   do_check_eq(gUpdateManager.updateCount, 0);
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing update cleanup when reading the status file returns " +
               "STATUS_NONE, the version file is for a newer version, and the " +
               "update xml has an update with STATE_PENDING (Bug 601701).");
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   var patches = getLocalPatchString(null, null, null, null, null, null,
                                     STATE_PENDING);
@@ -32,12 +32,8 @@ function run_test() {
 
   var versionFile = dir.clone();
   versionFile.append(FILE_UPDATE_VERSION);
   logTestInfo("testing " + versionFile.path + " should not exist");
   do_check_false(versionFile.exists());
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing that the update.log is moved after a successful update");
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   var patches = getLocalPatchString(null, null, null, null, null, null,
                                     STATE_PENDING);
   var updates = getLocalUpdateString(patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
@@ -40,12 +40,8 @@ function run_test() {
   do_check_false(log.exists());
 
   dir.append("0");
   logTestInfo("testing " + dir.path + " should exist (bug 512994)");
   do_check_true(dir.exists());
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing update logs are first in first out deleted");
 
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   var patches = getLocalPatchString(null, null, null, null, null, null,
                                     STATE_PENDING);
   var updates = getLocalUpdateString(patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
@@ -51,12 +51,8 @@ function run_test() {
   do_check_eq(readFile(log), "Backup Update Log");
 
   dir.append("0");
   logTestInfo("testing " + dir.path + " should exist (bug 512994)");
   do_check_true(dir.exists());
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js
@@ -2,17 +2,20 @@
  * 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/.
  */
 
 var gNextRunFunc;
 var gExpectedStatusResult;
 
 function run_test() {
-  setupTestCommon(true);
+  // This test needs access to omni.ja to read the update.locale file so don't
+  // use a custom directory for the application directory.
+  gUseTestAppDir = false;
+  setupTestCommon();
 
   logTestInfo("testing mar download and mar hash verification");
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
   // The HTTP server is only used for the mar file downloads since it is slow
   start_httpserver();
   setUpdateURLOverride(gURLData + "update.xml");
   // The mock XMLHttpRequest is MUCH faster
@@ -21,31 +24,26 @@ function run_test() {
   do_execute_soon(run_test_pt1);
 }
 
 // The HttpServer must be stopped before calling do_test_finished
 function finish_test() {
   stop_httpserver(do_test_finished);
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 // Callback function used by the custom XMLHttpRequest implementation to
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   gXHR.status = 400;
   gXHR.responseText = gResponseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
-  }
-  catch(e) {
+  } catch(e) {
   }
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 // Helper function for testing mar downloads that have the correct size
 // specified in the update xml.
 function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) {
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
@@ -1,21 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing download a complete on partial failure. Calling " +
               "nsIUpdatePrompt::showUpdateError should call getNewPrompter " +
               "and alert on the object returned by getNewPrompter when the " +
               "update.state == " + STATE_FAILED + " and the update.errorCode " +
               "== " + WRITE_ERROR + " (Bug 595059).");
 
+  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
+
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                             "Fake Window Watcher",
                             "@mozilla.org/embedcomp/window-watcher;1",
                             WindowWatcherFactory);
 
   standardInit();
 
@@ -36,17 +38,16 @@ function run_test() {
                  createInstance(AUS_Ci.nsIUpdatePrompt);
   prompter.showUpdateError(update);
 }
 
 function end_test() {
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                               WindowWatcherFactory);
-  cleanupTestCommon();
 }
 
 var WindowWatcher = {
   getNewPrompter: function(aParent) {
     do_check_eq(aParent, null);
     return {
       alert: function(aTitle, aText) {
         let title = getString("updaterIOErrorTitle");
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadFileTooBig_gonk.js
@@ -18,17 +18,17 @@ FakeDirProvider.prototype = {
         gActiveUpdate.errorCode = AUS_Cr.NS_ERROR_FILE_TOO_BIG;
       }
     }
     return null;
   }
 };
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   setUpdateURLOverride();
   overrideXHR(xhr_pt1);
   standardInit();
 
   logTestInfo("testing that error codes set from a directory provider propagate" +
               "up to AUS.downloadUpdate() correctly (Bug 794211).");
 
@@ -48,18 +48,17 @@ function run_test() {
 
 function xhr_pt1() {
   gXHR.status = 200;
   gXHR.responseText = gResponseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
-  }
-  catch(e) {
+  } catch (e) {
     gXHR.responseXML = null;
   }
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 function run_test_pt1() {
   gUpdates = null;
@@ -86,11 +85,9 @@ function check_test_pt1() {
 }
 
 function end_test() {
   gDirService.unregisterProvider(gDirProvider);
   gDirService.registerProvider(gOldProvider);
   gActiveUpdate = null;
   gDirService = null;
   gDirProvider = null;
-
-  cleanupTestCommon();
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedByOfflineRetry.js
@@ -2,17 +2,17 @@
  * 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/.
  */
 
 // Needs to be in sync w/ nsUpdateService.js
 const NETWORK_ERROR_OFFLINE = 111;
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing when an update check fails because the network is " +
               "offline that we check again when the network comes online " +
               "(Bug 794211).");
 
   setUpdateURLOverride();
   Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false);
 
@@ -59,24 +59,20 @@ function xhr_pt2() {
   var responseBody = getLocalUpdatesXMLString(updates);
 
   gXHR.status = 200;
   gXHR.responseText = responseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(responseBody, "application/xml");
+  } catch (e) {
   }
-  catch(e) { }
   gXHR.onload({ target: gXHR });
 }
 
 function check_test_pt2(update) {
   // We just verify that there are updates to know the check succeeded.
   do_check_neq(update, null);
   do_check_eq(update.name, "App Update Test");
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
@@ -11,17 +11,17 @@ var gIncrementalDownloadClassID, gIncOld
 // gIncrementalDownloadErrorType is used to loop through each of the connection
 // error types in the Mock incremental downloader.
 var gIncrementalDownloadErrorType = 0;
 
 var gNextRunFunc;
 var gExpectedStatusResult;
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing mar downloads, mar hash verification, and " +
               "mar download interrupted recovery");
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
   // The HTTP server is only used for the mar file downloads since it is slow
   start_httpserver();
   setUpdateURLOverride(gURLData + "update.xml");
@@ -33,30 +33,28 @@ function run_test() {
 
 // The HttpServer must be stopped before calling do_test_finished
 function finish_test() {
   stop_httpserver(do_test_finished);
 }
 
 function end_test() {
   cleanupMockIncrementalDownload();
-  cleanupTestCommon();
 }
 
 // Callback function used by the custom XMLHttpRequest implementation to
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   gXHR.status = 400;
   gXHR.responseText = gResponseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
-  }
-  catch(e) {
+  } catch (e) {
   }
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 // Helper function for testing mar downloads that have the correct size
 // specified in the update xml.
 function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) {
--- a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing resuming an update download in progress for the same " +
               "version of the application on startup (Bug 485624)");
 
   var patches, updates;
 
   patches = getLocalPatchString(null, null, null, null, null, null,
                                 STATE_DOWNLOADING);
@@ -35,12 +35,8 @@ function run_test() {
   // xpcom-shutdown which will leave behind the test directory.
   gAUS.pauseDownload();
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   reloadUpdateManagerData();
 
   do_timeout(TEST_CHECK_TIMEOUT, do_test_finished);
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
@@ -1,16 +1,30 @@
 /* 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/. */
 
 const INSTALL_LOCALE = "@AB_CD@";
-const APP_BIN_NAME = "@MOZ_APP_NAME@";
+const MOZ_APP_NAME = "@MOZ_APP_NAME@";
 const BIN_SUFFIX = "@BIN_SUFFIX@";
 
+#ifdef XP_WIN
+// MOZ_APP_VENDOR is optional.
+// On Windows, if MOZ_APP_VENDOR is not defined the updates directory will be
+// located under %LOCALAPPDATA%\@MOZ_APP_BASENAME@\updates\TaskBarID
+#ifdef MOZ_APP_VENDOR
+const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@";
+#else
+const MOZ_APP_VENDOR = "";
+#endif
+
+// MOZ_APP_BASENAME is not optional for tests.
+const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@";
+#endif // XP_WIN
+
 const APP_INFO_NAME = "XPCShell";
 const APP_INFO_VENDOR = "Mozilla";
 
 #ifdef XP_UNIX
 const APP_BIN_SUFFIX = "-bin";
 #else
 const APP_BIN_SUFFIX = "@BIN_SUFFIX@";
 #endif
@@ -61,24 +75,17 @@ const USE_EXECV = IS_UNIX && !IS_MACOSX;
 #ifdef MOZ_VERIFY_MAR_SIGNATURE
 const IS_MAR_CHECKS_ENABLED = true;
 #else
 const IS_MAR_CHECKS_ENABLED = false;
 #endif
 
 const URL_HOST = "http://localhost";
 
-const APPLY_TO_DIR_SUFFIX = "_applyToDir/";
-const UPDATES_DIR_SUFFIX = "_mar";
-#ifdef XP_MACOSX
-const UPDATED_DIR_SUFFIX = "Updated.app/";
-#else
-const UPDATED_DIR_SUFFIX = "updated/";
-#endif
-
+const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX;
 const FILE_COMPLETE_MAR = "complete.mar";
 const FILE_COMPLETE_WIN_MAR = "complete_win.mar";
 const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX;
 const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe";
 const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe";
 const FILE_OLD_VERSION_MAR = "old_version.mar";
 const FILE_PARTIAL_MAR = "partial.mar";
 const FILE_PARTIAL_WIN_MAR = "partial_win.mar";
@@ -90,19 +97,16 @@ const LOG_COMPLETE_SUCCESS = "complete_l
 const LOG_COMPLETE_SWITCH_SUCCESS = "complete_log_switch_success"
 const LOG_COMPLETE_CC_SUCCESS = "complete_cc_log_success";
 const LOG_COMPLETE_CC_SWITCH_SUCCESS = "complete_cc_log_switch_success";
 
 const LOG_PARTIAL_SUCCESS = "partial_log_success";
 const LOG_PARTIAL_SWITCH_SUCCESS = "partial_log_switch_success";
 const LOG_PARTIAL_FAILURE = "partial_log_failure";
 
-const ERR_CALLBACK_FILE_IN_USE = "NS_main: file in use - failed to " +
-                                 "exclusively open executable file:"
-
 const ERR_RENAME_FILE = "rename_file: failed to rename file";
 const ERR_UNABLE_OPEN_DEST = "unable to open destination file";
 const ERR_BACKUP_DISCARD = "backup_discard: unable to remove";
 
 const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result.";
 
 // All we care about is that the last modified time has changed so that Mac OS
 // X Launch Services invalidates its cache so the test allows up to one minute
@@ -117,19 +121,21 @@ const TEST_CHECK_TIMEOUT = 100;
 
 // How many of TEST_CHECK_TIMEOUT to wait before we abort the test.
 const MAX_TIMEOUT_RUNS = 1000;
 
 // Maximum number of milliseconds the process that is launched can run before
 // the test will try to kill it.
 const APP_TIMER_TIMEOUT = 120000;
 
-// Use a copy of the main application executable for the test to avoid main
-// executable in use errors.
-const FILE_WIN_TEST_EXE = "_aus_test_app.exe";
+#ifdef XP_WIN
+const PIPE_TO_NULL = "1> nul 2>&1";
+#else
+const PIPE_TO_NULL = "> /dev/null 2>&1";
+#endif
 
 // This default value will be overridden when using the http server.
 var gURLData = URL_HOST + "/";
 
 var gTestID;
 
 var gTestserver;
 
@@ -144,25 +150,45 @@ var gResponseBody;
 var gResponseStatusCode = 200;
 var gRequestURL;
 var gUpdateCount;
 var gUpdates;
 var gStatusCode;
 var gStatusText;
 var gStatusResult;
 
-// Variables are used instead of contants so tests can override these values
+var gProcess;
+var gAppTimer;
+var gHandle;
+
+var gGREDirOrig;
+var gAppDirOrig;
+
+var gServiceLaunchedCallbackLog = null;
+var gServiceLaunchedCallbackArgs = null;
+
+// Variables are used instead of contants so tests can override these values if
+// necessary.
 var gCallbackBinFile = "callback_app" + BIN_SUFFIX;
 var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
-var gBackgroundUpdate = false;
+var gStageUpdate = false;
 var gSwitchApp = false;
 var gDisableReplaceFallback = false;
+var gUseTestAppDir = true;
 
 var gTimeoutRuns = 0;
 
+// Environment related globals
+var gShouldResetEnv = undefined;
+var gAddedEnvXRENoWindowsCrashDialog = false;
+var gEnvXPCOMDebugBreak;
+var gEnvXPCOMMemLeakLog;
+var gEnvDyldLibraryPath;
+var gEnvLdLibraryPath;
+
 /**
  * The mar files used for the updater tests contain the following remove
  * operations.
  *
  * partial and complete test mar remove operations
  * -----------------------------------------------
  * remove "text1"
  * remove "text0"
@@ -326,49 +352,88 @@ var DEBUG_AUS_TEST = true;
 #ifdef MOZ_MAINTENANCE_SERVICE
 const STATE_APPLIED_PLATFORM = STATE_APPLIED_SVC;
 #else
 const STATE_APPLIED_PLATFORM = STATE_APPLIED;
 #endif
 
 // This makes it possible to run most tests on xulrunner where the update
 // channel default preference is not set.
-if (APP_BIN_NAME == "xulrunner") {
+if (MOZ_APP_NAME == "xulrunner") {
   try {
     gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
-  }
-  catch (e) {
+  } catch (e) {
     setUpdateChannel("test_channel");
   }
 }
 
-function setupTestCommon(aAdjustGeneralPaths) {
+/**
+ * Helper function for setting up the test environment.
+ */
+function setupTestCommon() {
   do_test_pending();
 
   if (gTestID) {
     do_throw("should only be called once!");
   }
 
   let caller = Components.stack.caller;
   gTestID = caller.filename.toString().split("/").pop().split(".")[0];
 
-  if (aAdjustGeneralPaths) {
-     // adjustGeneralPaths registers a cleanup function that calls end_test.
-     adjustGeneralPaths();
+  // Don't attempt to show a prompt when an update finishes.
+  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
+
+  gGREDirOrig = getGREDir();
+  gAppDirOrig = getAppBaseDir();
+
+  let applyDir = getApplyDirFile(null, true).parent;
+  if (IS_MACOSX) {
+    applyDir = applyDir.parent;
   }
 
+  // Try to remove the directory used to apply updates. Since the test hasn't
+  // ran yet and the directory shouldn't exist finished this is non-fatal for
+  // the test.
+  if (applyDir.exists()) {
+    logTestInfo("attempting to remove directory. Path: " + applyDir.path);
+    try {
+      removeDirRecursive(applyDir);
+    } catch (e) {
+      logTestInfo("non-fatal error removing directory. Path: " +
+                  applyDir.path + ", Exception: " + e);
+    }
+  }
+
+  // adjustGeneralPaths registers a cleanup function that calls end_test when
+  // it is defined as a function.
+  adjustGeneralPaths();
+
   removeUpdateDirsAndFiles();
+
+  // Try to remove the directory used to apply updates. Since the test hasn't
+  // ran yet and the directory shouldn't exist finished this is non-fatal for
+  // the test.
+  let updatesDir = getMockUpdRootD();
+  if (updatesDir.exists())  {
+    logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
+    try {
+      removeDirRecursive(updatesDir);
+    } catch (e) {
+      logTestInfo("non-fatal error removing directory. Path: " +
+                  updatesDir.path + ", Exception: " + e);
+    }
+  }
 }
 
 /**
- * Nulls out the most commonly used global vars used by tests as appropriate.
+ * Nulls out the most commonly used global vars used by tests to prevent leaks
+ * as needed and attempts to restore the system to its original state.
  */
 function cleanupTestCommon() {
   logTestInfo("start - general test cleanup");
-  removeUpdateDirsAndFiles();
 
   // Force the update manager to reload the update data to prevent it from
   // writing the old data to the files that have just been removed.
   reloadUpdateManagerData();
 
   if (gChannel) {
     gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
   }
@@ -388,16 +453,85 @@ function cleanupTestCommon() {
     gXHR.onerror     = null;
     gXHR.onload      = null;
     gXHR.onprogress  = null;
 
     gXHR             = null;
   }
 
   gTestserver = null;
+
+  if (IS_UNIX) {
+    // This will delete the launch script if it exists.
+    getLaunchScript();
+  }
+
+  if (IS_WIN && MOZ_APP_BASENAME) {
+    let appDir = getApplyDirFile(null, true);
+    let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
+    const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
+                     "\\TaskBarIDs";
+    let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
+              createInstance(AUS_Ci.nsIWindowsRegKey);
+    try {
+      key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
+               AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
+      if (key.hasValue(appDir.path)) {
+        key.removeValue(appDir.path);
+      }
+    } catch (e) {
+    }
+    try {
+      key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
+               AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
+      if (key.hasValue(appDir.path)) {
+        key.removeValue(appDir.path);
+      }
+    } catch (e) {
+    }
+  }
+
+  removeUpdateDirsAndFiles();
+
+  // The updates directory is located outside of the application directory on
+  // Windows so it also needs to be removed.
+  if (IS_WIN) {
+    let updatesDir = getMockUpdRootD();
+    // Try to remove the directory used to apply updates. Since the test has
+    // already finished this is non-fatal for the test.
+    if (updatesDir.exists()) {
+      logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
+      try {
+        removeDirRecursive(updatesDir);
+      } catch (e) {
+        logTestInfo("non-fatal error removing directory. Path: " +
+                    updatesDir.path + ", Exception: " + e);
+      }
+    }
+  }
+
+  let applyDir = getApplyDirFile(null, true).parent;
+  if (IS_MACOSX) {
+    applyDir = applyDir.parent;
+  }
+
+  // Try to remove the directory used to apply updates. Since the test has
+  // already finished this is non-fatal for the test.
+  if (applyDir.exists()) {
+    logTestInfo("attempting to remove directory. Path: " + applyDir.path);
+    try {
+      removeDirRecursive(applyDir);
+    } catch (e) {
+      logTestInfo("non-fatal error removing directory. Path: " +
+                  applyDir.path + ", Exception: " + e);
+    }
+  }
+
+  resetEnvironment();
+
   logTestInfo("finish - general test cleanup");
 }
 
 /**
  * Sets the most commonly used preferences used by tests
  */
 function setDefaultPrefs() {
   Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
@@ -415,53 +549,100 @@ function setDefaultPrefs() {
  */
 function standardInit() {
   createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0");
   setDefaultPrefs();
   // Initialize the update service stub component
   initUpdateServiceStub();
 }
 
-/* Custom path handler for the http server */
-function pathHandler(metadata, response) {
-  response.setHeader("Content-Type", "text/xml", false);
-  response.setStatusLine(metadata.httpVersion, gResponseStatusCode, "OK");
-  response.bodyOutputStream.write(gResponseBody, gResponseBody.length);
+/**
+ * Custom path handler for the http server
+ *
+ * @param   aMetadata
+ *          The http metadata for the request.
+ * @param   aResponse
+ *          The http response for the request.
+ */
+function pathHandler(aMetadata, aResponse) {
+  aResponse.setHeader("Content-Type", "text/xml", false);
+  aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK");
+  aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length);
+}
+
+/**
+ * Helper function for getting the application version from the application.ini
+ * file. This will look in both the GRE and the application directories for the
+ * application.ini file.
+ *
+ * @return  The version string from the application.ini file.
+ * @throws  If the application.ini file is not found.
+ */
+function getAppVersion() {
+  // Read the application.ini and use its application version.
+  let iniFile = gGREDirOrig.clone();
+  iniFile.append("application.ini");
+  if (!iniFile.exists()) {
+    iniFile = gAppDirOrig.clone();
+    iniFile.append("application.ini");
+  }
+  if (!iniFile.exists()) {
+    do_throw("Unable to find application.ini!");
+  }
+  let iniParser = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
+                  getService(AUS_Ci.nsIINIParserFactory).
+                  createINIParser(iniFile);
+  return iniParser.getString("App", "Version");
 }
 
 /**
  * Helper function for getting the relative path to the directory where the
- * update will be applied.
+ * application binary is located.
+ * For Mac OS X the path will be:
+ *   <test_file_leafname>.app/Contents/MacOS/
+ * For other platforms the path will be:
+ *   <test_file_leafname>/appdir/
  *
- * The main files in the update are located two directories below the apply to
- * directory since Mac OS X sets the last modified time for the root directory
- * to the current time and if the update changes any files in the root directory
- * then it wouldn't be possible to test (bug 600098).
+ * Note: The appdir subdirectory is needed for platforms other than Mac OS X so
+ *       the tests can run in parallel due to update staging creating a lock
+ *       file named moz_update_in_progress.lock in the parent directory of the
+ *       installation directory.
  *
- * @return  The relative path to the directory where the update will be applied.
+ * @return  The relative path to the directory where application binary is
+ *          located.
  */
 function getApplyDirPath() {
-  return gTestID + APPLY_TO_DIR_SUFFIX + "appdir/";
+  if (IS_MACOSX) {
+    return gTestID + DIR_APP_SUFFIX + DIR_APP_REL_PATH;
+  }
+  return gTestID + DIR_APP_REL_PATH;
 }
 
 /**
  * Helper function for getting the nsIFile for a file in the directory where the
  * update will be applied.
  *
  * The files for the update are located two directories below the apply to
  * directory since Mac OS X sets the last modified time for the root directory
  * to the current time and if the update changes any files in the root directory
  * then it wouldn't be possible to test (bug 600098).
  *
+ * @param   aRelPath (optional)
+ *          The relative path to the file or directory to get from the root of
+ *          the test's directory. If not specified the test's directory will be
+ *          returned.
+ * @param   aAllowNonexistent (optional)
+ *          Whether the file must exist. If false or not specified the file must
+ *          exist or the function will throw.
  * @return  The nsIFile for the file in the directory where the update will be
  *          applied.
  */
-function getApplyDirFile(aRelPath, allowNonexistent) {
+function getApplyDirFile(aRelPath, aAllowNonexistent) {
   let relpath = getApplyDirPath() + (aRelPath ? aRelPath : "");
-  return do_get_file(relpath, allowNonexistent);
+  return do_get_file(relpath, aAllowNonexistent);
 }
 
 /**
  * Helper function for getting the relative path to the directory where the
  * test data files are located.
  *
  * @return  The relative path to the directory where the test data files are
  *          located.
@@ -469,224 +650,345 @@ function getApplyDirFile(aRelPath, allow
 function getTestDirPath() {
   return "../data/";
 }
 
 /**
  * Helper function for getting the nsIFile for a file in the test data
  * directory.
  *
+ * @param   aRelPath (optional)
+ *          The relative path to the file or directory to get from the root of
+ *          the test's data directory. If not specified the test's data
+ *          directory will be returned.
  * @return  The nsIFile for the file in the test data directory.
+ * @throws  If the file or directory does not exist.
  */
 function getTestDirFile(aRelPath) {
   let relpath = getTestDirPath() + (aRelPath ? aRelPath : "");
   return do_get_file(relpath, false);
 }
 
 /**
- * Helper function for getting the updated directory.
+ * Helper function for getting the directory that was updated. This can either
+ * be the directory where the application binary is located or the directory
+ * that contains the staged update.
  */
 function getUpdatedDirPath() {
-  let suffix = "";
-  if (gBackgroundUpdate) {
-    suffix = UPDATED_DIR_SUFFIX;
+  let updatedDirPath = gTestID;
+  if (IS_MACOSX) {
+    updatedDirPath += DIR_APP_SUFFIX;
+  } else {
+    // The appdir subdirectory is needed so the tests can run in parallel due to
+    // update staging creating a lock file named moz_update_in_progress.lock in
+    // the parent directory of the installation directory.
+    updatedDirPath += DIR_APP_REL_PATH;
+  }
+  if (gStageUpdate) {
+    updatedDirPath += DIR_UPDATED + "/";
+  } else if (IS_MACOSX) {
+    updatedDirPath += DIR_APP_REL_PATH;
+  }
+  return updatedDirPath;
+}
+
+/**
+ * Helper function for getting the directory where files are added, removed,
+ * and modified by the simple.mar update file.
+ *
+ * @return  nsIFile for the directory where files are added, removed, and
+ * modified by the simple.mar update file.
+ */
+function getUpdateTestDir() {
+  let updateTestDir = getApplyDirFile(null, true);
+
+  if (IS_MACOSX) {
+    updateTestDir = updateTestDir.parent.parent;
+  }
+  updateTestDir.append("update_test");
+  return updateTestDir;
+}
+
+
+#ifdef XP_WIN
+XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash",
+                            function test_gInstallDirPathHash() {
+  // Figure out where we should check for a cached hash value
+  if (!MOZ_APP_BASENAME)
+    return null;
+
+  let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
+  let appDir = getApplyDirFile(null, true);
+
+  const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
+                   "\\TaskBarIDs";
+  let regKey = AUS_Cc["@mozilla.org/windows-registry-key;1"].
+               createInstance(AUS_Ci.nsIWindowsRegKey);
+  try {
+    regKey.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
+                AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
+    regKey.writeStringValue(appDir.path, gTestID);
+    return gTestID;
+  } catch (e) {
+  }
+
+  try {
+    regKey.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
+                  AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
+    regKey.writeStringValue(appDir.path, gTestID);
+    return gTestID;
+  } catch (e) {
+    logTestInfo("failed to create registry key. Registry Path: " + REG_PATH +
+                ", Key Name: " + appDir.path + ", Key Value: " + gTestID +
+                ", Exception " + e);
   }
-  return getApplyDirPath() + suffix;
+  return null;
+});
+
+XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir",
+                            function test_gLocalAppDataDir() {
+  const CSIDL_LOCAL_APPDATA = 0x1c;
+
+  AUS_Cu.import("resource://gre/modules/ctypes.jsm");
+  let lib = ctypes.open("shell32");
+  let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
+                                           ctypes.winapi_abi,
+                                           ctypes.bool, /* bool(return) */
+                                           ctypes.int32_t, /* HWND hwndOwner */
+                                           ctypes.jschar.ptr, /* LPTSTR lpszPath */
+                                           ctypes.int32_t, /* int csidl */
+                                           ctypes.bool /* BOOL fCreate */);
+
+  let aryPathLocalAppData = ctypes.jschar.array()(260);
+  let rv = SHGetSpecialFolderPath(0, aryPathLocalAppData, CSIDL_LOCAL_APPDATA, false);
+  lib.close();
+
+  let pathLocalAppData = aryPathLocalAppData.readString(); // Convert the c-string to js-string
+  let updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
+                   createInstance(AUS_Ci.nsILocalFile);
+  updatesDir.initWithPath(pathLocalAppData);
+  return updatesDir;
+});
+
+XPCOMUtils.defineLazyGetter(this, "gProgFilesDir",
+                            function test_gProgFilesDir() {
+  const CSIDL_PROGRAM_FILES = 0x26;
+
+  AUS_Cu.import("resource://gre/modules/ctypes.jsm");
+  let lib = ctypes.open("shell32");
+  let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
+                                           ctypes.winapi_abi,
+                                           ctypes.bool, /* bool(return) */
+                                           ctypes.int32_t, /* HWND hwndOwner */
+                                           ctypes.jschar.ptr, /* LPTSTR lpszPath */
+                                           ctypes.int32_t, /* int csidl */
+                                           ctypes.bool /* BOOL fCreate */);
+
+  let aryPathProgFiles = ctypes.jschar.array()(260);
+  let rv = SHGetSpecialFolderPath(0, aryPathProgFiles, CSIDL_PROGRAM_FILES, false);
+  lib.close();
+
+  let pathProgFiles = aryPathProgFiles.readString(); // Convert the c-string to js-string
+  let progFilesDir = AUS_Cc["@mozilla.org/file/local;1"].
+                     createInstance(AUS_Ci.nsILocalFile);
+  progFilesDir.initWithPath(pathProgFiles);
+  return progFilesDir;
+});
+
+/**
+ * Helper function for getting the update root directory used by the tests. This
+ * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
+ * in nsXREDirProvider.cpp so an application will be able to find the update
+ * when running a test that launches the application.
+ */
+function getMockUpdRootD() {
+  let localAppDataDir = gLocalAppDataDir.clone();
+  let progFilesDir = gProgFilesDir.clone();
+  let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent;
+
+  let appDirPath = appDir.path;
+  var relPathUpdates = "";
+  if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) {
+    relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) +
+                      "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash;
+  }
+
+  if (!relPathUpdates) {
+    if (appDirPath.length > progFilesDir.path.length) {
+      if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) {
+        if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
+          relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
+        } else {
+          relPathUpdates += MOZ_APP_BASENAME;
+        }
+        relPathUpdates += appDirPath.substr(progFilesDir.path.length);
+      }
+    }
+  }
+
+  if (!relPathUpdates) {
+    if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
+      relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
+    } else {
+      relPathUpdates += MOZ_APP_BASENAME;
+    }
+    relPathUpdates += "\\" + MOZ_APP_NAME;
+  }
+
+  var updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
+                   createInstance(AUS_Ci.nsILocalFile);
+  updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates);
+  logTestInfo("returning UpdRootD Path: " + updatesDir.path);
+  return updatesDir;
 }
+#else
+/**
+ * Helper function for getting the update root directory used by the tests. This
+ * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
+ * in nsXREDirProvider.cpp so an application will be able to find the update
+ * when running a test that launches the application.
+ */
+function getMockUpdRootD() {
+  return getApplyDirFile(null, true);
+}
+#endif
 
 /**
  * Helper function for getting the nsIFile for the directory where the update
  * has been applied.
  *
  * This will be the same as getApplyDirFile for foreground updates, but will
- * point to a different file for the case of background updates.
+ * point to a different file for the case of staged updates.
  *
  * Functions which attempt to access the files in the updated directory should
  * be using this instead of getApplyDirFile.
  *
+ * @param   aRelPath (optional)
+ *          The relative path to the file or directory to get from the root of
+ *          the test's directory. If not specified the test's directory will be
+ *          returned.
+ * @param   aAllowNonexistent (optional)
+ *          Whether the file must exist. If false or not specified the file must
+ *          exist or the function will throw.
  * @return  The nsIFile for the directory where the update has been applied.
  */
-function getTargetDirFile(aRelPath, allowNonexistent) {
+function getTargetDirFile(aRelPath, aAllowNonexistent) {
   let relpath = getUpdatedDirPath() + (aRelPath ? aRelPath : "");
-  return do_get_file(relpath, allowNonexistent);
+  return do_get_file(relpath, aAllowNonexistent);
 }
 
 if (IS_WIN) {
   const kLockFileName = "updated.update_in_progress.lock";
   /**
    * Helper function for locking a directory on Windows.
+   *
+   * @param   aDir
+   *          The nsIFile for the directory to lock.
    */
   function lockDirectory(aDir) {
     var file = aDir.clone();
     file.append(kLockFileName);
     file.create(file.NORMAL_FILE_TYPE, 0o444);
     file.QueryInterface(AUS_Ci.nsILocalFileWin);
     file.fileAttributesWin |= file.WFA_READONLY;
     file.fileAttributesWin &= ~file.WFA_READWRITE;
     logTestInfo("testing the successful creation of the lock file");
     do_check_true(file.exists());
     do_check_false(file.isWritable());
   }
   /**
    * Helper function for unlocking a directory on Windows.
+   *
+   * @param   aDir
+   *          The nsIFile for the directory to unlock.
    */
   function unlockDirectory(aDir) {
     var file = aDir.clone();
     file.append(kLockFileName);
     file.QueryInterface(AUS_Ci.nsILocalFileWin);
     file.fileAttributesWin |= file.WFA_READWRITE;
     file.fileAttributesWin &= ~file.WFA_READONLY;
     logTestInfo("removing and testing the successful removal of the lock file");
     file.remove(false);
     do_check_false(file.exists());
   }
 }
 
 /**
- * Copies the minimum files required by the application to be able to process
- * an application update when the application is launched for a test.
- *
- * @param  aSrcDir
- *         nsIFile for the source directory to be copied from.
- * @param  aDestDir
- *         nsIFile for the destination directory parent.
- * @param  aDestLeafName
- *         the destination directory name.
- */
-function copyMinimumAppFiles(aSrcDir, aDestDir, aDestLeafName) {
-  let destDir = aDestDir.clone();
-  destDir.append(aDestLeafName);
-  if (!destDir.exists()) {
-    try {
-      destDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
-    }
-    catch (e) {
-      logTestInfo("unable to create directory, path: " + destDir.path +
-                  ", exception: " + e);
-      do_throw(e);
-    }
-  }
-
-  // Required files for the application or the test that aren't listed in the
-  // dependentlibs.list file.
-  let fileLeafNames = [APP_BIN_NAME + APP_BIN_SUFFIX, FILE_UPDATER_BIN,
-                       FILE_UPDATE_SETTINGS_INI, "application.ini",
-                       "dependentlibs.list"];
-
-  // Read the dependent libs file leafnames from the dependentlibs.list file
-  // into the array.
-  let deplibsFile = aSrcDir.clone();
-  deplibsFile.append("dependentlibs.list");
-  let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
-                createInstance(AUS_Ci.nsIFileInputStream);
-  istream.init(deplibsFile, 0x01, 0o444, 0);
-  istream.QueryInterface(AUS_Ci.nsILineInputStream);
-
-  let hasMore;
-  let line = {};
-  do {
-    hasMore = istream.readLine(line);
-    fileLeafNames.push(line.value);
-  } while(hasMore);
-
-  istream.close();
-
-  fileLeafNames.forEach(function CMAF_FLN_FE(aLeafName) {
-    let srcFile = aSrcDir.clone();
-    srcFile.append(aLeafName);
-    try {
-      srcFile.copyTo(destDir, aLeafName);
-    }
-    catch (e) {
-      logTestInfo("unable to copy file, src path: " + srcFile.path +
-                  ", dest path: " + destFile.path + ", exception: " + e);
-      do_throw(e);
-    }
-  });
-}
-
-/**
  * Helper function for updater tests for launching the updater binary to apply
  * a mar file.
  *
- * @return  The exit value returned from the updater binary.
+ * @param   aExpectedExitValue
+ *          The expected exit value from the updater binary.
+ * @param   aCallback (optional)
+ *          A callback function that will be called when this function finishes.
+ *          If null no function will be called when this function finishes.
+ *          If not specified the checkUpdateApplied function will be called when
+ *          this function finishes.
  */
-function runUpdate() {
+function runUpdate(aExpectedExitValue, aCallback) {
   // Copy the updater binary to the updates directory.
-  let binDir = getGREDir();
+  let binDir = gGREDirOrig.clone();
   let updater = binDir.clone();
   updater.append("updater.app");
   if (!updater.exists()) {
     updater = binDir.clone();
     updater.append(FILE_UPDATER_BIN);
     if (!updater.exists()) {
       do_throw("Unable to find updater binary!");
     }
   }
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
-  updater.copyTo(updatesDir, updater.leafName);
+  let updatesDir = getUpdatesPatchDir();
+  updater.copyToFollowingLinks(updatesDir, updater.leafName);
   let updateBin = updatesDir.clone();
   updateBin.append(updater.leafName);
   if (updateBin.leafName == "updater.app") {
     updateBin.append("Contents");
     updateBin.append("MacOS");
     updateBin.append("updater");
-    if (!updateBin.exists())
+    if (!updateBin.exists()) {
       do_throw("Unable to find the updater executable!");
+    }
   }
 
-  let updatesDirPath = updatesDir.path;
-  if (/ /.test(updatesDirPath))
-    updatesDirPath = '"' + updatesDirPath + '"';
-
-  let applyToDir = getApplyDirFile();
+  let applyToDir = getApplyDirFile(null, true);
   let applyToDirPath = applyToDir.path;
-  if (gBackgroundUpdate || gSwitchApp) {
-    applyToDirPath += "/" + UPDATED_DIR_SUFFIX;
+  if (gStageUpdate || gSwitchApp) {
+    applyToDirPath += "/" + DIR_UPDATED + "/";
   }
   if (IS_WIN) {
     // Convert to native path
     applyToDirPath = applyToDirPath.replace(/\//g, "\\");
   }
-  if (/ /.test(applyToDirPath))
-    applyToDirPath = '"' + applyToDirPath + '"';
 
   let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
   callbackApp.permissions = PERMS_DIRECTORY;
 
-  let cwdPath = callbackApp.parent.path;
-  if (/ /.test(cwdPath))
-    cwdPath = '"' + cwdPath + '"';
-
-  let callbackAppPath = callbackApp.path;
-  if (/ /.test(callbackAppPath))
-    callbackAppPath = '"' + callbackAppPath + '"';
-
   // Backup the updater-settings.ini file if it exists by moving it.
   let updateSettingsIni = getApplyDirFile(null, true);
   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
   if (updateSettingsIni.exists()) {
     updateSettingsIni.moveTo(updateSettingsIni.parent, FILE_UPDATE_SETTINGS_INI_BAK);
   }
   updateSettingsIni = getApplyDirFile(null, true);
   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
-  let args = [updatesDirPath, applyToDirPath, 0];
-  if (gBackgroundUpdate) {
+  let args = [updatesDir.path, applyToDirPath, 0];
+  if (gStageUpdate) {
     args[2] = -1;
   } else {
     if (gSwitchApp) {
       args[2] = "0/replace";
     }
-    args = args.concat([cwdPath, callbackAppPath]);
+    args = args.concat([callbackApp.parent.path, callbackApp.path]);
     args = args.concat(gCallbackArgs);
   }
-  logTestInfo("Running the updater: " + updateBin.path + " " + args.join(" "));
+  logTestInfo("running the updater: " + updateBin.path + " " + args.join(" "));
 
   let env = AUS_Cc["@mozilla.org/process/environment;1"].
             getService(AUS_Ci.nsIEnvironment);
   if (gDisableReplaceFallback) {
     env.set("MOZ_NO_REPLACE_FALLBACK", "1");
   }
 
   let process = AUS_Cc["@mozilla.org/process/util;1"].
@@ -700,26 +1002,51 @@ function runUpdate() {
 
   // Restore the backed up updater-settings.ini if it exists.
   let updateSettingsIni = getApplyDirFile(null, true);
   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
   if (updateSettingsIni.exists()) {
     updateSettingsIni.moveTo(updateSettingsIni.parent, FILE_UPDATE_SETTINGS_INI);
   }
 
-  return process.exitValue;
-}
+  logTestInfo("testing updater binary process exitValue against expected " +
+              "exit value");
+  do_check_eq(process.exitValue, aExpectedExitValue);
 
-let gServiceLaunchedCallbackLog = null;
-let gServiceLaunchedCallbackArgs = null;
+  if (aCallback !== null) {
+    if (typeof(aCallback) == typeof(Function)) {
+      aCallback();
+    } else {
+      checkUpdateApplied();
+    }
+  }
+}
+/**
+ * Helper function for updater tests to stage an update.
+ */
+function stageUpdate() {
+  logTestInfo("start - staging update");
+  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
+
+  setEnvironment();
+  // Stage the update.
+  AUS_Cc["@mozilla.org/updates/update-processor;1"].
+    createInstance(AUS_Ci.nsIUpdateProcessor).
+    processUpdate(gUpdateManager.activeUpdate);
+  resetEnvironment();
+
+  logTestInfo("finish - staging update");
+}
 
 /**
  * Helper function to check whether the maintenance service updater tests should
  * run. See bug 711660 for more details.
  *
+ * @param  aFirstTest
+ *         Whether this is the first test within the test.
  * @return true if the test should run and false if it shouldn't.
  */
 function shouldRunServiceTest(aFirstTest) {
   // In case the machine is running an old maintenance service or if it
   // is not installed, and permissions exist to install it.  Then install
   // the newer bin that we have.
   attemptServiceInstall();
 
@@ -738,18 +1065,17 @@ function shouldRunServiceTest(aFirstTest
   const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" +
                    "3932ecacee736d366d6436db0f55bce4";
 
   let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
             createInstance(AUS_Ci.nsIWindowsRegKey);
   try {
     key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
              AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64);
-  }
-  catch (e) {
+  } catch (e) {
 #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
     // The build system could sign the files and not have the test registry key
     // in which case we should fail the test by throwing so it can be fixed.
     if (isBinarySigned(updaterBinPath)) {
       do_throw("binary is signed but the test registry key does not exists!");
     }
 #endif
 
@@ -759,23 +1085,23 @@ function shouldRunServiceTest(aFirstTest
   }
 
   // Check to make sure the service is installed
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let args = ["wait-for-service-stop", "MozillaMaintenance", "10"];
   let process = AUS_Cc["@mozilla.org/process/util;1"].
                 createInstance(AUS_Ci.nsIProcess);
   process.init(helperBin);
-  logTestInfo("Checking if the service exists on this machine.");
+  logTestInfo("checking if the service exists on this machine.");
   process.run(true, args, args.length);
   if (process.exitValue == 0xEE) {
     do_throw("test registry key exists but this test can only run on systems " +
              "with the maintenance service installed.");
   } else {
-    logTestInfo("Service exists, return value: " + process.exitValue);
+    logTestInfo("service exists, return value: " + process.exitValue);
   }
 
   // If this is the first test in the series, then there is no reason the
   // service should be anything but stopped, so be strict here and throw
   // an error.
   if (aFirstTest && process.exitValue != 0) {
     do_throw("First test, check for service stopped state returned error " +
              process.exitValue);
@@ -809,32 +1135,170 @@ function isBinarySigned(aBinPath) {
     logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " +
                 process.exitValue + " for file " + aBinPath);
     return false;
   }
   return true;
 }
 
 /**
- * Copies the specified filename from the dist/bin
- * directory into the apply-to directory.
+ * Helper function for asynchronously setting up the application files required
+ * to launch the application for the updater tests by either copying or creating
+ * symlinks for the files. This is needed for Windows debug builds which can
+ * lock a file that is being copied so that the tests can run in parallel. After
+ * the files have been copied the setupAppFilesFinished function will be called.
+ */
+function setupAppFilesAsync() {
+  gTimeoutRuns++;
+  try {
+    setupAppFiles();
+  } catch (e) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " +
+               "files. Exception: " + e);
+    }
+    do_timeout(TEST_CHECK_TIMEOUT, setupAppFilesAsync);
+    return;
+  }
+
+  setupAppFilesFinished();
+}
+
+/**
+ * Helper function for setting up the application files required to launch the
+ * application for the updater tests by either copying or creating symlinks for
+ * the files.
+ */
+function setupAppFiles() {
+  logTestInfo("start - copying or creating symlinks for application files " +
+              "for the test");
+
+  let srcDir = getCurrentProcessDir();
+  let destDir = getApplyDirFile(null, true);
+  if (!destDir.exists()) {
+    try {
+      destDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
+    } catch (e) {
+      logTestInfo("unable to create directory, Path: " + destDir.path +
+                  ", Exception: " + e);
+      do_throw(e);
+    }
+  }
+
+  // Required files for the application or the test that aren't listed in the
+  // dependentlibs.list file.
+  let fileRelPaths = [FILE_APP_BIN, FILE_UPDATER_BIN, FILE_UPDATE_SETTINGS_INI,
+                       "application.ini", "dependentlibs.list"];
+
+  // On Linux the updater.png must also be copied
+  if (IS_UNIX && !IS_MACOSX) {
+    fileRelPaths.push("icons/updater.png");
+  }
+
+  // Read the dependent libs file leafnames from the dependentlibs.list file
+  // into the array.
+  let deplibsFile = srcDir.clone();
+  deplibsFile.append("dependentlibs.list");
+  let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
+                createInstance(AUS_Ci.nsIFileInputStream);
+  istream.init(deplibsFile, 0x01, 0o444, 0);
+  istream.QueryInterface(AUS_Ci.nsILineInputStream);
+
+  let hasMore;
+  let line = {};
+  do {
+    hasMore = istream.readLine(line);
+    fileRelPaths.push(line.value);
+  } while(hasMore);
+
+  istream.close();
+
+  fileRelPaths.forEach(function CMAF_FLN_FE(aFileRelPath) {
+    copyFileToTestAppDir(aFileRelPath);
+  });
+
+  logTestInfo("finish - copying or creating symlinks for application files " +
+              "for the test");
+}
+
+/**
+ * Copies the specified files from the dist/bin directory into the test's
+ * application directory.
  *
- * @param filename The name of the file to copy
-*/
-function copyBinToApplyToDir(filename) {
-  let binDir = getGREDir();
-  let fileToCopy = binDir.clone();
-  fileToCopy.append(filename);
-  if (!fileToCopy.exists()) {
-    do_throw("Unable to copy binary: " + filename);
+ * @param  aFileRelPath
+ *         The relative path of the file to copy.
+ */
+function copyFileToTestAppDir(aFileRelPath) {
+  let fileRelPath = aFileRelPath;
+  let srcFile = gGREDirOrig.clone();
+  let pathParts = fileRelPath.split("/");
+  for (let i = 0; i < pathParts.length; i++) {
+    if (pathParts[i]) {
+      srcFile.append(pathParts[i]);
+    }
+  }
+
+  if (IS_MACOSX && !srcFile.exists()) {
+    logTestInfo("unable to copy file since it doesn't exist! Checking if " +
+                 fileRelPath + DIR_APP_SUFFIX + " exists. Path: " +
+                 srcFile.path);
+    srcFile = gGREDirOrig.clone();
+    for (let i = 0; i < pathParts.length; i++) {
+      if (pathParts[i]) {
+        srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? DIR_APP_SUFFIX : ""));
+      }
+    }
+    fileRelPath = fileRelPath + DIR_APP_SUFFIX;
+  }
+  if (!srcFile.exists()) {
+    do_throw("Unable to copy file since it doesn't exist! Path: " +
+             srcFile.path);
   }
-  let applyToUpdater = getApplyDirFile(null, true);
-  if (applyToUpdater.path != binDir.path) {
-    do_print("copying " + fileToCopy.path + " to: " + applyToUpdater.path);
-    fileToCopy.copyTo(applyToUpdater, filename);
+
+  // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a
+  // file extension and this will always be false on Windows.
+  let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" ||
+                       fileRelPath.substr(fileRelPath.length - 3) == ".so" ||
+                       fileRelPath.substr(fileRelPath.length - 6) == ".dylib");
+  let destFile = getApplyDirFile(fileRelPath, true);
+  if (!shouldSymlink) {
+    if (!destFile.exists()) {
+      try {
+        srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName);
+      } catch (e) {
+        // Just in case it is partially copied
+        if (destFile.exists()) {
+          try {
+            destFile.remove(true);
+          } catch (e) {
+            logTestInfo("unable to remove file that failed to copy! Path: " +
+                        destFile.path);
+          }
+        }
+        do_throw("Unable to copy file! Path: " + srcFile.path +
+                 ", Exception: " + e);
+      }
+    }
+  } else {
+    try {
+      if (destFile.exists()) {
+        destFile.remove(false);
+      }
+      let ln = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
+      ln.initWithPath("/bin/ln");
+      let process = AUS_Cc["@mozilla.org/process/util;1"].createInstance(AUS_Ci.nsIProcess);
+      process.init(ln);
+      let args = ["-s", srcFile.path, destFile.path];
+      process.run(true, args, args.length);
+      logTestInfo("verifying symlink. Path: " + destFile.path);
+      do_check_true(destFile.isSymlink());
+    } catch (e) {
+      do_throw("Unable to create symlink for file! Path: " + srcFile.path +
+               ", Exception: " + e);
+    }
   }
 }
 
 /**
  * Attempts to upgrade the maintenance service if permissions are allowed.
  * This is useful for XP where we have permission to upgrade in case an
  * older service installer exists.  Also if the user manually installed into
  * a unprivileged location.
@@ -852,36 +1316,34 @@ function attemptServiceInstall() {
   let installerFile = binDir.clone();
   installerFile.append(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
   if (!installerFile.exists()) {
     do_throw(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN + " not found.");
   }
   let installerProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   installerProcess.init(installerFile);
-  logTestInfo("Starting installer process...");
+  logTestInfo("starting installer process...");
   installerProcess.run(true, [], 0);
 }
 
 /**
  * Helper function for updater tests for launching the updater using the
  * maintenance service to apply a mar file.
  *
- * @param aInitialStatus  the initial value of update.status
- * @param aExpectedStatus the expected value of update.status when the test finishes
- * @param aCallback       the function to be called when the update is finished
- * @param aUpdatesDir     the updates root directory to use (optional)
- * @param aCheckSvcLog    whether the service log should be checked (optional)
+ * @param aInitialStatus  the initial value of update.status.
+ * @param aExpectedStatus the expected value of update.status when the test
+                          finishes.
+ * @param aCheckSvcLog    whether the service log should be checked (optional).
  */
-function runUpdateUsingService(aInitialStatus, aExpectedStatus,
-                               aCallback, aUpdatesDir, aCheckSvcLog) {
+function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
   // Check the service logs for a successful update
   function checkServiceLogs(aOriginalContents) {
     let contents = readServiceLogFile();
-    logTestInfo("The contents of maintenanceservice.log:\n" + contents + "\n");
+    logTestInfo("the contents of maintenanceservice.log:\n" + contents + "\n");
     do_check_neq(contents, aOriginalContents);
     do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1);
   }
   function readServiceLogFile() {
     let file = AUS_Cc["@mozilla.org/file/directory_service;1"].
                getService(AUS_Ci.nsIProperties).
                get("CmAppData", AUS_Ci.nsIFile);
     file.append("Mozilla");
@@ -894,369 +1356,332 @@ function runUpdateUsingService(aInitialS
     waitForApplicationStop("maintenanceservice_installer.exe");
     // maintenanceservice_tmp.exe is started async from the service installer.
     waitForApplicationStop("maintenanceservice_tmp.exe");
     // In case the SCM thinks the service is stopped, but process still exists.
     waitForApplicationStop("maintenanceservice.exe");
   }
   function waitForServiceStop(aFailTest) {
     waitServiceApps();
-    logTestInfo("Waiting for service to stop if necessary...");
+    logTestInfo("waiting for service to stop if necessary...");
     // Use the helper bin to ensure the service is stopped. If not
     // stopped then wait for the service to be stopped (at most 120 seconds)
     let helperBin = getTestDirFile(FILE_HELPER_BIN);
     let helperBinArgs = ["wait-for-service-stop",
                          "MozillaMaintenance",
                          "120"];
     let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
     helperBinProcess.init(helperBin);
-    logTestInfo("Stopping service...");
+    logTestInfo("stopping service...");
     helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
     if (helperBinProcess.exitValue == 0xEE) {
       do_throw("The service does not exist on this machine.  Return value: " +
                helperBinProcess.exitValue);
     } else if (helperBinProcess.exitValue != 0) {
       if (aFailTest) {
         do_throw("maintenance service did not stop, last state: " +
                  helperBinProcess.exitValue + ". Forcing test failure.");
       } else {
         logTestInfo("maintenance service did not stop, last state: " +
                     helperBinProcess.exitValue + ".  May cause failures.");
       }
     } else {
-      logTestInfo("Service stopped.");
+      logTestInfo("service stopped.");
     }
     waitServiceApps();
   }
-  function waitForApplicationStop(application) {
-    logTestInfo("Waiting for " + application + " to stop if " +
+  function waitForApplicationStop(aApplication) {
+    logTestInfo("waiting for " + aApplication + " to stop if " +
                 "necessary...");
     // Use the helper bin to ensure the application is stopped.
     // If not, then wait for it to be stopped (at most 120 seconds)
     let helperBin = getTestDirFile(FILE_HELPER_BIN);
     let helperBinArgs = ["wait-for-application-exit",
-                         application,
+                         aApplication,
                          "120"];
     let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
     helperBinProcess.init(helperBin);
     helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
     if (helperBinProcess.exitValue != 0) {
-      do_throw(application + " did not stop, last state: " +
+      do_throw(aApplication + " did not stop, last state: " +
                helperBinProcess.exitValue + ". Forcing test failure.");
     }
   }
 
   // Make sure the service from the previous test is already stopped.
   waitForServiceStop(true);
 
   // Prevent the cleanup function from begin run more than once
   if (typeof(gRegisteredServiceCleanup) === "undefined") {
     gRegisteredServiceCleanup = true;
 
-    do_register_cleanup(function serviceCleanup() {
+    do_register_cleanup(function RUUS_cleanup() {
       resetEnvironment();
 
-      // This will delete the app console log file if it exists.
-      try {
-        getAppConsoleLogPath();
-      }
-      catch (e) {
-        logTestInfo("unable to remove file during cleanup. Exception: " + e);
-      }
-
       // This will delete the app arguments log file if it exists.
       try {
         getAppArgsLogPath();
-      }
-      catch (e) {
+      } catch (e) {
         logTestInfo("unable to remove file during cleanup. Exception: " + e);
       }
     });
   }
 
-  if (aCheckSvcLog === undefined) {
-    aCheckSvcLog = true; // default to true
-  }
-
   let svcOriginalLog;
-  if (aCheckSvcLog) {
+  // Default to checking the service log if the parameter is not specified.
+  if (aCheckSvcLog === undefined || aCheckSvcLog) {
     svcOriginalLog = readServiceLogFile();
   }
 
   let appArgsLogPath = getAppArgsLogPath();
   gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, "");
 
-  let updatesDir = aUpdatesDir || do_get_file(gTestID + UPDATES_DIR_SUFFIX);
+  let updatesDir = getUpdatesPatchDir();
   let file = updatesDir.clone();
-  file.append(FILE_UPDATE_STATUS);
-  writeFile(file, aInitialStatus + "\n");
+  writeStatusFile(aInitialStatus);
 
   // sanity check
-  do_check_eq(readStatusFile(updatesDir), aInitialStatus);
+  do_check_eq(readStatusState(), aInitialStatus);
 
-  file = updatesDir.clone();
-  file.append(FILE_UPDATE_VERSION);
-  writeFile(file, DEFAULT_UPDATE_VERSION + "\n");
+  writeVersionFile(DEFAULT_UPDATE_VERSION);
 
   gServiceLaunchedCallbackArgs = [
     "-no-remote",
     "-process-updates",
     "-dump-args",
-    appArgsLogPath
+    appArgsLogPath,
+    PIPE_TO_NULL
   ];
 
-  let launchBin = getLaunchBin();
-  let args = getProcessArgs(["-dump-args", appArgsLogPath]);
-  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
-
-  let process = AUS_Cc["@mozilla.org/process/util;1"].
-                   createInstance(AUS_Ci.nsIProcess);
-  process.init(launchBin);
-
-  // Override the update root directory
-  gEnvUpdateRootOverride = updatesDir.path;
-  gEnvAppDirOverride = getApplyDirFile(null).path;
-  gEnvSKipUpdateDirHashing = true;
-
   if (gSwitchApp) {
     // We want to set the env vars again
     gShouldResetEnv = undefined;
   }
 
   setEnvironment();
 
   // There is a security check done by the service to make sure the updater
   // we are executing is the same as the one in the apply-to dir.
   // To make sure they match from tests we copy updater.exe to the apply-to dir.
-  copyBinToApplyToDir(FILE_UPDATER_BIN);
+  copyFileToTestAppDir(FILE_UPDATER_BIN);
 
   // The service will execute maintenanceservice_installer.exe and
   // will copy maintenanceservice.exe out of the same directory from
   // the installation directory.  So we need to make sure both of those
   // bins always exist in the installation directory.
-  copyBinToApplyToDir(FILE_MAINTENANCE_SERVICE_BIN);
-  copyBinToApplyToDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
+  copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN);
+  copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
 
-  // Backup the updater-settings.ini file if it exists by moving it.
   let updateSettingsIni = getApplyDirFile(null, true);
   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(updateSettingsIni.parent, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = getApplyDirFile(null, true);
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
+  let launchBin = getLaunchBin();
+  let args = getProcessArgs(["-dump-args", appArgsLogPath]);
+
+  let process = AUS_Cc["@mozilla.org/process/util;1"].
+                   createInstance(AUS_Ci.nsIProcess);
+  process.init(launchBin);
+  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
   // Firefox does not wait for the service command to finish, but
   // we still launch the process sync to avoid intermittent failures with
   // the log file not being written out yet.
   // We will rely on watching the update.status file and waiting for the service
   // to stop to know the service command is done.
   process.run(true, args, args.length);
 
   resetEnvironment();
 
-  function timerCallback(timer) {
+  function timerCallback(aTimer) {
     // Wait for the expected status
-    let status = readStatusFile(updatesDir);
-    // For failed status, we don't care what the failure code is
-    if (aExpectedStatus == STATE_FAILED) {
-      status = status.split(": ")[0];
-    }
+    let status = readStatusState();
     // status will probably always be equal to STATE_APPLYING but there is a
     // race condition where it would be possible on slower machines where status
     // could be equal to STATE_PENDING_SVC.
     if (status == STATE_APPLYING ||
         status == STATE_PENDING_SVC) {
-      logTestInfo("Still waiting to see the " + aExpectedStatus +
+      logTestInfo("still waiting to see the " + aExpectedStatus +
                   " status, got " + status + " for now...");
       return;
     }
 
     // Make sure all of the logs are written out.
     waitForServiceStop(false);
 
     // Restore the backed up updater-settings.ini if it exists.
     let updateSettingsIni = getApplyDirFile(null, true);
     updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
     if (updateSettingsIni.exists()) {
       updateSettingsIni.moveTo(updateSettingsIni.parent, FILE_UPDATE_SETTINGS_INI);
     }
 
     do_check_eq(status, aExpectedStatus);
 
-    timer.cancel();
-    timer = null;
+    aTimer.cancel();
+    aTimer = null;
 
     if (aCheckSvcLog) {
       checkServiceLogs(svcOriginalLog);
     }
-    aCallback();
+
+    checkUpdateFinished();
   }
 
   let timer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
   timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK);
 }
 
 /**
  * Gets the platform specific shell binary that is launched using nsIProcess and
- * in turn launches the updater.
+ * in turn launches a binary used for the test (e.g. application, updater,
+ * etc.). A shell is used so debug console output can be redirected to a file so
+ * it doesn't end up in the test log.
  *
  * @return  nsIFile for the shell binary to launch using nsIProcess.
  * @throws  if the shell binary doesn't exist.
  */
 function getLaunchBin() {
   let launchBin;
   if (IS_WIN) {
     launchBin = Services.dirsvc.get("WinD", AUS_Ci.nsIFile);
     launchBin.append("System32");
     launchBin.append("cmd.exe");
-  }
-  else {
+  } else {
     launchBin = AUS_Cc["@mozilla.org/file/local;1"].
                 createInstance(AUS_Ci.nsILocalFile);
     launchBin.initWithPath("/bin/sh");
   }
 
   if (!launchBin.exists())
     do_throw(launchBin.path + " must exist to run this test!");
 
   return launchBin;
 }
 
+/**
+ * Helper function that waits until the helper has completed its operations and
+ * is in a sleep state before performing an update by calling doUpdate.
+ */
 function waitForHelperSleep() {
   // Give the lock file process time to lock the file before updating otherwise
   // this test can fail intermittently on Windows debug builds.
   let output = getApplyDirFile("a/b/output", true);
   if (readFile(output) != "sleeping\n") {
     do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
     return;
   }
   output.remove(false);
   doUpdate();
 }
 
+/**
+ * Helper function that waits until the helper has finished its operations
+ * before calling waitForHelperFinishFileUnlock to verify that the helper's
+ * input and output directories are no longer in use.
+ */
 function waitForHelperFinished() {
   // Give the lock file process time to lock the file before updating otherwise
   // this test can fail intermittently on Windows debug builds.
   let output = getApplyDirFile("a/b/output", true);
   if (readFile(output) != "finished\n") {
     do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinished);
     return;
   }
   // Give the lock file process time to unlock the file before deleting the
   // input and output files.
   waitForHelperFinishFileUnlock();
 }
 
+/**
+ * Helper function that waits until the helper's input and output directories
+ * are no longer in use before calling checkUpdate.
+ */
 function waitForHelperFinishFileUnlock() {
   try {
     let output = getApplyDirFile("a/b/output", true);
     if (output.exists()) {
       output.remove(false);
     }
     let input = getApplyDirFile("a/b/input", true);
     if (input.exists()) {
       input.remove(false);
     }
-  }
-  catch (e) {
+  } catch (e) {
     // Give the lock file process time to unlock the file before deleting the
     // input and output files.
     do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinishFileUnlock);
     return;
   }
   checkUpdate();
 }
 
+/**
+ * Helper function to tell the helper to finish and exit its sleep state.
+ */
 function setupHelperFinish() {
   let input = getApplyDirFile("a/b/input", true);
   writeFile(input, "finish\n");
   waitForHelperFinished();
 }
 
 /**
- * Helper function for updater binary tests for setting up the files and
+ * Helper function for updater binary tests that creates the files and
  * directories used by the test.
  *
  * @param   aMarFile
  *          The mar file for the update test.
  */
 function setupUpdaterTest(aMarFile) {
-  // Remove the directory where the updater, mar file, etc. will be copied to
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
-  try {
-    removeDirRecursive(updatesDir);
+  let updatesPatchDir = getUpdatesPatchDir();
+  if (!updatesPatchDir.exists()) {
+    updatesPatchDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
   }
-  catch (e) {
-    dump("Unable to remove directory\n" +
-         "path: " + updatesDir.path + "\n" +
-         "Exception: " + e + "\n");
-  }
-  if (!updatesDir.exists()) {
-    updatesDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
-  }
+  // Copy the mar that will be applied
+  let mar = getTestDirFile(aMarFile);
+  mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Remove the directory where the update will be applied if it exists.
   let applyToDir = getApplyDirFile(null, true);
-  try {
-    removeDirRecursive(applyToDir);
-  }
-  catch (e) {
-    dump("Unable to remove directory\n" +
-         "path: " + applyToDir.path + "\n" +
-         "Exception: " + e + "\n");
-  }
-  logTestInfo("testing successful removal of the directory used to apply the " +
-              "mar file");
-  do_check_false(applyToDir.exists());
-
-  // Add the test files that will be updated for a successful update or left in
-  // the initial state for a failed update.
   TEST_FILES.forEach(function SUT_TF_FE(aTestFile) {
     if (aTestFile.originalFile || aTestFile.originalContents) {
       let testDir = getApplyDirFile(aTestFile.relPathDir, true);
       if (!testDir.exists())
         testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
 
       let testFile;
       if (aTestFile.originalFile) {
         testFile = getTestDirFile(aTestFile.originalFile);
-        testFile.copyTo(testDir, aTestFile.fileName);
+        testFile.copyToFollowingLinks(testDir, aTestFile.fileName);
         testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName);
-      }
-      else {
-        testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName, true);
+      } else {
+        testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName,
+                                   true);
         writeFile(testFile, aTestFile.originalContents);
       }
 
       // Skip these tests on Windows and OS/2 since their
       // implementaions of chmod doesn't really set permissions.
       if (!IS_WIN && !IS_OS2 && aTestFile.originalPerms) {
         testFile.permissions = aTestFile.originalPerms;
         // Store the actual permissions on the file for reference later after
         // setting the permissions.
-        if (!aTestFile.comparePerms)
+        if (!aTestFile.comparePerms) {
           aTestFile.comparePerms = testFile.permissions;
+        }
       }
     }
   });
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let afterApplyBinDir = getApplyDirFile("a/b/", true);
-  helperBin.copyTo(afterApplyBinDir, gCallbackBinFile);
+  helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile);
 
-  // Copy the mar that will be applied
-  let mar = getTestDirFile(aMarFile);
-  mar.copyTo(updatesDir, FILE_UPDATE_ARCHIVE);
-
-  // Add the test directory that will be updated for a successful update or left in
-  // the initial state for a failed update.
+  // Add the test directory that will be updated for a successful update or left
+  // in the initial state for a failed update.
   var testDirs = TEST_DIRS.concat(ADDITIONAL_TEST_DIRS);
   testDirs.forEach(function SUT_TD_FE(aTestDir) {
     let testDir = getApplyDirFile(aTestDir.relPathDir, true);
     if (!testDir.exists()) {
       testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
     }
 
     if (aTestDir.files) {
@@ -1284,67 +1709,40 @@ function setupUpdaterTest(aMarFile) {
           });
         }
       });
     }
   });
 }
 
 /**
- * Helper function for updater binary tests to clean up the state after the test
- * has finished.
- */
-function cleanupUpdaterTest() {
-  logTestInfo("start - updater test cleanup");
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
-  try {
-    removeDirRecursive(updatesDir);
-  }
-  catch (e) {
-    dump("Unable to remove directory\n" +
-         "path: " + updatesDir.path + "\n" +
-         "Exception: " + e + "\n");
-  }
-
-  // Try to remove the updates and the apply to directories.
-  let applyToDir = getApplyDirFile(null, true).parent;
-  try {
-    removeDirRecursive(applyToDir);
-  }
-  catch (e) {
-    dump("Unable to remove directory\n" +
-         "path: " + applyToDir.path + "\n" +
-         "Exception: " + e + "\n");
-  }
-
-  cleanupTestCommon();
-  logTestInfo("finish - updater test cleanup");
-}
-
-/**
  * Helper function for updater binary tests for verifying the contents of the
  * update log after a successful update.
+ *
+ * @param   aCompareLogFile
+ *          The log file to compare the update log with.
  */
 function checkUpdateLogContents(aCompareLogFile) {
-  let updateLog = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
+  let updateLog = getUpdatesPatchDir();
   updateLog.append(FILE_UPDATE_LOG);
   let updateLogContents = readFileBytes(updateLog);
-  if (gBackgroundUpdate) {
-    // Skip the background update messages
-    updateLogContents = updateLogContents.replace(/Performing a background update/, "");
+
+  if (gStageUpdate) {
+    // Skip the staged update messages
+    updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
   } else if (gSwitchApp) {
     // Skip the switch app request messages
-    updateLogContents = updateLogContents.replace(/Performing a background update/, "");
+    updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
     updateLogContents = updateLogContents.replace(/Performing a replace request/, "");
   }
   // Skip the source/destination lines since they contain absolute paths.
   updateLogContents = updateLogContents.replace(/SOURCE DIRECTORY.*/g, "");
   updateLogContents = updateLogContents.replace(/DESTINATION DIRECTORY.*/g, "");
   // Skip lines that log failed attempts to open the callback executable.
-  updateLogContents = updateLogContents.replace(/NS_main: callback app open attempt .*/g, "");
+  updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, "");
   if (gSwitchApp) {
     // Remove the lines which contain absolute paths
     updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, "");
 #ifdef XP_MACOSX
     // Remove the entire section about moving the precomplete file as it contains
     // absolute paths.
     updateLogContents = updateLogContents.replace(/\n/g, "%%%EOL%%%");
     updateLogContents = updateLogContents.replace(/Moving the precomplete file.*Finished moving the precomplete file/, "");
@@ -1369,104 +1767,107 @@ function checkUpdateLogContents(aCompare
   // Remove leading and trailing newlines
   compareLogContents = compareLogContents.replace(/^\n|\n$/g, "");
 
   // Don't write the contents of the file to the log to reduce log spam
   // unless there is a failure.
   if (compareLogContents == updateLogContents) {
     logTestInfo("log contents are correct");
     do_check_true(true);
-  }
-  else {
+  } else {
     logTestInfo("log contents are not correct");
     do_check_eq(compareLogContents, updateLogContents);
   }
 }
 
+/**
+ * Helper function to check if the update log contains a string.
+ *
+ * @param   aCheckString
+ *          The string to check if the update log contains.
+ */
 function checkUpdateLogContains(aCheckString) {
-  let updateLog = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
+  let updateLog = getUpdatesPatchDir();
   updateLog.append(FILE_UPDATE_LOG);
   let updateLogContents = readFileBytes(updateLog);
   if (updateLogContents.indexOf(aCheckString) != -1) {
     logTestInfo("log file does contain: " + aCheckString);
     do_check_true(true);
-  }
-  else {
+  } else {
     logTestInfo("log file does not contain: " + aCheckString);
     logTestInfo("log file contents:\n" + updateLogContents);
     do_check_true(false);
   }
 }
 
 /**
  * Helper function for updater binary tests for verifying the state of files and
  * directories after a successful update.
  */
 function checkFilesAfterUpdateSuccess() {
   logTestInfo("testing contents of files after a successful update");
   TEST_FILES.forEach(function CFAUS_TF_FE(aTestFile) {
-    let testFile = getTargetDirFile(aTestFile.relPathDir + aTestFile.fileName, true);
+    let testFile = getTargetDirFile(aTestFile.relPathDir + aTestFile.fileName,
+                                    true);
     logTestInfo("testing file: " + testFile.path);
     if (aTestFile.compareFile || aTestFile.compareContents) {
       do_check_true(testFile.exists());
 
       // Skip these tests on Windows and OS/2 since their
       // implementaions of chmod doesn't really set permissions.
       if (!IS_WIN && !IS_OS2 && aTestFile.comparePerms) {
         // Check if the permssions as set in the complete mar file are correct.
         let logPerms = "testing file permissions - ";
         if (aTestFile.originalPerms) {
-          logPerms += "original permissions: " + aTestFile.originalPerms.toString(8) + ", ";
+          logPerms += "original permissions: " +
+                      aTestFile.originalPerms.toString(8) + ", ";
         }
-        logPerms += "compare permissions : " + aTestFile.comparePerms.toString(8) + ", ";
+        logPerms += "compare permissions : " +
+                    aTestFile.comparePerms.toString(8) + ", ";
         logPerms += "updated permissions : " + testFile.permissions.toString(8);
         logTestInfo(logPerms);
         do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
       }
 
       let fileContents1 = readFileBytes(testFile);
       let fileContents2 = aTestFile.compareFile ?
                           readFileBytes(getTestDirFile(aTestFile.compareFile)) :
                           aTestFile.compareContents;
       // Don't write the contents of the file to the log to reduce log spam
       // unless there is a failure.
       if (fileContents1 == fileContents2) {
         logTestInfo("file contents are correct");
         do_check_true(true);
-      }
-      else {
+      } else {
         logTestInfo("file contents are not correct");
         do_check_eq(fileContents1, fileContents2);
       }
-    }
-    else {
+    } else {
       do_check_false(testFile.exists());
     }
   });
 
   logTestInfo("testing operations specified in removed-files were performed " +
               "after a successful update");
   var testDirs = TEST_DIRS.concat(ADDITIONAL_TEST_DIRS);
   testDirs.forEach(function CFAUS_TD_FE(aTestDir) {
     let testDir = getTargetDirFile(aTestDir.relPathDir, true);
     logTestInfo("testing directory: " + testDir.path);
     if (aTestDir.dirRemoved) {
       do_check_false(testDir.exists());
-    }
-    else {
+    } else {
       do_check_true(testDir.exists());
 
       if (aTestDir.files) {
         aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) {
           let testFile = getTargetDirFile(aTestDir.relPathDir + aTestFile, true);
           logTestInfo("testing directory file: " + testFile.path);
           if (aTestDir.filesRemoved) {
             do_check_false(testFile.exists());
-          }
-          else {
+          } else {
             do_check_true(testFile.exists());
           }
         });
       }
 
       if (aTestDir.subDirs) {
         aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
           let testSubDir = getTargetDirFile(aTestDir.relPathDir + aSubDir, true);
@@ -1504,40 +1905,40 @@ function checkFilesAfterUpdateFailure(aG
       do_check_true(testFile.exists());
 
       // Skip these tests on Windows and OS/2 since their
       // implementaions of chmod doesn't really set permissions.
       if (!IS_WIN && !IS_OS2 && aTestFile.comparePerms) {
         // Check the original permssions are retained on the file.
         let logPerms = "testing file permissions - ";
         if (aTestFile.originalPerms) {
-          logPerms += "original permissions: " + aTestFile.originalPerms.toString(8) + ", ";
+          logPerms += "original permissions: " +
+                      aTestFile.originalPerms.toString(8) + ", ";
         }
-        logPerms += "compare permissions : " + aTestFile.comparePerms.toString(8) + ", ";
+        logPerms += "compare permissions : " +
+                    aTestFile.comparePerms.toString(8) + ", ";
         logPerms += "updated permissions : " + testFile.permissions.toString(8);
         logTestInfo(logPerms);
         do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
       }
 
       let fileContents1 = readFileBytes(testFile);
       let fileContents2 = aTestFile.compareFile ?
                           readFileBytes(getTestDirFile(aTestFile.compareFile)) :
                           aTestFile.compareContents;
       // Don't write the contents of the file to the log to reduce log spam
       // unless there is a failure.
       if (fileContents1 == fileContents2) {
         logTestInfo("file contents are correct");
         do_check_true(true);
-      }
-      else {
+      } else {
         logTestInfo("file contents are not correct");
         do_check_eq(fileContents1, fileContents2);
       }
-    }
-    else {
+    } else {
       do_check_false(testFile.exists());
     }
   });
 
   logTestInfo("testing operations specified in removed-files were not " +
               "performed after a failed update");
   TEST_DIRS.forEach(function CFAUF_TD_FE(aTestDir) {
     let testDir = getdir(aTestDir.relPathDir, true);
@@ -1554,17 +1955,18 @@ function checkFilesAfterUpdateFailure(aG
 
     if (aTestDir.subDirs) {
       aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
         let testSubDir = getdir(aTestDir.relPathDir + aSubDir, true);
         logTestInfo("testing sub-directory: " + testSubDir.path);
         do_check_true(testSubDir.exists());
         if (aTestDir.subDirFiles) {
           aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) {
-            let testFile = getdir(aTestDir.relPathDir + aSubDir + aTestFile, true);
+            let testFile = getdir(aTestDir.relPathDir + aSubDir + aTestFile,
+                                  true);
             logTestInfo("testing sub-directory file: " + testFile.path);
             do_check_true(testFile.exists());
           });
         }
       });
     }
   });
 
@@ -1572,17 +1974,17 @@ function checkFilesAfterUpdateFailure(aG
 }
 
 /**
  * Helper function for updater binary tests for verifying patch files and
  * moz-backup files aren't left behind after a successful or failed update.
  */
 function checkFilesAfterUpdateCommon() {
   logTestInfo("testing patch files should not be left behind");
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
+  let updatesDir = getUpdatesPatchDir();
   let entries = updatesDir.QueryInterface(AUS_Ci.nsIFile).directoryEntries;
   while (entries.hasMoreElements()) {
     let entry = entries.getNext().QueryInterface(AUS_Ci.nsIFile);
     do_check_neq(getFileExtension(entry), "patch");
   }
 
   logTestInfo("testing backup files should not be left behind");
   let applyToDir = getTargetDirFile(null, true);
@@ -1610,151 +2012,98 @@ function checkCallbackAppLog() {
   if (logContents != expectedLogContents) {
     do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog);
     return;
   }
 
   if (logContents == expectedLogContents) {
     logTestInfo("callback log file contents are correct");
     do_check_true(true);
-  }
-  else {
+  } else {
     logTestInfo("callback log file contents are not correct");
     do_check_eq(logContents, expectedLogContents);
   }
 
-  removeCallbackCopy();
+  waitForFilesInUse();
 }
 
 /**
  * Helper function for updater service tests for verifying the contents of the
  * updater callback application log which should contain the arguments passed to
  * the callback application.
  */
 function checkCallbackServiceLog() {
   do_check_neq(gServiceLaunchedCallbackLog, null);
 
   let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n";
   let logFile = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
   logFile.initWithPath(gServiceLaunchedCallbackLog);
   let logContents = readFile(logFile);
-
   // It is possible for the log file contents check to occur before the log file
   // contents are completely written so wait until the contents are the expected
   // value. If the contents are never the expected value then the test will
   // fail by timing out.
   if (logContents != expectedLogContents) {
     logTestInfo("callback service log not expected value, waiting longer");
     do_timeout(TEST_HELPER_TIMEOUT, checkCallbackServiceLog);
     return;
   }
 
   logTestInfo("testing that the callback application successfully launched " +
-              "and the expected command line arguments passed to it");
+              "and the expected command line arguments were passed to it");
   do_check_eq(logContents, expectedLogContents);
 
-  removeCallbackCopy();
-}
-
-function removeCallbackCopy() {
-  // Remove the copy of the application executable used for the test on
-  // Windows if it exists.
-  let appBinCopy = getAppDir();
-  appBinCopy.append(gTestID + FILE_WIN_TEST_EXE);
-  if (appBinCopy.exists()) {
-    try {
-      logTestInfo("attempting removal of file: " + appBinCopy.path);
-      appBinCopy.remove(false);
-    }
-    catch (e) {
-      logTestInfo("non-fatal error removing file after test finished (will " +
-                  "try again). File: " + appBinCopy.path + " Exception: " + e);
-      do_timeout(TEST_HELPER_TIMEOUT, removeCallbackCopy);
-      return;
-    }
-  }
-  logTestInfo("attempting removal of the updater binary");
-  removeUpdater();
-}
-
-
-/**
- * Helper function for updater tests that removes the updater binary before
- * ending the test so the updater binary isn't in use during test cleanup.
- */
-function removeUpdater() {
-  if (IS_WIN) {
-    // Remove the copy of the application executable used for the test on
-    // Windows if it exists.
-    let updater = getUpdatesDir();
-    updater.append("0");
-    updater.append(FILE_UPDATER_BIN);
-    if (updater.exists()) {
-      try {
-        updater.remove(false);
-      }
-      catch (e) {
-        logTestInfo("non-fatal error removing file after test finished (will " +
-                    "try again). File: " + updater.path + " Exception: " + e);
-        do_timeout(TEST_HELPER_TIMEOUT, removeUpdater);
-        return;
-      }
-    }
-    else {
-      logTestInfo("updater doesn't exist, path: " + updater.path);
-    }
-  }
-  logTestInfo("calling do_test_finished");
-  do_test_finished();
+  waitForFilesInUse();
 }
 
 // Waits until files that are in use that break tests are no longer in use and
-// then calls removeCallbackCopy.
+// then calls do_test_finished.
 function waitForFilesInUse() {
-  let maintSvcInstaller = getAppDir();
-  maintSvcInstaller.append("FILE_MAINTENANCE_SERVICE_INSTALLER_BIN");
-
-  let helper = getAppDir();
-  helper.append("uninstall");
-  helper.append("helper.exe");
+  if (IS_WIN) {
+    let appBin = getApplyDirFile(FILE_APP_BIN, true);
+    let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true);
+    let helper = getApplyDirFile("uninstall/helper.exe", true);
+    let updater = getUpdatesPatchDir();
+    updater.append(FILE_UPDATER_BIN);
 
-  let files = [maintSvcInstaller, helper];
-  for (let i = 0; i < files.length; ++i) {
-    let file = files[i];
-    let fileBak = file.parent.clone();
-    if (file.exists()) {
-      fileBak.append(file.leafName + ".bak");
-      try {
-        if (fileBak.exists()) {
-          fileBak.remove(false);
-        }
-        file.copyTo(fileBak.parent, fileBak.leafName);
-        file.remove(false);
-        fileBak.moveTo(file.parent, file.leafName);
-        logTestInfo("file is not in use. path: " + file.path);
-      }
-      catch (e) {
-        logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT +
-                    " ms, path: " + file.path + ", exception: " + e);
+    let files = [appBin, updater, maintSvcInstaller, helper];
+
+    for (var i = 0; i < files.length; ++i) {
+      let file = files[i];
+      let fileBak = file.parent.clone();
+      if (file.exists()) {
+        fileBak.append(file.leafName + ".bak");
         try {
           if (fileBak.exists()) {
             fileBak.remove(false);
           }
+          file.copyTo(fileBak.parent, fileBak.leafName);
+          file.remove(false);
+          fileBak.moveTo(file.parent, file.leafName);
+          logTestInfo("file is not in use. Path: " + file.path);
+        } catch (e) {
+          logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT +
+                      " ms, Path: " + file.path + ", Exception: " + e);
+          try {
+            if (fileBak.exists()) {
+              fileBak.remove(false);
+            }
+          } catch (e) {
+            logTestInfo("unable to remove file, this should never happen! " +
+                        "Path: " + fileBak.path + ", Exception: " + e);
+          }
+          do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse);
+          return;
         }
-        catch (e) {
-          logTestInfo("unable to remove file, this should never happen! " +
-                      "path: " + fileBak.path + ", exception: " + e);
-        }
-        do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse);
-        return;
       }
     }
   }
 
-  removeCallbackCopy();
+  logTestInfo("calling do_test_finished");
+  do_test_finished();
 }
 
 /**
  * Helper function for updater binary tests for verifying there are no update
  * backup files left behind after an update.
  *
  * @param   aFile
  *          An nsIFile to check if it has moz-backup for its extension.
@@ -1779,218 +2128,222 @@ function checkFilesInDirRecursive(aDir, 
     do_throw("Directory must exist!");
 
   let dirEntries = aDir.directoryEntries;
   while (dirEntries.hasMoreElements()) {
     let entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
 
     if (entry.isDirectory()) {
       checkFilesInDirRecursive(entry, aCallback);
-    }
-    else {
+    } else {
       aCallback(entry);
     }
   }
 }
 
 /**
  * Sets up the bare bones XMLHttpRequest implementation below.
  *
- * @param   callback
+ * @param   aCallback
  *          The callback function that will call the nsIDomEventListener's
  *          handleEvent method.
  *
  *          Example of the callback function
  *
  *            function callHandleEvent() {
  *              gXHR.status = gExpectedStatus;
  *              var e = { target: gXHR };
  *              gXHR.onload.handleEvent(e);
  *            }
  */
-function overrideXHR(callback) {
-  gXHRCallback = callback;
+function overrideXHR(aCallback) {
+  gXHRCallback = aCallback;
   gXHR = new xhr();
   var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.registerFactory(gXHR.classID, gXHR.classDescription,
                             gXHR.contractID, gXHR);
 }
 
 
 /**
  * Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
  * and onload nsIDomEventListener handleEvent.
  */
-function makeHandler(val) {
-  if (typeof val == "function")
-    return ({ handleEvent: val });
-  return val;
+function makeHandler(aVal) {
+  if (typeof aVal == "function")
+    return { handleEvent: aVal };
+  return aVal;
 }
 function xhr() {
 }
 xhr.prototype = {
-  overrideMimeType: function(mimetype) { },
-  setRequestHeader: function(header, value) { },
+  overrideMimeType: function(aMimetype) { },
+  setRequestHeader: function(aHeader, aValue) { },
   status: null,
-  channel: { set notificationCallbacks(val) { } },
+  channel: { set notificationCallbacks(aVal) { } },
   _url: null,
   _method: null,
-  open: function (method, url) {
-    gXHR.channel.originalURI = Services.io.newURI(url, null, null);
-    gXHR._method = method; gXHR._url = url;
+  open: function(aMethod, aUrl) {
+    gXHR.channel.originalURI = Services.io.newURI(aUrl, null, null);
+    gXHR._method = aMethod; gXHR._url = aUrl;
   },
   responseXML: null,
   responseText: null,
-  send: function(body) {
+  send: function(aBody) {
     do_execute_soon(gXHRCallback); // Use a timeout so the XHR completes
   },
   _onprogress: null,
-  set onprogress(val) { gXHR._onprogress = makeHandler(val); },
+  set onprogress(aValue) { gXHR._onprogress = makeHandler(aValue); },
   get onprogress() { return gXHR._onprogress; },
   _onerror: null,
-  set onerror(val) { gXHR._onerror = makeHandler(val); },
+  set onerror(aValue) { gXHR._onerror = makeHandler(aValue); },
   get onerror() { return gXHR._onerror; },
   _onload: null,
-  set onload(val) { gXHR._onload = makeHandler(val); },
+  set onload(aValue) { gXHR._onload = makeHandler(aValue); },
   get onload() { return gXHR._onload; },
-  addEventListener: function(event, val, capturing) {
-    eval("gXHR._on" + event + " = val");
+  addEventListener: function(aEvent, aValue, aCapturing) {
+    eval("gXHR._on" + aEvent + " = aValue");
   },
   flags: AUS_Ci.nsIClassInfo.SINGLETON,
   implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
-  getHelperForLanguage: function(language) null,
-  getInterfaces: function(count) {
+  getHelperForLanguage: function(aLanguage) null,
+  getInterfaces: function(aCount) {
     var interfaces = [AUS_Ci.nsISupports];
-    count.value = interfaces.length;
+    aCount.value = interfaces.length;
     return interfaces;
   },
   classDescription: "XMLHttpRequest",
   contractID: "@mozilla.org/xmlextras/xmlhttprequest;1",
   classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"),
-  createInstance: function (outer, aIID) {
-    if (outer == null)
+  createInstance: function(aOuter, aIID) {
+    if (aOuter == null)
       return gXHR.QueryInterface(aIID);
     throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(AUS_Ci.nsIClassInfo) ||
         aIID.equals(AUS_Ci.nsISupports))
       return gXHR;
     throw AUS_Cr.NS_ERROR_NO_INTERFACE;
   },
   get wrappedJSObject() { return this; }
 };
 
-function overrideUpdatePrompt(callback) {
+/**
+ * Helper function to override the update prompt component to verify whether it
+ * is called or not.
+ *
+ * @param   aCallback
+ *          The callback to call if the update prompt component is called.
+ */
+function overrideUpdatePrompt(aCallback) {
   var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   gUpdatePrompt = new UpdatePrompt();
-  gUpdatePromptCallback = callback;
+  gUpdatePromptCallback = aCallback;
   registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription,
                             gUpdatePrompt.contractID, gUpdatePrompt);
 }
 
 function UpdatePrompt() {
   var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded",
              "showUpdateError", "showUpdateHistory", "showUpdateInstalled"];
 
-  fns.forEach(function(promptFn) {
-    UpdatePrompt.prototype[promptFn] = function() {
+  fns.forEach(function(aPromptFn) {
+    UpdatePrompt.prototype[aPromptFn] = function() {
       if (!gUpdatePromptCallback) {
         return;
       }
 
-      var callback = gUpdatePromptCallback[promptFn];
+      var callback = gUpdatePromptCallback[aPromptFn];
       if (!callback) {
         return;
       }
 
       callback.apply(gUpdatePromptCallback,
                      Array.prototype.slice.call(arguments));
     }
   });
 }
 
 UpdatePrompt.prototype = {
   flags: AUS_Ci.nsIClassInfo.SINGLETON,
   implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
-  getHelperForLanguage: function(language) null,
-  getInterfaces: function(count) {
+  getHelperForLanguage: function(aLanguage) null,
+  getInterfaces: function(aCount) {
     var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt];
-    count.value = interfaces.length;
+    aCount.value = interfaces.length;
     return interfaces;
   },
   classDescription: "UpdatePrompt",
   contractID: "@mozilla.org/updates/update-prompt;1",
   classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"),
-  createInstance: function (outer, aIID) {
-    if (outer == null)
+  createInstance: function(aOuter, aIID) {
+    if (aOuter == null)
       return gUpdatePrompt.QueryInterface(aIID);
     throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(AUS_Ci.nsIClassInfo) ||
         aIID.equals(AUS_Ci.nsISupports) ||
         aIID.equals(AUS_Ci.nsIUpdatePrompt))
       return gUpdatePrompt;
     throw AUS_Cr.NS_ERROR_NO_INTERFACE;
   },
 };
 
-
-
 /* Update check listener */
 const updateCheckListener = {
-  onProgress: function UCL_onProgress(request, position, totalSize) {
+  onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) {
   },
 
-  onCheckComplete: function UCL_onCheckComplete(request, updates, updateCount) {
-    gRequestURL = request.channel.originalURI.spec;
-    gUpdateCount = updateCount;
-    gUpdates = updates;
+  onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) {
+    gRequestURL = aRequest.channel.originalURI.spec;
+    gUpdateCount = aUpdateCount;
+    gUpdates = aUpdates;
     logTestInfo("url = " + gRequestURL + ", " +
-                "request.status = " + request.status + ", " +
-                "update.statusText = " + request.statusText + ", " +
-                "updateCount = " + updateCount);
+                "request.status = " + aRequest.status + ", " +
+                "update.statusText = " + aRequest.statusText + ", " +
+                "updateCount = " + aUpdateCount);
     // Use a timeout to allow the XHR to complete
     do_execute_soon(gCheckFunc);
   },
 
-  onError: function UCL_onError(request, update) {
-    gRequestURL = request.channel.originalURI.spec;
-    gStatusCode = request.status;
+  onError: function UCL_onError(aRequest, aUpdate) {
+    gRequestURL = aRequest.channel.originalURI.spec;
+    gStatusCode = aRequest.status;
 
-    gStatusText = update.statusText;
+    gStatusText = aUpdate.statusText;
     logTestInfo("url = " + gRequestURL + ", " +
                 "request.status = " + gStatusCode + ", " +
                 "update.statusText = " + gStatusText);
     // Use a timeout to allow the XHR to complete
-    do_execute_soon(gCheckFunc.bind(null, request, update));
+    do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate));
   },
 
   QueryInterface: function(aIID) {
     if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) &&
         !aIID.equals(AUS_Ci.nsISupports))
       throw AUS_Cr.NS_ERROR_NO_INTERFACE;
     return this;
   }
 };
 
 /* Update download listener - nsIRequestObserver */
 const downloadListener = {
-  onStartRequest: function DL_onStartRequest(request, context) {
+  onStartRequest: function DL_onStartRequest(aRequest, aContext) {
   },
 
-  onProgress: function DL_onProgress(request, context, progress, maxProgress) {
+  onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) {
   },
 
-  onStatus: function DL_onStatus(request, context, status, statusText) {
+  onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) {
   },
 
-  onStopRequest: function DL_onStopRequest(request, context, status) {
-    gStatusResult = status;
+  onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) {
+    gStatusResult = aStatus;
     // Use a timeout to allow the request to complete
     do_execute_soon(gCheckFunc);
   },
 
   QueryInterface: function DL_QueryInterface(aIID) {
     if (!aIID.equals(AUS_Ci.nsIRequestObserver) &&
         !aIID.equals(AUS_Ci.nsIProgressEventSink) &&
         !aIID.equals(AUS_Ci.nsISupports))
@@ -1999,166 +2352,147 @@ const downloadListener = {
   }
 };
 
 /**
  * Helper for starting the http server used by the tests
  */
 function start_httpserver() {
   let dir = getTestDirFile();
-  logTestInfo("http server file path: " + dir.path);
+  logTestInfo("http server directory path: " + dir.path);
 
   if (!dir.isDirectory()) {
     do_throw("A file instead of a directory was specified for HttpServer " +
-             "registerDirectory! path: " + dir.path + "\n");
+             "registerDirectory! Path: " + dir.path + "\n");
   }
 
-  Components.utils.import("resource://testing-common/httpd.js");
+  AUS_Cu.import("resource://testing-common/httpd.js");
   gTestserver = new HttpServer();
   gTestserver.registerDirectory("/", dir);
   gTestserver.start(-1);
   let testserverPort = gTestserver.identity.primaryPort;
   gURLData = URL_HOST + ":" + testserverPort + "/";
   logTestInfo("http server port = " + testserverPort);
 }
 
-/* Helper for stopping the http server used by the tests */
-function stop_httpserver(callback) {
-  do_check_true(!!callback);
-  gTestserver.stop(callback);
+/**
+ * Helper for stopping the http server used by the tests
+ *
+ * @param   aCallback
+ *          The callback to call after stopping the http server.
+ */
+function stop_httpserver(aCallback) {
+  do_check_true(!!aCallback);
+  gTestserver.stop(aCallback);
 }
 
 /**
  * Creates an nsIXULAppInfo
  *
- * @param   id
+ * @param   aID
  *          The ID of the test application
- * @param   name
+ * @param   aName
  *          A name for the test application
- * @param   version
+ * @param   aVersion
  *          The version of the application
- * @param   platformVersion
+ * @param   aPlatformVersion
  *          The gecko version of the application
  */
-function createAppInfo(id, name, version, platformVersion) {
+function createAppInfo(aID, aName, aVersion, aPlatformVersion) {
   const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
   const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
   var XULAppInfo = {
     vendor: APP_INFO_VENDOR,
-    name: name,
-    ID: id,
-    version: version,
+    name: aName,
+    ID: aID,
+    version: aVersion,
     appBuildID: "2007010101",
-    platformVersion: platformVersion,
+    platformVersion: aPlatformVersion,
     platformBuildID: "2007010101",
     inSafeMode: false,
     logConsoleErrors: true,
     OS: "XPCShell",
     XPCOMABI: "noarch-spidermonkey",
 
-    QueryInterface: function QueryInterface(iid) {
-      if (iid.equals(AUS_Ci.nsIXULAppInfo) ||
-          iid.equals(AUS_Ci.nsIXULRuntime) ||
+    QueryInterface: function QueryInterface(aIID) {
+      if (aIID.equals(AUS_Ci.nsIXULAppInfo) ||
+          aIID.equals(AUS_Ci.nsIXULRuntime) ||
 #ifdef XP_WIN
-          iid.equals(AUS_Ci.nsIWinAppHelper) ||
+          aIID.equals(AUS_Ci.nsIWinAppHelper) ||
 #endif
-          iid.equals(AUS_Ci.nsISupports))
+          aIID.equals(AUS_Ci.nsISupports))
         return this;
       throw AUS_Cr.NS_ERROR_NO_INTERFACE;
     }
   };
 
   var XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer == null)
-        return XULAppInfo.QueryInterface(iid);
+    createInstance: function (aOuter, aIID) {
+      if (aOuter == null)
+        return XULAppInfo.QueryInterface(aIID);
       throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
     }
   };
 
   var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
                             XULAPPINFO_CONTRACTID, XULAppInfoFactory);
 }
 
 /**
  * Returns the platform specific arguments used by nsIProcess when launching
  * the application.
  *
- * @param aExtraArgs optional array of extra arguments
+ * @param   aExtraArgs (optional)
+ *          An array of extra arguments to append to the default arguments.
  * @return  an array of arguments to be passed to nsIProcess.
  *
- * Notes:
- * 1. Mozilla universal binaries that contain both i386 and x86_64 on Mac OS X
- *    10.5.x must be launched using the i386 architecture.
- * 2. A shell is necessary to pipe the application's console output which
- *    would otherwise pollute the xpcshell log.
+ * Note: a shell is necessary to pipe the application's console output which
+ *       would otherwise pollute the xpcshell log.
  *
  * Command line arguments used when launching the application:
  * -no-remote prevents shell integration from being affected by an existing
  * application process.
  * -process-updates makes the application exits after being relaunched by the
  * updater.
- * 1> pipes stdout to a file.
- * appConsoleLogPath is the file path to pipe the output from the shell.
- * Otherwise the output from the application will end up in the xpchsell log.
- * 2>&1 pipes stderr to sdout.
+ * the platform specific string defined by PIPE_TO_NULL to output both stdout
+ * and stderr to null. This is needed to prevent output from the application
+ * from ending up in the xpchsell log.
  */
 function getProcessArgs(aExtraArgs) {
   if (!aExtraArgs) {
     aExtraArgs = [];
   }
 
-  // Pipe the output from the launched application to a file so the output from
-  // its console isn't present in the xpcshell log.
-  let appConsoleLogPath = getAppConsoleLogPath();
+  let appBinPath = getApplyDirFile(FILE_APP_BIN, false).path;
+  if (/ /.test(appBinPath)) {
+    appBinPath = '"' + appBinPath + '"';
+  }
 
   let args;
   if (IS_UNIX) {
     let launchScript = getLaunchScript();
     // Precreate the script with executable permissions
     launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY);
 
     let scriptContents = "#! /bin/sh\n";
-    scriptContents += gAppBinPath + " -no-remote -process-updates " +
-                      aExtraArgs.join(" ") + " 1> " +
-                      appConsoleLogPath + " 2>&1";
+    scriptContents += appBinPath + " -no-remote -process-updates " +
+                      aExtraArgs.join(" ") + " " + PIPE_TO_NULL;
     writeFile(launchScript, scriptContents);
     logTestInfo("created " + launchScript.path + " containing:\n" +
                 scriptContents);
     args = [launchScript.path];
-  }
-  else {
-    args = ["/D", "/Q", "/C", gAppBinPath, "-no-remote", "-process-updates"].
-           concat(aExtraArgs).
-           concat(["1>", appConsoleLogPath, "2>&1"]);
+  } else {
+    args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"].
+           concat(aExtraArgs).concat(["1> nul 2>&1"]);
   }
   return args;
 }
 
 /**
- * Gets a file path for piping the console output from the application so it
- * doesn't appear in the xpcshell log file.
- *
- * @return  path to the file for piping the console output from the application.
- */
-function getAppConsoleLogPath() {
-  let appConsoleLog = do_get_file("/", true);
-  appConsoleLog.append(gTestID + "_app_console_log");
-  if (appConsoleLog.exists()) {
-    appConsoleLog.remove(false);
-  }
-  let appConsoleLogPath = appConsoleLog.path;
-  if (/ /.test(appConsoleLogPath)) {
-    appConsoleLogPath = '"' + appConsoleLogPath + '"';
-  }
-  return appConsoleLogPath;
-}
-
-/**
  * Gets a file path for the application to dump its arguments into.  This is used
  * to verify that a callback application is launched.
  *
  * @return  the file for the application to dump its arguments into.
  */
 function getAppArgsLogPath() {
   let appArgsLog = do_get_file("/", true);
   appArgsLog.append(gTestID + "_app_args_log");
@@ -2183,275 +2517,162 @@ function getLaunchScript() {
   launchScript.append(gTestID + "_launch.sh");
   if (launchScript.exists()) {
     launchScript.remove(false);
   }
   return launchScript;
 }
 
 /**
- * Checks for the existence of a platform specific application binary that can
- * be used for the test and gets its path if it is found.
- *
- * Note: The application shell scripts for launching the application work on all
- * platforms that provide a launch shell script except for Mac OS X 10.5 which
- * is why this test uses the binaries to launch the application.
- */
-XPCOMUtils.defineLazyGetter(this, "gAppBinPath", function test_gAppBinPath() {
-  let processDir = getAppDir();
-  let appBin = processDir.clone();
-  appBin.append(APP_BIN_NAME + APP_BIN_SUFFIX);
-  if (appBin.exists()) {
-    if (IS_WIN) {
-      let appBinCopy = processDir.clone();
-      appBinCopy.append(gTestID + FILE_WIN_TEST_EXE);
-      if (appBinCopy.exists()) {
-        appBinCopy.remove(false);
-      }
-      appBin.copyTo(processDir, gTestID + FILE_WIN_TEST_EXE);
-      appBin = processDir.clone();
-      appBin.append(gTestID + FILE_WIN_TEST_EXE);
-    }
-    let appBinPath = appBin.path;
-    if (/ /.test(appBinPath)) {
-      appBinPath = '"' + appBinPath + '"';
-    }
-    return appBinPath;
-  }
-  return null;
-});
-
-/**
- * This dummy function just returns false.  Tests which wish to adjust the app
- * directory on Mac OS X should define a real version of this function.
+ * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so
+ * xpcshell tests can run in parallel and to keep the environment clean.
  */
-function shouldAdjustPathsOnMac() {
-  return false;
-}
-
-// Override getUpdatesRootDir on Mac because we need to apply the update
-// inside the bundle directory.
-function symlinkUpdateFilesIntoBundleDirectory() {
-  if (!shouldAdjustPathsOnMac()) {
-    return;
-  }
-  // Symlink active-update.xml and updates/ inside the dist/bin directory
-  // to point to the bundle directory.
-  // This is necessary because in order to test the code which actually ships
-  // with Firefox, we need to perform the update inside the bundle directory,
-  // whereas xpcshell runs from dist/bin/, and the updater service code looks
-  // at the current process directory to find things like these two files.
-
-  Components.utils.import("resource://gre/modules/ctypes.jsm");
-  let libc = ctypes.open("/usr/lib/libc.dylib");
-  // We need these two low level APIs because their functionality is not
-  // provided in nsIFile APIs.
-  let symlink = libc.declare("symlink", ctypes.default_abi, ctypes.int,
-                             ctypes.char.ptr, ctypes.char.ptr);
-  let unlink = libc.declare("unlink", ctypes.default_abi, ctypes.int,
-                            ctypes.char.ptr);
-
-  // Symlink active-update.xml
-  let dest = getAppDir();
-  dest.append("active-update.xml");
-  if (!dest.exists()) {
-    dest.create(dest.NORMAL_FILE_TYPE, 0o644);
-  }
-  do_check_true(dest.exists());
-  let source = getUpdatesRootDir();
-  source.append("active-update.xml");
-  unlink(source.path);
-  let ret = symlink(dest.path, source.path);
-  do_check_eq(ret, 0);
-  do_check_true(source.exists());
-
-  // Symlink updates/
-  let dest2 = getAppDir();
-  dest2.append("updates");
-  if (dest2.exists()) {
-    dest2.remove(true);
-  }
-  dest2.create(dest.DIRECTORY_TYPE, 0o755);
-  do_check_true(dest2.exists());
-  let source2 = getUpdatesRootDir();
-  source2.append("updates");
-  if (source2.exists()) {
-    source2.remove(true);
-  }
-  ret = symlink(dest2.path, source2.path);
-  do_check_eq(ret, 0);
-  do_check_true(source2.exists());
-
-  // Cleanup the symlinks when the test is finished.
-  do_register_cleanup(function AUFIBD_cleanup() {
-    logTestInfo("start - unlinking symlinks");
-    let ret = unlink(source.path);
-    do_check_false(source.exists());
-    let ret = unlink(source2.path);
-    do_check_false(source2.exists());
-    logTestInfo("finish - unlinking symlinks");
-  });
-
-  // Now, make sure that getUpdatesRootDir returns the application bundle
-  // directory, to make the various stuff in the test framework to work
-  // correctly.
-  getUpdatesRootDir = getAppDir;
-}
-
-/**
- * This function copies the entire process directory over to a new one which we
- * can write to, so that we can test under Windows which holds locks on opened
- * files.
- */
-function adjustPathsOnWindows() {
-  logTestInfo("start - setup new process directory");
-  // We copy the entire GRE directory into another location so that xpcshell
-  // running doesn't prevent the updater from moving stuff around.
-  let tmpDir = do_get_profile();
-  tmpDir.append("ExecutableDir.tmp");
-  tmpDir.createUnique(tmpDir.DIRECTORY_TYPE, 0o755);
-  let procDir = getCurrentProcessDir();
-  logTestInfo("start - copy the process directory");
-  copyMinimumAppFiles(procDir, tmpDir, "bin");
-  logTestInfo("finish - copy the process directory");
-  let newDir = tmpDir.clone();
-  newDir.append("bin");
-  gWindowsBinDir = newDir;
-  logTestInfo("Using this new bin directory: " + gWindowsBinDir.path);
-  // Note that this directory will be deleted as part of the xpcshell teardown,
-  // so we don't need to remove it explicitly.
-
-  // We need to make NS_GRE_DIR point to the new bindir, since
-  // nsUpdateProcessor::ProcessUpdate uses NS_GRE_DIR to construct the
-  // destination path name which would be passed to updater.exe.
+function adjustGeneralPaths() {
   let dirProvider = {
-    getFile: function DP_getFile(prop, persistent) {
-      persistent.value = true;
-      if (prop == NS_GRE_DIR)
-        return getAppDir();
+    getFile: function AGP_DP_getFile(aProp, aPersistent) {
+      aPersistent.value = true;
+      switch (aProp) {
+        case NS_GRE_DIR:
+          if (gUseTestAppDir) {
+            return getApplyDirFile(null, true);
+          }
+          break;
+        case XRE_EXECUTABLE_FILE:
+          if (gUseTestAppDir) {
+            return getApplyDirFile(FILE_APP_BIN, true);
+          }
+          break;
+        case XRE_UPDATE_ROOT_DIR:
+          return getMockUpdRootD();
+      }
       return null;
     },
-    QueryInterface: function(iid) {
-      if (iid.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
-          iid.equals(AUS_Ci.nsISupports))
+    QueryInterface: function(aIID) {
+      if (aIID.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
+          aIID.equals(AUS_Ci.nsISupports))
         return this;
       throw AUS_Cr.NS_ERROR_NO_INTERFACE;
     }
   };
   let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
   ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
+  ds.QueryInterface(AUS_Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE);
   ds.registerProvider(dirProvider);
-  do_register_cleanup(function APOW_cleanup() {
+  do_register_cleanup(function AGP_cleanup() {
     logTestInfo("start - unregistering directory provider");
-    ds.unregisterProvider(dirProvider);
-    logTestInfo("finish - unregistering directory provider");
-  });
-  logTestInfo("finish - setup new process directory");
-}
 
-let gWindowsBinDir = null;
+    if (gAppTimer) {
+      logTestInfo("start - cancel app timer");
+      gAppTimer.cancel();
+      gAppTimer = null;
+      logTestInfo("finish - cancel app timer");
+    }
 
-/**
- * This function makes XREExeF and UpdRootD point to unique locations so
- * xpcshell tests can run in parallel.
- */
-function adjustGeneralPaths() {
-  let dirProvider = {
-    getFile: function DP_getFile(prop, persistent) {
-      persistent.value = true;
-      if (prop == XRE_EXECUTABLE_FILE)
-        return do_get_file(getApplyDirPath() + "test" + APP_BIN_SUFFIX, true);
-      if (prop == XRE_UPDATE_ROOT_DIR)
-        return do_get_file(getApplyDirPath(), true);
-      return null;
-    },
-    QueryInterface: function(iid) {
-      if (iid.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
-          iid.equals(AUS_Ci.nsISupports))
-        return this;
-      throw AUS_Cr.NS_ERROR_NO_INTERFACE;
+    if (gProcess && gProcess.isRunning) {
+      logTestInfo("start - kill process");
+      try {
+        gProcess.kill();
+      } catch (e) {
+        logTestInfo("kill process failed. Exception: " + e);
+      }
+      gProcess = null;
+      logTestInfo("finish - kill process");
     }
-  };
-  let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
-  ds.registerProvider(dirProvider);
-  do_register_cleanup(function() {
-    // Call end_test first before the directory provider is unregistered
-    end_test();
-    ds.unregisterProvider(dirProvider);
-    let testBin = do_get_file(getApplyDirPath() + "test" + APP_BIN_SUFFIX, true);
-    // Try to remove the test.bin file if it exists (it shouldn't).
-    if (testBin.exists()) {
+
+    if (gHandle) {
       try {
-        testBin.remove(false);
-      }
-      catch (e) {
-        dump("Unable to remove file\n" +
-             "path: " + testBin.path + "\n" +
-             "Exception: " + e + "\n");
+        logTestInfo("start - closing handle");
+        let kernel32 = ctypes.open("kernel32");
+        let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi,
+                                           ctypes.bool, /*return*/
+                                           ctypes.voidptr_t /*handle*/);
+        if (!CloseHandle(gHandle)) {
+          logTestInfo("call to CloseHandle failed");
+        }
+        kernel32.close();
+        gHandle = null;
+        logTestInfo("finish - closing handle");
+      } catch (e) {
+        logTestInfo("call to CloseHandle failed. Exception: " + e);
       }
     }
-    let testDir = do_get_file(getApplyDirPath(), true).parent;
-    // Try to remove the directory used to apply updates (this is non-fatal
-    // for the test).
-    if (testDir.exists()) {
-      try {
-        removeDirRecursive(testDir);
-      }
-      catch (e) {
-        dump("Unable to remove directory\n" +
-             "path: " + testDir.path + "\n" +
-             "Exception: " + e + "\n");
-      }
+
+    // Call end_test first before the directory provider is unregistered
+    if (typeof(end_test) == typeof(Function)) {
+      logTestInfo("calling end_test");
+      end_test();
     }
+
+    ds.unregisterProvider(dirProvider);
+    cleanupTestCommon();
+
+    logTestInfo("finish - unregistering directory provider");
   });
 }
 
+
 /**
- * This function returns the current process directory on Windows and Linux, and
- * the application bundle directory on Mac.
+ * Helper function for launching the application to apply an update.
  */
-function getAppDir() {
-  let dir = getCurrentProcessDir();
-  if (shouldAdjustPathsOnMac()) {
-    // objdir/dist/bin/../NightlyDebug.app/Contents/MacOS
-    dir = dir.parent;
-    dir.append(BUNDLE_NAME);
-    dir.append("Contents");
-    dir.append("MacOS");
-  } else if (IS_WIN && gWindowsBinDir) {
-    dir = gWindowsBinDir.clone();
+function launchAppToApplyUpdate() {
+  logTestInfo("start - launching application to apply update");
+
+  let appBin = getApplyDirFile(FILE_APP_BIN, false);
+
+  if (typeof(customLaunchAppToApplyUpdate) == typeof(Function)) {
+    customLaunchAppToApplyUpdate();
   }
-  return dir;
+
+  let launchBin = getLaunchBin();
+  let args = getProcessArgs();
+  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
+
+  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
+                createInstance(AUS_Ci.nsIProcess);
+  gProcess.init(launchBin);
+
+  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
+  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
+                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
+
+  setEnvironment();
+  logTestInfo("launching application");
+  gProcess.runAsync(args, args.length, gProcessObserver);
+  resetEnvironment();
+
+  logTestInfo("finish - launching application to apply update");
 }
 
 /**
  * The observer for the call to nsIProcess:runAsync.
  */
 let gProcessObserver = {
-  observe: function PO_observe(subject, topic, data) {
-    logTestInfo("topic " + topic + ", process exitValue " + gProcess.exitValue);
+  observe: function PO_observe(aSubject, aTopic, aData) {
+    logTestInfo("topic: " + aTopic + ", process exitValue: " +
+                gProcess.exitValue);
     if (gAppTimer) {
       gAppTimer.cancel();
       gAppTimer = null;
     }
-    if (topic != "process-finished" || gProcess.exitValue != 0) {
+    if (aTopic != "process-finished" || gProcess.exitValue != 0) {
       do_throw("Failed to launch application");
     }
     do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
   },
   QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
 };
 
 /**
  * The timer callback to kill the process if it takes too long.
  */
 let gTimerCallback = {
   notify: function TC_notify(aTimer) {
     gAppTimer = null;
     if (gProcess.isRunning) {
+      logTestInfo("attempt to kill process");
       gProcess.kill();
     }
     do_throw("launch application timer expired");
   },
   QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback])
 };
 
 /**
@@ -2462,27 +2683,16 @@ let gUpdateStagedObserver = {
     if (aTopic == "update-staged") {
       Services.obs.removeObserver(gUpdateStagedObserver, "update-staged");
       checkUpdateApplied();
     }
   },
   QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
 };
 
-// Environment related globals
-let gShouldResetEnv = undefined;
-let gAddedEnvXRENoWindowsCrashDialog = false;
-let gEnvXPCOMDebugBreak;
-let gEnvXPCOMMemLeakLog;
-let gEnvDyldLibraryPath;
-let gEnvLdLibraryPath;
-let gEnvUpdateRootOverride = null;
-let gEnvAppDirOverride = null;
-let gEnvSKipUpdateDirHashing = false;
-
 /**
  * Sets the environment that will be used by the application process when it is
  * launched.
  */
 function setEnvironment() {
   // Prevent setting the environment more than once.
   if (gShouldResetEnv !== undefined)
     return;
@@ -2494,17 +2704,17 @@ function setEnvironment() {
   if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) {
     gAddedEnvXRENoWindowsCrashDialog = true;
     logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
                 "variable to 1... previously it didn't exist");
     env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1");
   }
 
   if (IS_UNIX) {
-    let appGreDir = Services.dirsvc.get("GreD", AUS_Ci.nsIFile);
+    let appGreDir = gGREDirOrig.clone();
     let envGreDir = AUS_Cc["@mozilla.org/file/local;1"].
                     createInstance(AUS_Ci.nsILocalFile);
     let shouldSetEnv = true;
     if (IS_MACOSX) {
       if (env.exists("DYLD_LIBRARY_PATH")) {
         gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH");
         envGreDir.initWithPath(gEnvDyldLibraryPath);
         if (envGreDir.path == appGreDir.path) {
@@ -2513,18 +2723,17 @@ function setEnvironment() {
         }
       }
 
       if (shouldSetEnv) {
         logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " +
                     appGreDir.path);
         env.set("DYLD_LIBRARY_PATH", appGreDir.path);
       }
-    }
-    else {
+    } else {
       if (env.exists("LD_LIBRARY_PATH")) {
         gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH");
         envGreDir.initWithPath(gEnvLdLibraryPath);
         if (envGreDir.path == appGreDir.path) {
           gEnvLdLibraryPath = null;
           shouldSetEnv = false;
         }
       }
@@ -2543,43 +2752,26 @@ function setEnvironment() {
                 "previous value " + gEnvXPCOMMemLeakLog);
     env.set("XPCOM_MEM_LEAK_LOG", "");
   }
 
   if (env.exists("XPCOM_DEBUG_BREAK")) {
     gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK");
     logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
                 "warn... previous value " + gEnvXPCOMDebugBreak);
-  }
-  else {
+  } else {
     logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
                 "warn... previously it didn't exist");
   }
 
   env.set("XPCOM_DEBUG_BREAK", "warn");
 
-  if (IS_WIN && gEnvSKipUpdateDirHashing) {
-    env.set("MOZ_UPDATE_NO_HASH_DIR", "1");
-  }
-
-  if (gEnvUpdateRootOverride) {
-    logTestInfo("setting the MOZ_UPDATE_ROOT_OVERRIDE environment variable to " +
-                gEnvUpdateRootOverride + "\n");
-    env.set("MOZ_UPDATE_ROOT_OVERRIDE", gEnvUpdateRootOverride);
-  }
-
-  if (gEnvAppDirOverride) {
-    logTestInfo("setting the MOZ_UPDATE_APPDIR_OVERRIDE environment variable to " +
-                gEnvAppDirOverride + "\n");
-    env.set("MOZ_UPDATE_APPDIR_OVERRIDE", gEnvAppDirOverride);
-  }
-
-  if (gBackgroundUpdate) {
-    logTestInfo("setting the MOZ_UPDATE_BACKGROUND environment variable to 1\n");
-    env.set("MOZ_UPDATE_BACKGROUND", "1");
+  if (gStageUpdate) {
+    logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1\n");
+    env.set("MOZ_UPDATE_STAGING", "1");
   }
 
   logTestInfo("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1");
   env.set("MOZ_NO_SERVICE_FALLBACK", "1");
 }
 
 /**
  * Sets the environment back to the original values after launching the
@@ -2600,65 +2792,49 @@ function resetEnvironment() {
                 gEnvXPCOMMemLeakLog);
     env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog);
   }
 
   if (gEnvXPCOMDebugBreak) {
     logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " +
                 gEnvXPCOMDebugBreak);
     env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak);
-  }
-  else {
+  } else {
     logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable");
     env.set("XPCOM_DEBUG_BREAK", "");
   }
 
   if (IS_UNIX) {
     if (IS_MACOSX) {
       if (gEnvDyldLibraryPath) {
         logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " +
                     "back to " + gEnvDyldLibraryPath);
         env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath);
-      }
-      else {
+      } else {
         logTestInfo("removing DYLD_LIBRARY_PATH environment variable");
         env.set("DYLD_LIBRARY_PATH", "");
       }
-    }
-    else {
+    } else {
       if (gEnvLdLibraryPath) {
         logTestInfo("setting LD_LIBRARY_PATH environment variable value back " +
                     "to " + gEnvLdLibraryPath);
         env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath);
-      }
-      else {
+      } else {
         logTestInfo("removing LD_LIBRARY_PATH environment variable");
         env.set("LD_LIBRARY_PATH", "");
       }
     }
   }
 
   if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) {
     logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
                 "variable");
     env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "");
   }
 
-  if (gEnvUpdateRootOverride) {
-    logTestInfo("removing the MOZ_UPDATE_ROOT_OVERRIDE environment variable\n");
-    env.set("MOZ_UPDATE_ROOT_OVERRIDE", "");
-    gEnvUpdateRootOverride = null;
-  }
-
-  if (gEnvAppDirOverride) {
-    logTestInfo("removing the MOZ_UPDATE_APPDIR_OVERRIDE environment variable\n");
-    env.set("MOZ_UPDATE_APPDIR_OVERRIDE", "");
-    gEnvAppDirOverride = null;
-  }
-
-  if (gBackgroundUpdate) {
-    logTestInfo("removing the MOZ_UPDATE_BACKGROUND environment variable\n");
-    env.set("MOZ_UPDATE_BACKGROUND", "");
+  if (gStageUpdate) {
+    logTestInfo("removing the MOZ_UPDATE_STAGING environment variable\n");
+    env.set("MOZ_UPDATE_STAGING", "");
   }
 
   logTestInfo("removing MOZ_NO_SERVICE_FALLBACK environment variable");
   env.set("MOZ_NO_SERVICE_FALLBACK", "");
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
@@ -2,32 +2,28 @@
  * 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/.
  */
 
 var gNextRunFunc;
 var gExpectedCount;
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing remote update xml attributes");
 
   setUpdateURLOverride();
   setUpdateChannel("test_channel");
   // The mock XMLHttpRequest is MUCH faster
   overrideXHR(callHandleEvent);
   standardInit();
   do_execute_soon(run_test_pt01);
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 // Helper function for testing update counts returned from an update xml
 function run_test_helper_pt1(aMsg, aExpectedCount, aNextRunFunc) {
   gUpdates = null;
   gUpdateCount = null;
   gCheckFunc = check_test_helper_pt1;
   gNextRunFunc = aNextRunFunc;
   gExpectedCount = aExpectedCount;
   logTestInfo(aMsg, Components.stack.caller);
@@ -43,18 +39,17 @@ function check_test_helper_pt1() {
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   gXHR.status = 400;
   gXHR.responseText = gResponseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
-  }
-  catch(e) {
+  } catch (e) {
     gXHR.responseXML = null;
   }
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 // update xml not found
 function run_test_pt01() {
@@ -94,18 +89,17 @@ function check_test_pt02() {
   // isn't specified in the update xml.
 //  var defaultDetailsURL;
 //  try {
     // Try using a default details URL supplied by the distribution
     // if the update XML does not supply one.
 //    var formatter = AUS_Cc["@mozilla.org/toolkit/URLFormatterService;1"].
 //                    getService(AUS_Ci.nsIURLFormatter);
 //    defaultDetailsURL = formatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS);
-//  }
-//  catch (e) {
+//  } catch (e) {
 //    defaultDetailsURL = "";
 //  }
 
   do_check_eq(gUpdateCount, 1);
   var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount).QueryInterface(AUS_Ci.nsIPropertyBag);
   do_check_eq(bestUpdate.type, "minor");
   do_check_eq(bestUpdate.name, "Minor Test");
   do_check_eq(bestUpdate.displayVersion, "version 2.1a1pre");
--- a/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js
@@ -3,17 +3,17 @@
  */
 
 /**
  * Test that nsIUpdatePrompt doesn't display UI for showUpdateInstalled and
  * showUpdateAvailable when there is already an application update window open.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing nsIUpdatePrompt notifications should not be seen when " +
               "there is already an application update window open");
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
 
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
@@ -56,20 +56,16 @@ function run_test() {
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                               WindowWatcherFactory);
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"),
                               WindowMediatorFactory);
 
   do_test_finished();
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 function check_showUpdateInstalled() {
   do_throw("showUpdateInstalled should not have called openWindow!");
 }
 
 function check_showUpdateAvailable() {
   do_throw("showUpdateAvailable should not have called openWindow!");
 }
 
--- a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
@@ -4,17 +4,17 @@
 
 /**
  * Test that nsIUpdatePrompt doesn't display UI for showUpdateInstalled,
  * showUpdateAvailable, and showUpdateError when the app.update.silent
  * preference is true.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing nsIUpdatePrompt notifications should not be seen " +
               "when the " + PREF_APP_UPDATE_SILENT + " preference is true");
 
   Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
 
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
@@ -59,20 +59,16 @@ function run_test() {
 
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                               WindowWatcherFactory);
 
   do_test_finished();
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 function check_showUpdateInstalled() {
   do_throw("showUpdateInstalled should not have called openWindow!");
 }
 
 function check_showUpdateAvailable() {
   do_throw("showUpdateAvailable should not have called openWindow!");
 }
 
--- a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing nsIUpdatePrompt notifications should not be displayed " +
               "when showUpdateAvailable is called for an unsupported system " +
               "update when the unsupported notification has already been " +
               "shown (bug 843497)");
 
   setUpdateURLOverride();
   // The mock XMLHttpRequest is MUCH faster
@@ -52,30 +52,28 @@ function check_test() {
 }
 
 function end_test() {
   let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                               WindowWatcherFactory);
   registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"),
                               WindowMediatorFactory);
-  cleanupTestCommon();
 }
 
 // Callback function used by the custom XMLHttpRequest implementation to
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   gXHR.status = 400;
   gXHR.responseText = gResponseBody;
   try {
     var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
                  createInstance(AUS_Ci.nsIDOMParser);
     gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
-  }
-  catch(e) {
+  } catch (e) {
   }
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 function check_showUpdateAvailable() {
   do_throw("showUpdateAvailable should not have called openWindow!");
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateCheckOnLoadOnErrorStatusText.js
@@ -8,32 +8,28 @@
 // 2152398868, 2152398878, 2152398890, 2152398919, 2152398920, 2153390069,
 // 2152398918, 2152398861
 
 var gNextRunFunc;
 var gExpectedStatusCode;
 var gExpectedStatusText;
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing nsIUpdateCheckListener onload and onerror error code " +
               "and statusText values");
 
   setUpdateURLOverride();
   standardInit();
   // The mock XMLHttpRequest is MUCH faster
   overrideXHR(callHandleEvent);
   do_execute_soon(run_test_pt1);
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 // Callback function used by the custom XMLHttpRequest implementation to
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   gXHR.status = gExpectedStatusCode;
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -1,15 +1,15 @@
 /* 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/.
  */
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   logTestInfo("testing addition of a successful update to " + FILE_UPDATES_DB +
               " and verification of update properties including the format " +
               "prior to bug 530872");
 
   setUpdateChannel("test_channel");
 
   var patch, patches, update, updates;
@@ -205,12 +205,8 @@ function run_test() {
   do_check_eq(patch.hashFunction, "MD5");
   do_check_eq(patch.hashValue, MD5_HASH_SIMPLE_MAR);
   do_check_eq(patch.size, SIZE_SIMPLE_MAR);
   do_check_true(patch.selected);
   do_check_eq(patch.state, STATE_FAILED);
 
   do_test_finished();
 }
-
-function end_test() {
-  cleanupTestCommon();
-}
--- a/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateRootDirMigration_win.js
@@ -8,50 +8,51 @@ const PREF_APP_UPDATE_MIGRATE_APP_DIR = 
 function clearTaskbarIDHash(exePath, appInfoName) {
   let registry = AUS_Cc["@mozilla.org/windows-registry-key;1"].
                  createInstance(AUS_Ci.nsIWindowsRegKey);
   try {
     registry.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
                   "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs",
                   AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
     registry.removeValue(exePath);
-  } catch (ex) {
-  } finally {
+  } catch (e) {
+  }
+  finally {
     registry.close();
   }
 }
 
 function setTaskbarIDHash(exePath, hash, appInfoName) {
   let registry = AUS_Cc["@mozilla.org/windows-registry-key;1"].
                  createInstance(AUS_Ci.nsIWindowsRegKey);
   try {
     registry.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
                     "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs",
                     AUS_Ci.nsIWindowsRegKey.ACCESS_WRITE);
     registry.writeStringValue(exePath, hash);
-  } catch (ex) {
-  } finally {
+  } catch (e) {
+  }
+  finally {
     registry.close();
   }
 };
 
 function getMigrated() {
   var migrated = 0;
   try {
     migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR);
   } catch (e) {
   }
   return migrated;
 }
 
 /* General Update Manager Tests */
 
 function run_test() {
-  setupTestCommon(false);
-  do_register_cleanup(end_test);
+  setupTestCommon();
 
   standardInit();
 
   var appinfo = AUS_Cc["@mozilla.org/xre/app-info;1"].
                 getService(AUS_Ci.nsIXULAppInfo).
                 QueryInterface(AUS_Ci.nsIXULRuntime);
 
    // Obtain the old update root leaf
@@ -79,17 +80,17 @@ function run_test() {
   var newUpdateRoot = FileUtils.getDir("UpdRootD", [], false);
 
   ///////////////////////////////////////////////////////////
   // Setting a taskbar ID without the old update dir existing should set the
   // pref so a migration isn't retried.
 
   // Remove the old and new update root directories
   try {
-  oldUpdateRoot.remove(true);
+    oldUpdateRoot.remove(true);
   } catch (e) {
   }
   try {
     newUpdateRoot.remove(true);
   } catch (e) {
   }
   Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, false);
   setTaskbarIDHash(exeFile.parent.path, "AAAAAAAA", appinfo.name);
@@ -162,10 +163,9 @@ function run_test() {
 }
 
 function end_test() {
   var appinfo = AUS_Cc["@mozilla.org/xre/app-info;1"].
                 getService(AUS_Ci.nsIXULAppInfo).
                 QueryInterface(AUS_Ci.nsIXULRuntime);
   var exeFile = FileUtils.getFile(XRE_EXECUTABLE_FILE, []);
   clearTaskbarIDHash(exeFile.parent.path, appinfo.name);
-  cleanupTestCommon();
 }
--- a/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js
@@ -7,31 +7,30 @@
 
 Components.utils.import("resource://gre/modules/ctypes.jsm")
 
 const URL_PREFIX = URL_HOST + "/";
 
 var gAppInfo;
 
 function run_test() {
-  setupTestCommon(true);
+  // This test needs access to omni.ja to read the update.locale file so don't
+  // use a custom directory for the application directory.
+  gUseTestAppDir = false;
+  setupTestCommon();
 
   // The mock XMLHttpRequest is MUCH faster
   overrideXHR(callHandleEvent);
   standardInit();
   gAppInfo = AUS_Cc["@mozilla.org/xre/app-info;1"].
              getService(AUS_Ci.nsIXULAppInfo).
              QueryInterface(AUS_Ci.nsIXULRuntime);
   do_execute_soon(run_test_pt1);
 }
 
-function end_test() {
-  cleanupTestCommon();
-}
-
 // Callback function used by the custom XMLHttpRequest implementation to
 // call the nsIDOMEventListener's handleEvent method for onload.
 function callHandleEvent() {
   var e = { target: gXHR };
   gXHR.onload(e);
 }
 
 // Helper function for parsing the result from the contructed url
@@ -90,18 +89,17 @@ function run_test_pt4() {
   setUpdateURLOverride(url);
   gUpdateChecker.checkForUpdates(updateCheckListener, true);
 }
 
 function check_test_pt4() {
   var abi;
   try {
     abi = gAppInfo.XPCOMABI;
-  }
-  catch (e) {
+  } catch (e) {
     do_throw("nsIXULAppInfo:XPCOMABI not defined\n");
   }
 
   if (IS_MACOSX) {
     // Mac universal build should report a different ABI than either macppc
     // or mactel. This is necessary since nsUpdateService.js will set the ABI to
     // Universal-gcc3 for Mac universal builds.
     var macutils = AUS_Cc["@mozilla.org/xpcom/mac-utils;1"].
@@ -124,18 +122,17 @@ function check_test_pt4() {
 // Bug 488936 added the update.locale file that stores the update locale
 function run_test_pt5() {
   gCheckFunc = check_test_pt5;
   var url = URL_PREFIX + "%LOCALE%/";
   logTestInfo("testing url constructed with %LOCALE% - " + url);
   setUpdateURLOverride(url);
   try {
     gUpdateChecker.checkForUpdates(updateCheckListener, true);
-  }
-  catch (e) {
+  } catch (e) {
     logTestInfo("The following error is most likely due to a missing " +
                 "update.locale file");
     do_throw(e);
   }
 }
 
 function check_test_pt5() {
   do_check_eq(getResult(gRequestURL), INSTALL_LOCALE);
@@ -320,18 +317,17 @@ function check_test_pt9() {
         do_throw("Failed to obtain processor architecture: " + e);
       }
     }
   }
 
   if (osVersion) {
     try {
       osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
-    }
-    catch (e) {
+    } catch (e) {
       // Not all platforms have a secondary widget library, so an error is
       // nothing to worry about.
     }
     osVersion = encodeURIComponent(osVersion);
   }
 
   do_check_eq(getResult(gRequestURL), osVersion);
   run_test_pt10();
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateAppBinInUseStageSuccess_win.js
@@ -1,296 +1,146 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
- * Test applying an update by applying an update in the background and
- * launching an application
- */
-
-/**
- * This test is identical to test_0201_app_launch_apply_update.js, except
- * that it locks the application directory when the test is launched to
- * make the updater fall back to apply the update regularly.
+ * Test applying an update by staging an update and launching an application to
+ * apply it.
  */
 
 /**
  * The MAR file used for this test should not contain a version 2 update
  * manifest file (e.g. updatev2.manifest).
  */
 
-
 Components.utils.import("resource://gre/modules/ctypes.jsm");
 
-let gAppTimer;
-let gProcess;
-
 function run_test() {
-  if (APP_BIN_NAME == "xulrunner") {
+  if (MOZ_APP_NAME == "xulrunner") {
     logTestInfo("Unable to run this test on xulrunner");
     return;
   }
 
-  setupTestCommon(false);
-
-  do_register_cleanup(end_test);
+  setupTestCommon();
 
   if (IS_WIN) {
     Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, true);
   }
 
-  symlinkUpdateFilesIntoBundleDirectory();
-  if (IS_WIN) {
-    adjustPathsOnWindows();
-  }
-
-  if (!gAppBinPath) {
-    do_throw("Main application binary not found... expected: " +
-             APP_BIN_NAME + APP_BIN_SUFFIX);
-    return;
-  }
-
-  // Don't attempt to show a prompt when the update is finished.
-  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
-
-  gEnvSKipUpdateDirHashing = true;
   let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
   let patches = getLocalPatchString(null, null, null, null, null, "true",
                                     STATE_PENDING);
   let updates = getLocalUpdateString(patches, null, null, null, null, null,
                                      null, null, null, null, null, null,
                                      null, "true", channel);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-  // Read the application.ini and use its application version
-  let processDir = getAppDir();
-  let file = processDir.clone();
-  file.append("application.ini");
-  let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-            getService(AUS_Ci.nsIINIParserFactory).
-            createINIParser(file);
-  let version = ini.getString("App", "Version");
-  writeVersionFile(version);
+  writeVersionFile(getAppVersion());
   writeStatusFile(STATE_PENDING);
 
-  // This is the directory where the update files will be located
-  let updateTestDir = getUpdateTestDir();
-  try {
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  let updatesPatchDir = getUpdatesDir();
-  updatesPatchDir.append("0");
+  let updatesPatchDir = getUpdatesPatchDir();
   let mar = getTestDirFile(FILE_SIMPLE_MAR);
   mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Backup the updater.ini file if it exists by moving it. This prevents the
-  // post update executable from being launched if it is specified.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK);
-  }
-
-  // Backup the updater-settings.ini file if it exists by moving it.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+  let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
   reloadUpdateManagerData();
   do_check_true(!!gUpdateManager.activeUpdate);
 
-  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
-
-  // Initiate a background update.
-  AUS_Cc["@mozilla.org/updates/update-processor;1"].
-    createInstance(AUS_Ci.nsIUpdateProcessor).
-    processUpdate(gUpdateManager.activeUpdate);
+  setupAppFilesAsync();
 }
 
-function switchApp() {
-  let launchBin = getLaunchBin();
-  let args = getProcessArgs();
-  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
+function setupAppFilesFinished() {
+  stageUpdate();
+}
 
-  // Lock the installation directory
+function customLaunchAppToApplyUpdate() {
+  logTestInfo("start - locking installation directory");
   const LPCWSTR = ctypes.jschar.ptr;
   const DWORD = ctypes.uint32_t;
   const LPVOID = ctypes.voidptr_t;
   const GENERIC_READ = 0x80000000;
   const FILE_SHARE_READ = 1;
   const FILE_SHARE_WRITE = 2;
   const OPEN_EXISTING = 3;
   const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
   const INVALID_HANDLE_VALUE = LPVOID(0xffffffff);
   let kernel32 = ctypes.open("kernel32");
   let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi,
                                     LPVOID, LPCWSTR, DWORD, DWORD,
                                     LPVOID, DWORD, DWORD, LPVOID);
-  logTestInfo(gWindowsBinDir.path);
-  let handle = CreateFile(gWindowsBinDir.path, GENERIC_READ,
-                          FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
-                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
-  do_check_neq(handle.toString(), INVALID_HANDLE_VALUE.toString());
+  gHandle = CreateFile(getAppBaseDir().path, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
+                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
+  do_check_neq(gHandle.toString(), INVALID_HANDLE_VALUE.toString());
   kernel32.close();
-
-  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
-                createInstance(AUS_Ci.nsIProcess);
-  gProcess.init(launchBin);
-
-  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
-  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
-                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
-
-  setEnvironment();
-
-  gProcess.runAsync(args, args.length, gProcessObserver);
-
-  resetEnvironment();
-}
-
-function end_test() {
-  if (gProcess.isRunning) {
-    logTestInfo("attempt to kill process");
-    gProcess.kill();
-  }
-
-  if (gAppTimer) {
-    logTestInfo("cancelling timer");
-    gAppTimer.cancel();
-    gAppTimer = null;
-  }
-
-  resetEnvironment();
-
-  let processDir = getAppDir();
-  // Restore the backup of the updater.ini if it exists.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI_BAK);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI);
-  }
-
-  // Restore the backed up updater-settings.ini if it exists.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI);
-  }
-
-  // Remove the files added by the update.
-  let updateTestDir = getUpdateTestDir();
-  try {
-    logTestInfo("removing update test directory " + updateTestDir.path);
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  if (IS_UNIX) {
-    // This will delete the launch script if it exists.
-    getLaunchScript();
-  }
-
-  cleanupTestCommon();
-}
-
-function shouldAdjustPathsOnMac() {
-  // When running xpcshell tests locally, xpcshell and firefox-bin do not live
-  // in the same directory.
-  let dir = getCurrentProcessDir();
-  return (IS_MACOSX && dir.leafName != "MacOS");
+  logTestInfo("finish - locking installation directory");
 }
 
 /**
- * Gets the directory where the update adds / removes the files contained in the
- * update.
- *
- * @return  nsIFile for the directory where the update adds / removes the files
- *          contained in the update mar.
- */
-function getUpdateTestDir() {
-  let updateTestDir = getAppDir();
-  if (IS_MACOSX) {
-    updateTestDir = updateTestDir.parent.parent;
-  }
-  updateTestDir.append("update_test");
-  return updateTestDir;
-}
-
-/**
- * Checks if the update has finished being applied in the background.
+ * Checks if the update has finished being staged.
  */
 function checkUpdateApplied() {
   gTimeoutRuns++;
-  // Don't proceed until the update has been applied.
+  // Don't proceed until the active update's state is applied.
   if (gUpdateManager.activeUpdate.state != STATE_APPLIED_PLATFORM) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for update to be " +
-               "applied, current state is: " + gUpdateManager.activeUpdate.state);
-    else
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
+               "applied, current state is: " +
+               gUpdateManager.activeUpdate.state);
+    } else {
       do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
     return;
   }
 
-  let updatedDir = getAppDir();
-  if (IS_MACOSX) {
-    updatedDir = updatedDir.parent.parent;
-  }
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
-  logTestInfo("testing " + updatedDir.path + " should exist");
-  do_check_true(updatedDir.exists());
-
-  let log;
-  if (IS_WIN) {
-    log = getUpdatesDir();
-  } else {
-    log = updatedDir.clone();
-    if (IS_MACOSX) {
-      log.append("Contents");
-      log.append("MacOS");
+  // Don't proceed until the update's status state is applied.
+  let state = readStatusState();
+  if (state != STATE_APPLIED_PLATFORM) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
+               "status state to equal " + STATE_APPLIED_PLATFORM + ", " +
+               "current status state: " + state);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
     }
-    log.append("updates");
-  }
-  log.append(FILE_LAST_LOG);
-  if (!log.exists()) {
-    do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
     return;
   }
 
-  // Don't proceed until the update status is no longer pending or applying.
-  let status = readStatusFile();
-  do_check_eq(status, STATE_APPLIED_PLATFORM);
-
-  // On Windows, make sure not to use the maintenance service for switching
-  // the app.
-  if (IS_WIN) {
-    writeStatusFile(STATE_APPLIED);
-    status = readStatusFile();
-    do_check_eq(status, STATE_APPLIED);
+  // Don't proceed until the last update log has been created.
+  let log = getUpdatesDir();
+  log.append(FILE_LAST_LOG);
+  if (!log.exists()) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update log " +
+               "to be created. Path: " + log.path);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
+    return;
   }
 
   // Log the contents of the update.log so it is simpler to diagnose a test
   // failure.
   let contents = readFile(log);
   logTestInfo("contents of " + log.path + ":\n" +
               contents.replace(/\r\n/g, "\n"));
 
+  let updatedDir = getUpdatedDir();
+  logTestInfo("testing " + updatedDir.path + " should exist");
+  do_check_true(updatedDir.exists());
+
+  // On Windows, make sure not to use the maintenance service for switching
+  // the app.
+  if (IS_WIN) {
+    writeStatusFile(STATE_APPLIED);
+    do_check_eq(readStatusState(), STATE_APPLIED);
+  }
+
   let updateTestDir = getUpdateTestDir();
   logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
   do_check_false(updateTestDir.exists());
 
   updateTestDir = updatedDir.clone();
   updateTestDir.append("update_test");
   let file = updateTestDir.clone();
   file.append("UpdateTestRemoveFile");
@@ -313,36 +163,25 @@ function checkUpdateApplied() {
   log = updatesDir.clone();
   log.append("0");
   log.append(FILE_UPDATE_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
   log = updatesDir.clone();
   log.append(FILE_LAST_LOG);
-  if (IS_WIN) {
-    // On Windows this file lives outside of the app directory, so it should
-    // exist.
-    logTestInfo("testing " + log.path + " should exist");
-    do_check_true(log.exists());
-  } else {
-    logTestInfo("testing " + log.path + " shouldn't exist");
-    do_check_false(log.exists());
-  }
+  logTestInfo("testing " + log.path + " should exist");
+  do_check_true(log.exists());
 
   log = updatesDir.clone();
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
   updatesDir = updatedDir.clone();
-  if (IS_MACOSX) {
-    updatesDir.append("Contents");
-    updatesDir.append("MacOS");
-  }
   updatesDir.append("updates");
   log = updatesDir.clone();
   log.append("0");
   log.append(FILE_UPDATE_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
   if (!IS_WIN) {
@@ -356,68 +195,49 @@ function checkUpdateApplied() {
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
   updatesDir.append("0");
   logTestInfo("testing " + updatesDir.path + " shouldn't exist");
   do_check_false(updatesDir.exists());
 
-  // Now, switch the updated version of the app
-  do_timeout(TEST_CHECK_TIMEOUT, switchApp);
+  // Now, switch the updated version of the app.
+  do_timeout(TEST_CHECK_TIMEOUT, launchAppToApplyUpdate);
 }
 
 /**
  * Checks if the update has finished and if it has finished performs checks for
  * the test.
  */
 function checkUpdateFinished() {
-  // Don't proceed until the update status is no longer applied.
   gTimeoutRuns++;
-  try {
-    let status = readStatusFile();
-    if (status != STATE_SUCCEEDED) {
-      if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-        do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for state to " +
-                 "change to succeeded, current status: " + status);
-      else
-        do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
-      return;
+  // Don't proceed until the update's status state is succeeded.
+  let state = readStatusState();
+  if (state != STATE_SUCCEEDED) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
+               "status state to equal " + STATE_SUCCEEDED + ", " +
+               "current status state: " + state);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     }
-  } catch (e) {
-    // Ignore exceptions if the status file is not found
+    return;
   }
 
-  try {
-    // This will delete the app console log file if it exists.
-    getAppConsoleLogPath();
-  } catch (e) {
-    if (e.result == Components.results.NS_ERROR_FILE_IS_LOCKED) {
-      // This might happen on Windows in case the callback application has not
-      // finished its job yet.  So, we'll wait some more.
-      if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-        do_throw("Exceeded whilst waiting for file to be unlocked");
-      else
-        do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
-      return;
+  // Don't proceed until the application was switched out with the staged update
+  // successfully.
+  let updatedDir = getUpdatedDir();
+  if (updatedDir.exists()) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded while waiting for updated dir to not exist. Path: " +
+               updatedDir.path);
     } else {
-      do_throw("getAppConsoleLogPath threw: " + e);
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     }
-  }
-
-  // At this point we need to see if the application was switched successfully.
-
-  let updatedDir = getAppDir();
-  if (IS_MACOSX) {
-    updatedDir = updatedDir.parent.parent;
-  }
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
-  logTestInfo("testing " + updatedDir.path + " shouldn't exist");
-  if (updatedDir.exists()) {
-    do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     return;
   }
 
   let updateTestDir = getUpdateTestDir();
 
   let file = updateTestDir.clone();
   file.append("UpdateTestRemoveFile");
   logTestInfo("testing " + file.path + " shouldn't exist");
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateStageSuccess.js
@@ -1,272 +1,129 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
- * Test applying an update by applying an update in the background and
- * launching an application
+ * Test applying an update by staging an update and launching an application to
+ * apply it.
  */
 
 /**
  * The MAR file used for this test should not contain a version 2 update
  * manifest file (e.g. updatev2.manifest).
  */
 
-let gAppTimer;
-let gProcess;
-
 function run_test() {
-  if (APP_BIN_NAME == "xulrunner") {
+  if (MOZ_APP_NAME == "xulrunner") {
     logTestInfo("Unable to run this test on xulrunner");
     return;
   }
 
-  setupTestCommon(false);
-
-  do_register_cleanup(end_test);
+  setupTestCommon();
 
   if (IS_WIN) {
     Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, true);
   }
 
-  symlinkUpdateFilesIntoBundleDirectory();
-  if (IS_WIN) {
-    adjustPathsOnWindows();
-  }
-
-  if (!gAppBinPath) {
-    do_throw("Main application binary not found... expected: " +
-             APP_BIN_NAME + APP_BIN_SUFFIX);
-    return;
-  }
-
-  // Don't attempt to show a prompt when the update is finished.
-  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
-
-  gEnvSKipUpdateDirHashing = true;
   let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
   let patches = getLocalPatchString(null, null, null, null, null, "true",
                                     STATE_PENDING);
   let updates = getLocalUpdateString(patches, null, null, null, null, null,
                                      null, null, null, null, null, null,
                                      null, "true", channel);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-  // Read the application.ini and use its application version
-  let processDir = getAppDir();
-  let file = processDir.clone();
-  file.append("application.ini");
-  let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-            getService(AUS_Ci.nsIINIParserFactory).
-            createINIParser(file);
-  let version = ini.getString("App", "Version");
-  writeVersionFile(version);
+  writeVersionFile(getAppVersion());
   writeStatusFile(STATE_PENDING);
 
-  // This is the directory where the update files will be located
-  let updateTestDir = getUpdateTestDir();
-  try {
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  let updatesPatchDir = getUpdatesDir();
-  updatesPatchDir.append("0");
+  let updatesPatchDir = getUpdatesPatchDir();
   let mar = getTestDirFile(FILE_SIMPLE_MAR);
   mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Backup the updater.ini file if it exists by moving it. This prevents the
-  // post update executable from being launched if it is specified.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK);
-  }
-
-  // Backup the updater-settings.ini file if it exists by moving it.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+  let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
   reloadUpdateManagerData();
   do_check_true(!!gUpdateManager.activeUpdate);
 
-  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
-
-  // Initiate a background update.
-  AUS_Cc["@mozilla.org/updates/update-processor;1"].
-    createInstance(AUS_Ci.nsIUpdateProcessor).
-    processUpdate(gUpdateManager.activeUpdate);
-}
-
-function switchApp() {
-  let launchBin = getLaunchBin();
-  let args = getProcessArgs();
-  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
-
-  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
-                createInstance(AUS_Ci.nsIProcess);
-  gProcess.init(launchBin);
-
-  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
-  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
-                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
-
-  setEnvironment();
-
-  gProcess.runAsync(args, args.length, gProcessObserver);
-
-  resetEnvironment();
+  setupAppFilesAsync();
 }
 
-function end_test() {
-  if (gProcess.isRunning) {
-    logTestInfo("attempt to kill process");
-    gProcess.kill();
-  }
-
-  if (gAppTimer) {
-    logTestInfo("cancelling timer");
-    gAppTimer.cancel();
-    gAppTimer = null;
-  }
-
-  resetEnvironment();
-
-  let processDir = getAppDir();
-  // Restore the backup of the updater.ini if it exists.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI_BAK);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI);
-  }
-
-  // Restore the backed up updater-settings.ini if it exists.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI);
-  }
-
-  // Remove the files added by the update.
-  let updateTestDir = getUpdateTestDir();
-  try {
-    logTestInfo("removing update test directory " + updateTestDir.path);
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  if (IS_UNIX) {
-    // This will delete the launch script if it exists.
-    getLaunchScript();
-  }
-
-  cleanupTestCommon();
-}
-
-function shouldAdjustPathsOnMac() {
-  // When running xpcshell tests locally, xpcshell and firefox-bin do not live
-  // in the same directory.
-  let dir = getCurrentProcessDir();
-  return (IS_MACOSX && dir.leafName != "MacOS");
+function setupAppFilesFinished() {
+  stageUpdate();
 }
 
 /**
- * Gets the directory where the update adds / removes the files contained in the
- * update.
- *
- * @return  nsIFile for the directory where the update adds / removes the files
- *          contained in the update mar.
- */
-function getUpdateTestDir() {
-  let updateTestDir = getAppDir();
-  if (IS_MACOSX) {
-    updateTestDir = updateTestDir.parent.parent;
-  }
-  updateTestDir.append("update_test");
-  return updateTestDir;
-}
-
-/**
- * Checks if the update has finished being applied in the background.
+ * Checks if the update has finished being staged.
  */
 function checkUpdateApplied() {
   gTimeoutRuns++;
-  // Don't proceed until the update has been applied.
+  // Don't proceed until the update state is applied.
   if (gUpdateManager.activeUpdate.state != STATE_APPLIED_PLATFORM) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for update to be " +
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
                "applied, current state is: " +
                gUpdateManager.activeUpdate.state);
-    else
+    } else {
       do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
     return;
   }
 
-  let updatedDir = getAppDir();
-  if (IS_MACOSX) {
-    updatedDir = updatedDir.parent.parent;
+  // Don't proceed until the update status state is applied.
+  let state = readStatusState();
+  if (state != STATE_APPLIED_PLATFORM) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
+               "status state to equal " + STATE_APPLIED_PLATFORM + ", " +
+               "current status state: " + state);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
+    return;
   }
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
-  logTestInfo("testing " + updatedDir.path + " should exist");
-  do_check_true(updatedDir.exists());
 
+  // Don't proceed until the last update log has been created.
   let log;
   if (IS_WIN) {
     log = getUpdatesDir();
   } else {
-    log = updatedDir.clone();
+    log = getUpdatedDir();
     if (IS_MACOSX) {
       log.append("Contents");
       log.append("MacOS");
     }
-    log.append("updates");
+    log.append(DIR_UPDATES);
   }
   log.append(FILE_LAST_LOG);
   if (!log.exists()) {
-    do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update log " +
+               "to be created. Path: " + log.path);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
     return;
   }
 
-  // Don't proceed until the update status is no longer pending or applying.
-  let status = readStatusFile();
-  do_check_eq(status, STATE_APPLIED_PLATFORM);
-
-  // On Windows, make sure not to use the maintenance service for switching
-  // the app.
-  if (IS_WIN) {
-    writeStatusFile(STATE_APPLIED);
-    status = readStatusFile();
-    do_check_eq(status, STATE_APPLIED);
-  }
-
   // Log the contents of the update.log so it is simpler to diagnose a test
   // failure.
   let contents = readFile(log);
   logTestInfo("contents of " + log.path + ":\n" +
               contents.replace(/\r\n/g, "\n"));
 
+  let updatedDir = getUpdatedDir();
+  logTestInfo("testing " + updatedDir.path + " should exist");
+  do_check_true(updatedDir.exists());
+
   let updateTestDir = getUpdateTestDir();
   logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
   do_check_false(updateTestDir.exists());
 
-  updateTestDir = updatedDir.clone();
+  updateTestDir = getUpdatedDir();
   updateTestDir.append("update_test");
   let file = updateTestDir.clone();
   file.append("UpdateTestRemoveFile");
   logTestInfo("testing " + file.path + " shouldn't exist");
   do_check_false(file.exists());
 
   file = updateTestDir.clone();
   file.append("UpdateTestAddFile");
@@ -275,41 +132,38 @@ function checkUpdateApplied() {
   do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
 
   file = updateTestDir.clone();
   file.append("removed-files");
   logTestInfo("testing " + file.path + " should exist");
   do_check_true(file.exists());
   do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
 
-  let updatesDir = getUpdatesDir();
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append("0");
   log.append(FILE_UPDATE_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_LAST_LOG);
   if (IS_WIN) {
-    // On Windows this file lives outside of the app directory, so it should
-    // exist.
     logTestInfo("testing " + log.path + " should exist");
     do_check_true(log.exists());
   } else {
     logTestInfo("testing " + log.path + " shouldn't exist");
     do_check_false(log.exists());
   }
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
-  updatesDir = updatedDir.clone();
+  let updatesDir = getUpdatedDir();
   if (IS_MACOSX) {
     updatesDir.append("Contents");
     updatesDir.append("MacOS");
   }
   updatesDir.append("updates");
   log = updatesDir.clone();
   log.append("0");
   log.append(FILE_UPDATE_LOG);
@@ -327,71 +181,55 @@ function checkUpdateApplied() {
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
   updatesDir.append("0");
   logTestInfo("testing " + updatesDir.path + " shouldn't exist");
   do_check_false(updatesDir.exists());
 
+  // On Windows, make sure not to use the maintenance service for switching
+  // the app.
+  if (IS_WIN) {
+    writeStatusFile(STATE_APPLIED);
+    do_check_eq(readStatusState(), STATE_APPLIED);
+  }
+
   // Now, switch the updated version of the app
-  do_timeout(TEST_CHECK_TIMEOUT, switchApp);
+  do_timeout(TEST_CHECK_TIMEOUT, launchAppToApplyUpdate);
 }
 
 /**
  * Checks if the update has finished and if it has finished performs checks for
  * the test.
  */
 function checkUpdateFinished() {
   gTimeoutRuns++;
-  // Don't proceed until the update status is no longer applied.
-  try {
-    let status = readStatusFile();
-    if (status != STATE_SUCCEEDED) {
-      if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-        do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for state to " +
-                 "change to succeeded, current status: " + status);
-      else
-        do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
-      return;
+  // Don't proceed until the update status state is succeeded.
+  let state = readStatusState();
+  if (state != STATE_SUCCEEDED) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
+               "status state to equal " + STATE_SUCCEEDED + ", " +
+               "current status state: " + state);
+    } else {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     }
-  } catch (e) {
-    // Ignore exceptions if the status file is not found
+    return;
   }
 
-  try {
-    // This will delete the app console log file if it exists.
-    getAppConsoleLogPath();
-  } catch (e) {
-    if (e.result == Components.results.NS_ERROR_FILE_IS_LOCKED) {
-      // This might happen on Windows in case the callback application has not
-      // finished its job yet.  So, we'll wait some more.
-      if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-        do_throw("Exceeded whilst waiting for file to be unlocked");
-      else
-        do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
-      return;
+  // Don't proceed until the application was switched out with the staged update
+  // successfully.
+  let updatedDir = getUpdatedDir();
+  if (updatedDir.exists()) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded while waiting for update dir to not exist");
     } else {
-      do_throw("getAppConsoleLogPath threw: " + e);
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     }
-  }
-
-  // At this point we need to see if the application was switched successfully.
-
-  let updatedDir = getAppDir();
-  if (IS_MACOSX) {
-    updatedDir = updatedDir.parent.parent;
-  }
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
-  logTestInfo("testing " + updatedDir.path + " shouldn't exist");
-  if (updatedDir.exists()) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded whilst waiting for update dir to not exist");
-    else
-      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
     return;
   }
 
   let updateTestDir = getUpdateTestDir();
 
   let file = updateTestDir.clone();
   file.append("UpdateTestRemoveFile");
   logTestInfo("testing " + file.path + " shouldn't exist");
@@ -404,38 +242,38 @@ function checkUpdateFinished() {
   do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
 
   file = updateTestDir.clone();
   file.append("removed-files");
   logTestInfo("testing " + file.path + " should exist");
   do_check_true(file.exists());
   do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
 
-  let updatesDir = getUpdatesDir();
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append("0");
   log.append(FILE_UPDATE_LOG);
   if (IS_WIN) {
     // On Windows, this log file is written to the AppData directory, and will
     // therefore exist.
     logTestInfo("testing " + log.path + " should exist");
     do_check_true(log.exists());
   } else {
     logTestInfo("testing " + log.path + " shouldn't exist");
     do_check_false(log.exists());
   }
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_LAST_LOG);
   logTestInfo("testing " + log.path + " should exist");
   do_check_true(log.exists());
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
+  let updatesDir = getUpdatesDir();
   updatesDir.append("0");
   logTestInfo("testing " + updatesDir.path + " should exist");
   do_check_true(updatesDir.exists());
 
   waitForFilesInUse();
 }
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppApplyUpdateSuccess.js
@@ -1,303 +1,125 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Test applying an update by staging an update and launching an application */
+/**
+ * Test applying an update by staging an update and launching an application to
+ * apply it.
+ */
 
 /**
  * The MAR file used for this test should not contain a version 2 update
  * manifest file (e.g. updatev2.manifest).
  */
 
-let gAppTimer;
-let gProcess;
-
 function run_test() {
-  if (APP_BIN_NAME == "xulrunner") {
+  if (MOZ_APP_NAME == "xulrunner") {
     logTestInfo("Unable to run this test on xulrunner");
     return;
   }
 
-  setupTestCommon(false);
-
-  do_register_cleanup(end_test);
+  setupTestCommon();
 
-  if (!gAppBinPath) {
-    do_throw("Main application binary not found... expected: " +
-             APP_BIN_NAME + APP_BIN_SUFFIX);
-    return;
-  }
-
-  gEnvSKipUpdateDirHashing = true;
   let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
   let patches = getLocalPatchString(null, null, null, null, null, "true",
                                     STATE_PENDING);
   let updates = getLocalUpdateString(patches, null, null, null, null, null,
                                      null, null, null, null, null, null,
                                      null, "true", channel);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-  // Read the application.ini and use its application version
-  let processDir = getCurrentProcessDir();
-  let file = processDir.clone();
-  file.append("application.ini");
-  let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-            getService(AUS_Ci.nsIINIParserFactory).
-            createINIParser(file);
-  let version = ini.getString("App", "Version");
-  writeVersionFile(version);
+  writeVersionFile(getAppVersion());
   writeStatusFile(STATE_PENDING);
 
-  // This is the directory where the update files will be located
+  // This is the directory where the files that will be updated are located.
   let updateTestDir = getUpdateTestDir();
-  try {
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  // Add the directory where the update files will be added and add files that
-  // will be removed.
+  // Add the directory where the files will be added and add files that will be
+  // removed.
   if (!updateTestDir.exists()) {
     updateTestDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
   }
   logTestInfo("update test directory path: " + updateTestDir.path);
 
-  file = updateTestDir.clone();
+  let file = updateTestDir.clone();
   file.append("UpdateTestRemoveFile");
   writeFile(file, "ToBeRemoved");
 
   file = updateTestDir.clone();
   file.append("UpdateTestAddFile");
   writeFile(file, "ToBeReplaced");
 
   file = updateTestDir.clone();
   file.append("removed-files");
   writeFile(file, "ToBeReplaced");
 
-  let updatesPatchDir = getUpdatesDir();
-  updatesPatchDir.append("0");
+  let updatesPatchDir = getUpdatesPatchDir();
   let mar = getTestDirFile(FILE_SIMPLE_MAR);
   mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Backup the updater.ini file if it exists by moving it. This prevents the
-  // post update executable from being launched if it is specified.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK);
-  }
-
-  // Backup the updater-settings.ini file if it exists by moving it.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+  let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
-  let launchBin = getLaunchBin();
-  let args = getProcessArgs();
-  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
-
-  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
-                createInstance(AUS_Ci.nsIProcess);
-  gProcess.init(launchBin);
-
-  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
-  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
-                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
-
-  setEnvironment();
-
-  gProcess.runAsync(args, args.length, gProcessObserver);
-
-  resetEnvironment();
+  setupAppFilesAsync();
 }
 
-function end_test() {
-  if (gProcess.isRunning) {
-    logTestInfo("attempt to kill process");
-    gProcess.kill();
-  }
-
-  if (gAppTimer) {
-    logTestInfo("cancelling timer");
-    gAppTimer.cancel();
-    gAppTimer = null;
-  }
-
-  resetEnvironment();
-
-  let processDir = getCurrentProcessDir();
-  // Restore the backup of the updater.ini if it exists.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI_BAK);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI);
-  }
-
-  // Restore the backed up updater-settings.ini if it exists.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI);
-  }
-
-  if (IS_WIN) {
-    // Remove the copy of the application executable used for the test on
-    // Windows if it exists.
-    let appBinCopy = processDir.clone();
-    appBinCopy.append(FILE_WIN_TEST_EXE);
-    if (appBinCopy.exists()) {
-      appBinCopy.remove(false);
-    }
-  }
-
-  // Remove the files added by the update.
-  let updateTestDir = getUpdateTestDir();
-  try {
-    logTestInfo("removing update test directory " + updateTestDir.path);
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  // This will delete the app console log file if it exists.
-  try {
-    getAppConsoleLogPath();
-  }
-  catch (e) {
-    logTestInfo("unable to remove file during end_test. Exception: " + e);
-  }
-
-  if (IS_UNIX) {
-    // This will delete the launch script if it exists.
-    getLaunchScript();
-  }
-
-  cleanupTestCommon();
+function setupAppFilesFinished() {
+  do_timeout(TEST_CHECK_TIMEOUT, launchAppToApplyUpdate);
 }
 
 /**
- * Gets the directory where the update adds / removes the files contained in the
- * update.
- *
- * @return  nsIFile for the directory where the update adds / removes the files
- *          contained in the update mar.
- */
-function getUpdateTestDir() {
-  let updateTestDir = getCurrentProcessDir();
-  if (IS_MACOSX) {
-    updateTestDir = updateTestDir.parent.parent;
-  }
-  updateTestDir.append("update_test");
-  return updateTestDir;
-}
-
-/**
- * Checks if the update has finished, renames the update.log file to make
- * sure it is not in use, and then calls restoreLogFile to continue the test.
+ * Checks if the update has finished and if it has finished performs checks for
+ * the test.
  */
 function checkUpdateFinished() {
   gTimeoutRuns++;
-  // Don't proceed until the update.log has been created.
-  let updatesDir = getUpdatesDir();
-  updatesDir.append("0");
-  let log = updatesDir.clone();
-  log.append(FILE_UPDATE_LOG);
-  if (!log.exists()) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for updates log to " +
-               "be created at " + log.path);
-    else
+  // Don't proceed until the update status state is succeeded.
+  let state = readStatusState();
+  if (state != STATE_SUCCEEDED) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
+               "status state to equal " + STATE_SUCCEEDED + ", " +
+               "current status state: " + state);
+    } else {
       do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
-    return;
-  }
-
-  // Don't proceed until the update status is no longer pending or applying.
-  let status = readStatusFile();
-  if (status == STATE_PENDING || status == STATE_APPLYING) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for updates status " +
-               "to not be pending or applying, current status is: " + status);
-    else
-      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
+    }
     return;
   }
 
-  // Don't proceed until the update.log file can be renamed to update.log.bak
-  // (bug 889860).
-  try {
-    log.moveTo(updatesDir, FILE_UPDATE_LOG + ".bak");
-  }
-  catch (e) {
-    logTestInfo("unable to rename file " + FILE_UPDATE_LOG + " to " +
-                FILE_UPDATE_LOG + ".bak. Exception: " + e);
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting to be able to " +
-               "rename " + FILE_UPDATE_LOG + " to " + FILE_UPDATE_LOG +
-               ".bak. Path: " + log.path);
-    else
+  // Don't proceed until the update log has been created.
+  let log = getUpdatesPatchDir();
+  log.append(FILE_UPDATE_LOG);
+  if (!log.exists()) {
+    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update log " +
+               "to be created. Path: " + log.path);
+    } else {
       do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
+    }
     return;
   }
 
-  restoreLogFile();
-}
-
-/**
- * Checks if the renamed the update.log file can be renamed back to make
- * sure it is not in use and if so, continues the test.
- */
-function restoreLogFile() {
-  gTimeoutRuns++;
-  // Don't proceed until the update.log.bak file can be renamed back to
-  // update.log (bug 889860).
-  let updatesDir = getUpdatesDir();
-  updatesDir.append("0");
-  let log = updatesDir.clone();
-  log.append(FILE_UPDATE_LOG + ".bak");
-  try {
-    log.moveTo(updatesDir, FILE_UPDATE_LOG);
-  }
-  catch (e) {
-    logTestInfo("unable to rename file " + FILE_UPDATE_LOG + ".bak back to " +
-                FILE_UPDATE_LOG + ". Exception: " + e);
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting to be able to " +
-               "rename " + FILE_UPDATE_LOG + ".bak back to " + FILE_UPDATE_LOG +
-               ". Path: " + log.path);
-    else
-      do_timeout(TEST_CHECK_TIMEOUT, restoreLogFile);
-    return;
+  let updater = getUpdatesPatchDir();
+  updater.append(FILE_UPDATER_BIN);
+  if (updater.exists()) {
+    try {
+      updater.remove(false);
+    } catch (e) {
+      do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
+      return;
+    }
   }
 
   // Log the contents of the update.log so it is simpler to diagnose a test
   // failure. For example, on Windows if the application binary is in use the
   // updater will not apply the update.
   let contents = readFile(log);
   logTestInfo("contents of " + log.path + ":\n" +  
               contents.replace(/\r\n/g, "\n"));
 
-  if (IS_WIN && contents.indexOf("NS_main: file in use") != -1) {
-    do_throw("the application can't be in use when running this test");
-  }
-
-  let status = readStatusFile();
-  do_check_eq(status, STATE_SUCCEEDED);
-
   standardInit();
 
   let update = gUpdateManager.getUpdateAt(0);
   do_check_eq(update.state, STATE_SUCCEEDED);
 
   let updateTestDir = getUpdateTestDir();
 
   let file = updateTestDir.clone();
@@ -309,53 +131,29 @@ function restoreLogFile() {
   do_check_true(file.exists());
   do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
 
   file = updateTestDir.clone();
   file.append("removed-files");
   do_check_true(file.exists());
   do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
 
-  checkLogRenameFinished();
-}
-
-/**
- * Checks if the update.log file has been renamed after launch and if so,
- * continues the test.
- */
-function checkLogRenameFinished() {
-  gTimeoutRuns++;
-  // Don't proceed until the update.log has been renamed to last-update.log.
-  let log = getUpdatesDir();
-  log.append("0");
-  log.append(FILE_UPDATE_LOG);
-  if (log.exists()) {
-    if (gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whilst waiting for update log to " +
-               "be renamed to last-update.log at " + log.path);
-    else
-      do_timeout(TEST_CHECK_TIMEOUT, checkLogRenameFinished);
-    return;
-  }
-
-  let updatesDir = getUpdatesDir();
-  log = updatesDir.clone();
-  log.append("0");
+  log = getUpdatesPatchDir();
   log.append(FILE_UPDATE_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_LAST_LOG);
   logTestInfo("testing " + log.path + " should exist");
   do_check_true(log.exists());
 
-  log = updatesDir.clone();
+  log = getUpdatesDir();
   log.append(FILE_BACKUP_LOG);
   logTestInfo("testing " + log.path + " shouldn't exist");
   do_check_false(log.exists());
 
-  updatesDir.append("0");
-  logTestInfo("testing " + updatesDir.path + " should exist");
-  do_check_true(updatesDir.exists());
+  let updatesPatchDir = getUpdatesPatchDir();
+  logTestInfo("testing " + updatesPatchDir.path + " should exist");
+  do_check_true(updatesPatchDir.exists());
 
-  removeCallbackCopy();
+  waitForFilesInUse();
 }
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Application in use complete MAR file stage patch apply failure fallback test */
+/* Application in use complete MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -177,64 +177,51 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch the callback helper application so it is in use during the update
+  // Launch the callback helper application so it is in use during the update.
   let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
   callbackAppProcess.init(callbackApp);
   callbackAppProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Application in use complete MAR file stage patch apply failure test */
+/* Application in use complete MAR file staged patch apply failure test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -177,67 +177,52 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch the callback helper application so it is in use during the update
+  // Launch the callback helper application so it is in use during the update.
   let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
   callbackAppProcess.init(callbackApp);
   callbackAppProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0, null);
+  logTestInfo("testing update.status should be " + STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
-
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseStageSuccessComplete_unix.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Application in use complete MAR file stage patch apply success test */
+/* Application in use complete MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -223,104 +223,82 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on a successful
   // update (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile(null, true);
     applyToDir.lastModifiedTime = yesterday;
   }
 
   // Launch the callback helper application so it is in use during the update
   let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
   callbackApp.permissions = PERMS_DIRECTORY;
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
   callbackAppProcess.init(callbackApp);
   callbackAppProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  let applyToDir = getApplyDirFile();
-
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
-    let applyToDir = getApplyDirFile();
+    let applyToDir = getApplyDirFile(null, true);
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
+  let applyToDir = getApplyDirFile();
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
-    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
 
-  // Make sure that the intermediate directory has been removed
+  // Make sure that the intermediate directory has been removed.
   let updatedDir = applyToDir.clone();
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
+  updatedDir.append(DIR_UPDATED);
   do_check_false(updatedDir.exists());
 
   setupHelperFinish();
 }
 
-
 function checkUpdate() {
   checkCallbackAppLog();
 }
-
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marAppInUseSuccessComplete.js
@@ -223,21 +223,20 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch the callback helper application so it is in use during the update
+  // Launch the callback helper application so it is in use during the update.
   let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
   callbackApp.permissions = PERMS_DIRECTORY;
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"];
   let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"].
                            createInstance(AUS_Ci.nsIProcess);
   callbackAppProcess.init(callbackApp);
   callbackAppProcess.run(false, args, args.length);
 
@@ -251,49 +250,42 @@ function doUpdate() {
   // the past to test that the last modified time is updated on a successful
   // update (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
-
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
     let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
+  // Sorting on Linux is different so skip this check for now.
+  if (!IS_UNIX) {
+    checkUpdateLogContents(LOG_COMPLETE_SUCCESS);
+  }
 
   if (IS_WIN) {
     logTestInfo("testing tobedeleted directory doesn't exist");
     let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
     do_check_false(toBeDeletedDir.exists());
   }
 
   checkCallbackAppLog();
 }
-
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Replace app binary complete MAR file stage patch apply success test */
+/* Replace app binary complete MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -183,48 +183,36 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_WIN_MAR);
 
   gCallbackBinFile = "exe0.exe";
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppStageSuccessPartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* Patch app binary partial MAR file stage patch apply success test */
+/* Patch app binary partial MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -185,48 +185,36 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_WIN_MAR);
 
   gCallbackBinFile = "exe0.exe";
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessComplete_win.js
@@ -183,36 +183,29 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   setupUpdaterTest(FILE_COMPLETE_WIN_MAR);
 
   gCallbackBinFile = "exe0.exe";
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marCallbackAppSuccessPartial_win.js
@@ -185,36 +185,29 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
+  setupTestCommon();
 
   setupUpdaterTest(FILE_PARTIAL_WIN_MAR);
 
   gCallbackBinFile = "exe0.exe";
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marDirLockedStageFailure_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marDirLockedStageFailure_win.js
@@ -1,211 +1,79 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
- * Test applying an update by applying an update in the background and
- * launching an application
- */
-
-/**
- * This test is identical to test_0201_app_launch_apply_update.js, except
- * that it locks the application directory when the test is launched to
- * check if the alternate updated directory logic works correctly.
+ * Test applying an update by staging an update and launching an application to
+ * apply it.
  */
 
 /**
  * The MAR file used for this test should not contain a version 2 update
  * manifest file (e.g. updatev2.manifest).
  */
 
 function run_test() {
-  if (APP_BIN_NAME == "xulrunner") {
+  if (MOZ_APP_NAME == "xulrunner") {
     logTestInfo("Unable to run this test on xulrunner");
     return;
   }
 
-  setupTestCommon(false);
-
-  do_register_cleanup(end_test);
-
-  logTestInfo("setting up environment for the update test...");
-
-  symlinkUpdateFilesIntoBundleDirectory();
-  if (IS_WIN) {
-    adjustPathsOnWindows();
-  }
-
-  if (!gAppBinPath) {
-    do_throw("Main application binary not found... expected: " +
-             APP_BIN_NAME + APP_BIN_SUFFIX);
-    return;
-  }
-
-  // Don't attempt to show a prompt when the update is finished.
-  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
+  setupTestCommon();
 
   let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
   let patches = getLocalPatchString(null, null, null, null, null, "true",
                                     STATE_PENDING);
   let updates = getLocalUpdateString(patches, null, null, null, null, null,
                                      null, null, null, null, null, null,
                                      null, "true", channel);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-  // Read the application.ini and use its application version
-  let processDir = getAppDir();
-  lockDirectory(processDir);
-  let file = processDir.clone();
-  file.append("application.ini");
-  let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-            getService(AUS_Ci.nsIINIParserFactory).
-            createINIParser(file);
-  let version = ini.getString("App", "Version");
-  writeVersionFile(version);
+  writeVersionFile(getAppVersion());
   writeStatusFile(STATE_PENDING);
 
-  // Remove the old updated directory which might be left over from previous tests.
-  let oldUpdatedDir = processDir.clone();
-  oldUpdatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
-  if (oldUpdatedDir.exists()) {
-    oldUpdatedDir.remove(true);
-  }
-
-  // This is the directory where the update files will be located
-  let updateTestDir = getUpdateTestDir();
-  try {
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  let updatesPatchDir = getUpdatesDir();
-  updatesPatchDir.append("0");
+  let updatesPatchDir = getUpdatesPatchDir();
   let mar = getTestDirFile(FILE_SIMPLE_MAR);
   mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Backup the updater.ini file if it exists by moving it. This prevents the
-  // post update executable from being launched if it is specified.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK);
-  }
-
-  // Backup the updater-settings.ini file if it exists by moving it.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
-
   reloadUpdateManagerData();
   do_check_true(!!gUpdateManager.activeUpdate);
 
-  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
+  lockDirectory(getAppBaseDir());
 
-  setEnvironment();
+  let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
+  writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
-  // Initiate a background update.
-  logTestInfo("update preparation completed - calling processUpdate");
-  AUS_Cc["@mozilla.org/updates/update-processor;1"].
-    createInstance(AUS_Ci.nsIUpdateProcessor).
-    processUpdate(gUpdateManager.activeUpdate);
+  setupAppFilesAsync();
+}
 
-  resetEnvironment();
-
-  logTestInfo("processUpdate completed - waiting for update-staged notification");
+function setupAppFilesFinished() {
+  stageUpdate();
 }
 
 function end_test() {
-  logTestInfo("start - test cleanup");
   resetEnvironment();
-
-  let processDir = getAppDir();
-  // Restore the backup of the updater.ini if it exists.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI_BAK);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI);
-  }
-
-  // Restore the backed up updater-settings.ini if it exists.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI);
-  }
-
-  // Remove the files added by the update.
-  let updateTestDir = getUpdateTestDir();
-  try {
-    logTestInfo("removing update test directory " + updateTestDir.path);
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  if (IS_UNIX) {
-    // This will delete the launch script if it exists.
-    getLaunchScript();
-  }
-
-  cleanupTestCommon();
-  logTestInfo("finish - test cleanup");
-}
-
-function shouldAdjustPathsOnMac() {
-  // When running xpcshell tests locally, xpcshell and firefox-bin do not live
-  // in the same directory.
-  let dir = getCurrentProcessDir();
-  return (IS_MACOSX && dir.leafName != "MacOS");
 }
 
 /**
- * Gets the directory where the update adds / removes the files contained in the
- * update.
- *
- * @return  nsIFile for the directory where the update adds / removes the files
- *          contained in the update mar.
- */
-function getUpdateTestDir() {
-  let updateTestDir = getAppDir();
-  if (IS_MACOSX) {
-    updateTestDir = updateTestDir.parent.parent;
-  }
-  updateTestDir.append("update_test");
-  return updateTestDir;
-}
-
-/**
- * Checks if the update has failed being applied in the background.
+ * Checks if staging the update has failed.
  */
 function checkUpdateApplied() {
   // Don't proceed until the update has failed, and reset to pending.
   if (gUpdateManager.activeUpdate.state != STATE_PENDING) {
-    if (++gTimeoutRuns > MAX_TIMEOUT_RUNS)
-      do_throw("Exceeded MAX_TIMEOUT_RUNS whist waiting for pending state to finish");
-    else
+    if (++gTimeoutRuns > MAX_TIMEOUT_RUNS) {
+      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
+               STATE_PENDING + ", current state is: " +
+               gUpdateManager.activeUpdate.state);
+    } else {
       do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
+    }
     return;
   }
 
   do_timeout(TEST_CHECK_TIMEOUT, finishTest);
 }
 
 function finishTest() {
-  // Don't proceed until the update status is pending.
-  let status = readStatusFile();
-  do_check_eq(status, STATE_PENDING);
-
-  unlockDirectory(getAppDir());
-
-  removeCallbackCopy();
+  do_check_eq(readStatusState(), STATE_PENDING);
+  unlockDirectory(getAppBaseDir());
+  waitForFilesInUse();
 }
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFailurePartial.js
@@ -219,62 +219,50 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on all updates since
   // the precomplete file in the root of the bundle is renamed, etc. (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the partial mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a partial mar");
   // Note that on platforms where we use execv, we cannot trust the return code.
-  do_check_eq(exitValue, USE_EXECV ? 0 : 1);
+  runUpdate((USE_EXECV ? 0 : 1));
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateFailure();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_PARTIAL_FAILURE);
   }
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use complete MAR file background patch apply failure fallback test */
+/* File in use complete MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -183,65 +183,52 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[14].relPathDir +
                                      TEST_FILES[14].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use partial MAR file background patch apply failure fallback test */
+/* File in use partial MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -185,65 +185,52 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_WIN_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[12].relPathDir +
                                      TEST_FILES[12].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use complete MAR file background patch apply success test */
+/* File in use complete MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -183,66 +183,53 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[14].relPathDir +
                                      TEST_FILES[14].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0, null);
+  logTestInfo("testing update.status should be " + STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
-
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseStageSuccessPartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use partial MAR file background patch apply success test */
+/* File in use partial MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -185,66 +185,53 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_WIN_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[12].relPathDir +
                                      TEST_FILES[12].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0, null);
+  logTestInfo("testing update.status should be " + STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
-
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessComplete_win.js
@@ -183,52 +183,44 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[14].relPathDir +
                                      TEST_FILES[14].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
   checkUpdateLogContains(ERR_BACKUP_DISCARD);
 
   logTestInfo("testing tobedeleted directory exists");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_true(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileInUseSuccessPartial_win.js
@@ -185,52 +185,44 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_WIN_MAR);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let fileInUseBin = getApplyDirFile(TEST_FILES[12].relPathDir +
                                      TEST_FILES[12].fileName);
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
   checkUpdateLogContains(ERR_BACKUP_DISCARD);
 
   logTestInfo("testing tobedeleted directory exists");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_true(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailureComplete_win.js
@@ -177,21 +177,20 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -201,37 +200,28 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure();
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFailurePartial_win.js
@@ -178,21 +178,20 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -202,37 +201,28 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure();
   checkUpdateLogContains(ERR_UNABLE_OPEN_DEST);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File locked complete MAR file stage patch apply failure fallback test */
+/* File locked complete MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -177,22 +177,21 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -202,47 +201,35 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 1);
-
+  runUpdate(1, null);
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File locked partial MAR file stage patch apply failure fallback test */
+/* File locked partial MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -178,22 +178,21 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -203,47 +202,35 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 1);
-
+  runUpdate(1, null);
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File locked complete MAR file stage patch apply failure test */
+/* File locked complete MAR file staged patch apply failure test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -177,22 +177,21 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -202,50 +201,36 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 1);
+  runUpdate(1, null);
+  logTestInfo("testing update.status should be " + STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
-
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marFileLockedStageFailurePartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File locked partial MAR file stage patch apply failure test */
+/* File locked partial MAR file staged patch apply failure test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -178,22 +178,21 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  // Exclusively lock an existing file so it is in use during the update
+  // Exclusively lock an existing file so it is in use during the update.
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let helperDestDir = getApplyDirFile("a/b/");
   helperBin.copyTo(helperDestDir, FILE_HELPER_BIN);
   helperBin = getApplyDirFile("a/b/" + FILE_HELPER_BIN);
   // Strip off the first two directories so the path has to be from the helper's
   // working directory.
   let lockFileRelPath = TEST_FILES[3].relPathDir.split("/");
   lockFileRelPath = lockFileRelPath.slice(2);
@@ -203,50 +202,36 @@ function run_test() {
                      createInstance(AUS_Ci.nsIProcess);
   lockFileProcess.init(helperBin);
   lockFileProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 1);
+  runUpdate(1, null);
+  logTestInfo("testing update.status should be " + STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
-
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use inside removed dir complete MAR file background patch apply failure fallback test */
+/* File in use inside removed dir complete MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -183,74 +183,62 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                      TEST_DIRS[4].subDirs[0] +
                                      TEST_DIRS[4].subDirFiles[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                     TEST_DIRS[4].subDirs[0]);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[4].subDirFiles[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use inside removed dir partial MAR file background patch apply failure fallback test */
+/* File in use inside removed dir partial MAR file staged patch apply failure fallback test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -185,72 +185,60 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[2].relPathDir +
                                      TEST_DIRS[2].files[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[2].relPathDir);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[2].files[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_PENDING);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
+  do_check_eq(readStatusState(), STATE_PENDING);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessComplete_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use inside removed dir complete MAR file background patch apply success test */
+/* File in use inside removed dir complete MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -183,75 +183,63 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                      TEST_DIRS[4].subDirs[0] +
                                      TEST_DIRS[4].subDirFiles[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                     TEST_DIRS[4].subDirs[0]);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[4].subDirFiles[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseStageSuccessPartial_win.js
@@ -1,13 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-/* File in use inside removed dir partial MAR file background patch apply success test */
+/* File in use inside removed dir partial MAR file staged patch apply success test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -185,73 +185,61 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[2].relPathDir +
                                      TEST_DIRS[2].files[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[2].relPathDir);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[2].files[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "40"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
-
+  runUpdate(0, null);
   logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
   gDisableReplaceFallback = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
   checkFilesAfterUpdateFailure(getApplyDirFile);
   checkUpdateLogContains(ERR_RENAME_FILE);
 
   logTestInfo("testing tobedeleted directory does not exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessComplete_win.js
@@ -183,62 +183,54 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                      TEST_DIRS[4].subDirs[0] +
                                      TEST_DIRS[4].subDirFiles[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[4].relPathDir +
                                     TEST_DIRS[4].subDirs[0]);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[4].subDirFiles[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
   checkUpdateLogContains(ERR_BACKUP_DISCARD);
 
   logTestInfo("testing tobedeleted directory exists");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_true(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseSuccessPartial_win.js
@@ -185,60 +185,52 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
   let fileInUseBin = getApplyDirFile(TEST_DIRS[2].relPathDir +
                                      TEST_DIRS[2].files[0]);
   // Remove the empty file created for the test so the helper application can
   // replace it.
   fileInUseBin.remove(false);
 
   let helperBin = getTestDirFile(FILE_HELPER_BIN);
   let fileInUseDir = getApplyDirFile(TEST_DIRS[2].relPathDir);
   helperBin.copyTo(fileInUseDir, TEST_DIRS[2].files[0]);
 
-  // Launch an existing file so it is in use during the update
+  // Launch an existing file so it is in use during the update.
   let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"];
   let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"].
                          createInstance(AUS_Ci.nsIProcess);
   fileInUseProcess.init(fileInUseBin);
   fileInUseProcess.run(false, args, args.length);
 
   do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
 }
 
 function doUpdate() {
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   setupHelperFinish();
 }
 
 function checkUpdate() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
   checkFilesAfterUpdateSuccess();
   checkUpdateLogContains(ERR_BACKUP_DISCARD);
 
   logTestInfo("testing tobedeleted directory exists");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_true(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageFailurePartial.js
@@ -1,14 +1,14 @@
 /* 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/.
  */
 
-/* General Partial MAR File stage Patch Apply Failure Test */
+/* General Partial MAR File Staged Patch Apply Failure Test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -219,65 +219,55 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : false
 }, {
   description  : "Not removed for failed update (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : false
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on all updates since
   // the precomplete file in the root of the bundle is renamed, etc. (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the partial mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 1);
+  runUpdate(1);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_FAILED);
-  // The update status format for a failure is failed: # where # is the error
-  // code for the failure.
-  do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
+  do_check_eq(readStatusState(), STATE_FAILED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
+  gStageUpdate = false;
   checkFilesAfterUpdateFailure();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
+    gStageUpdate = true;
     checkUpdateLogContents(LOG_PARTIAL_FAILURE);
   }
 
-  // This shouldn't exist anyways in background updates, but let's make sure
+  // This shouldn't exist anyways for staged updates, but let's make sure.
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
   toBeDeletedDir = getTargetDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
-  do_test_finished();
+  waitForFilesInUse();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessComplete.js
@@ -1,14 +1,14 @@
 /* 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/.
  */
 
-/* General Complete MAR File Background Patch Apply Test */
+/* General Complete MAR File Staged Patch Apply Test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 var TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -257,30 +257,27 @@ function removeSymlink() {
 }
 
 function checkSymlink() {
   let args = ["check-symlink", getApplyDirFile().path + "/a/b/link"];
   runHelperProcess(args);
 }
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on a successful
   // update (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
   if (IS_UNIX) {
     removeSymlink();
     createSymlink();
     do_register_cleanup(removeSymlink);
     TEST_FILES.push({
@@ -291,88 +288,73 @@ function run_test() {
       compareContents  : "test",
       originalFile     : null,
       compareFile      : null,
       originalPerms    : 0o664,
       comparePerms     : 0o664
     });
   }
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  let updateLog = do_get_file(gTestID + UPDATES_DIR_SUFFIX, true);
-  updateLog.append(FILE_UPDATE_LOG);
-  do_check_eq(exitValue, 0);
+  runUpdate(0, null);
+  logTestInfo("testing update.status should be " + STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  logTestInfo("testing update.status should be " + STATE_APPLIED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
-
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_COMPLETE_SUCCESS);
   }
 
-  // This shouldn't exist anyways in background updates, but let's make sure
+  // This shouldn't exist anyways for staged updates, but let's make sure.
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
   toBeDeletedDir = getTargetDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
+  let applyToDir = getApplyDirFile();
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   if (IS_UNIX) {
     checkSymlink();
   } else {
     // Sorting on Linux is different so skip this check for now.
     checkUpdateLogContents(LOG_COMPLETE_SWITCH_SUCCESS);
   }
 
-  // This shouldn't exist anyways in background updates, but let's make sure
+  // This shouldn't exist anyways for staged updates, but let's make sure.
   logTestInfo("testing tobedeleted directory doesn't exist");
-  toBeDeletedDir = getApplyDirFile("tobedeleted", true);
+  let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
-  // Make sure that the intermediate directory has been removed
+  // Make sure that the intermediate directory has been removed.
   let updatedDir = applyToDir.clone();
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
+  updatedDir.append(DIR_UPDATED);
   do_check_false(updatedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marStageSuccessPartial.js
@@ -1,14 +1,14 @@
 /* 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/.
  */
 
-/* General Partial MAR File stage Patch Apply Test */
+/* General Partial MAR File Staged Patch Apply Test */
 
 // The files are listed in the same order as they are applied from the mar's
 // update.manifest. Complete updates have remove file and rmdir directory
 // operations located in the precomplete file performed first.
 const TEST_FILES = [
 {
   description      : "Should never change",
   fileName         : "channel-prefs.js",
@@ -226,100 +226,85 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
-  gBackgroundUpdate = true;
+  gStageUpdate = true;
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on all updates since
   // the precomplete file in the root of the bundle is renamed, etc. (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the partial mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0, null);
+  logTestInfo("testing update.status should be " + STATE_APPLIED);
+  do_check_eq(readStatusState(), STATE_APPLIED);
 
-  logTestInfo("testing update.status should be " + STATE_APPLIED);
-  do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
-
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_PARTIAL_SUCCESS);
   }
 
-  // This shouldn't exist anyways in background updates, but let's make sure
+  // This shouldn't exist anyways for staged updates, but let's make sure.
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
   toBeDeletedDir = getTargetDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
-  // Now switch the application and its updated version
-  gBackgroundUpdate = false;
+  // Now switch the application and its updated version.
+  gStageUpdate = false;
   gSwitchApp = true;
-  exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "switching to the updated application");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
+  let applyToDir = getApplyDirFile();
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_PARTIAL_SWITCH_SUCCESS);
   }
 
-  // This shouldn't exist anyways in background updates, but let's make sure
+  // This shouldn't exist anyways for staged updates, but let's make sure.
   logTestInfo("testing tobedeleted directory doesn't exist");
   toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
-  // Make sure that the intermediate directory has been removed
+  // Make sure that the intermediate directory has been removed.
   let updatedDir = applyToDir.clone();
-  updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
+  updatedDir.append(DIR_UPDATED);
   do_check_false(updatedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessComplete.js
@@ -224,60 +224,49 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by precomplete (rmdir)",
   relPathDir   : "a/b/2/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on a successful
   // update (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the complete mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a complete mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_COMPLETE_SUCCESS);
   }
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marSuccessPartial.js
@@ -226,59 +226,49 @@ ADDITIONAL_TEST_DIRS = [
   dirRemoved   : true
 }, {
   description  : "Removed by update.manifest (rmdir)",
   relPathDir   : "a/b/1/",
   dirRemoved   : true
 }];
 
 function run_test() {
-  setupTestCommon(true);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_PARTIAL_MAR);
 
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
-  let applyToDir = getApplyDirFile();
-
   // For Mac OS X set the last modified time for the root directory to a date in
   // the past to test that the last modified time is updated on all updates since
   // the precomplete file in the root of the bundle is renamed, etc. (bug 600098).
   if (IS_MACOSX) {
     let now = Date.now();
     let yesterday = now - (1000 * 60 * 60 * 24);
+    let applyToDir = getApplyDirFile();
     applyToDir.lastModifiedTime = yesterday;
   }
 
-  // apply the partial mar
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for success when " +
-              "applying a partial mar");
-  do_check_eq(exitValue, 0);
+  runUpdate(0);
+}
 
+function checkUpdateApplied() {
   logTestInfo("testing update.status should be " + STATE_SUCCEEDED);
-  do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED);
+  do_check_eq(readStatusState(), STATE_SUCCEEDED);
 
-  // For Mac OS X check that the last modified time for a directory has been
-  // updated after a successful update (bug 600098).
   if (IS_MACOSX) {
     logTestInfo("testing last modified time on the apply to directory has " +
                 "changed after a successful update (bug 600098)");
     let now = Date.now();
+    let applyToDir = getApplyDirFile();
     let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
     do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
   }
 
   checkFilesAfterUpdateSuccess();
   // Sorting on Linux is different so skip this check for now.
   if (!IS_UNIX) {
     checkUpdateLogContents(LOG_PARTIAL_SUCCESS);
   }
 
   logTestInfo("testing tobedeleted directory doesn't exist");
   let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
   do_check_false(toBeDeletedDir.exists());
 
   checkCallbackAppLog();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marVersionDowngrade.js
@@ -3,41 +3,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 /* Test version downgrade MAR security check */
 
 // We don't actually care if the MAR has any data, we only care about the
 // application return code and update.status result.
 const TEST_FILES = [];
-
 const VERSION_DOWNGRADE_ERROR = "23";
 
 function run_test() {
   if (!IS_MAR_CHECKS_ENABLED) {
     return;
   }
 
-  setupTestCommon(true);
-
-  // Setup an old version MAR file
+  setupTestCommon();
   setupUpdaterTest(FILE_OLD_VERSION_MAR);
 
   // Apply the MAR
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a version downgrade MAR");
-  // Make sure the updater execution failed.
   // Note that if execv is used, the updater process will turn into the
   // callback process, so its return code will be that of the callback
   // app.
-  do_check_eq(exitValue, USE_EXECV ? 0 : 1);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
+  runUpdate((USE_EXECV ? 0 : 1));
+}
 
-  //Make sure we get a version downgrade error
-  let updateStatus = readStatusFile(updatesDir);
-  do_check_eq(updateStatus.split(": ")[1], VERSION_DOWNGRADE_ERROR);
+function checkUpdateApplied() {
+  do_check_eq(readStatusFailedCode(), VERSION_DOWNGRADE_ERROR);
   do_test_finished();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
+++ b/toolkit/mozapps/update/tests/unit_base_updater/marWrongChannel.js
@@ -3,41 +3,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 /* Test product/channel MAR security check */
 
 // We don't actually care if the MAR has any data, we only care about the
 // application return code and update.status result.
 const TEST_FILES = [];
-
 const MAR_CHANNEL_MISMATCH_ERROR = "22";
 
 function run_test() {
   if (!IS_MAR_CHECKS_ENABLED) {
     return;
   }
 
-  setupTestCommon(true);
-
-  // Setup a wrong channel MAR file
+  setupTestCommon();
   setupUpdaterTest(FILE_WRONG_CHANNEL_MAR);
 
   // Apply the MAR
-  let exitValue = runUpdate();
-  logTestInfo("testing updater binary process exitValue for failure when " +
-              "applying a wrong product and channel MAR file");
-  // Make sure the updater execution failed.
   // Note that if execv is used, the updater process will turn into the
   // callback process, so its return code will be that of the callback
   // app.
-  do_check_eq(exitValue, USE_EXECV ? 0 : 1);
-  let updatesDir = do_get_file(gTestID + UPDATES_DIR_SUFFIX);
+  runUpdate((USE_EXECV ? 0 : 1));
+}
 
+function checkUpdateApplied() {
   //Make sure we get a version downgrade error
-  let updateStatus = readStatusFile(updatesDir);
-  do_check_eq(updateStatus.split(": ")[1], MAR_CHANNEL_MISMATCH_ERROR);
+  do_check_eq(readStatusFailedCode(), MAR_CHANNEL_MISMATCH_ERROR);
   do_test_finished();
 }
-
-function end_test() {
-  cleanupUpdaterTest();
-}
--- a/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
+++ b/toolkit/mozapps/update/tests/unit_base_updater/xpcshell.ini
@@ -12,34 +12,33 @@ tail =
 generated-files = head_update.js
 
 [marSuccessComplete.js]
 [marSuccessPartial.js]
 [marFailurePartial.js]
 [marStageSuccessComplete.js]
 skip-if = os == 'mac' || toolkit == 'gonk'
 reason = bug 820380
-[marVersionDowngrade.js]
-run-sequentially = Need to investigate.
-run-if = os == 'win'
 [marStageSuccessPartial.js]
 skip-if = os == 'mac'
+[marVersionDowngrade.js]
+run-if = os == 'win'
 [marWrongChannel.js]
 run-if = os == 'win'
 [marStageFailurePartial.js]
 [marCallbackAppSuccessComplete_win.js]
 run-if = os == 'win'
 [marCallbackAppSuccessPartial_win.js]
 run-if = os == 'win'
 [marCallbackAppStageSuccessComplete_win.js]
 run-if = os == 'win'
 [marCallbackAppStageSuccessPartial_win.js]
 run-if = os == 'win'
 [marAppInUseSuccessComplete.js]
-run-if = os == 'linux' || os == 'mac' || os == 'sunos' || os == 'win'
+skip-if = toolkit == 'gonk'
 [marAppInUseStageSuccessComplete_unix.js]
 run-if = os == 'linux' || os == 'sunos'
 [marAppInUseStageFailureComplete_win.js]
 run-if = os == 'win'
 [marAppInUseFallbackStageFailureComplete_win.js]
 run-if = os == 'win'
 [marFileLockedFailureComplete_win.js]
 run-if = os == 'win'
@@ -72,22 +71,18 @@ run-if = os == 'win'
 [marFileInUseFallbackStageFailureComplete_win.js]
 run-if = os == 'win'
 [marFileInUseFallbackStageFailurePartial_win.js]
 run-if = os == 'win'
 [marRMRFDirFileInUseFallbackStageFailureComplete_win.js]
 run-if = os == 'win'
 [marRMRFDirFileInUseFallbackStageFailurePartial_win.js]
 run-if = os == 'win'
+[marDirLockedStageFailure_win.js]
+run-if = os == 'win'
+[marAppApplyUpdateAppBinInUseStageSuccess_win.js]
+run-if = os == 'win'
 [marAppApplyUpdateSuccess.js]
-run-sequentially = Launches application.
 skip-if = toolkit == 'gonk'
 reason = bug 820380
 [marAppApplyUpdateStageSuccess.js]
-run-sequentially = Launches application.
 skip-if = toolkit == 'gonk'
 reason = bug 820380
-[marDirLockedStageFailure_win.js]
-run-sequentially = Launches application.
-run-if = os == 'win'
-[marAppApplyUpdateAppBinInUseStageSuccess_win.js]
-run-sequentially = Launches application.
-run-if = os == 'win'
--- a/toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/bootstrapSvc.js
@@ -18,25 +18,26 @@ const TEST_FILES = [
 }
 ];
 
 function run_test() {
   if (!shouldRunServiceTest(true)) {
     return;
   }
 
-  setupTestCommon(false);
-  do_register_cleanup(cleanupUpdaterTest);
-
+  setupTestCommon();
   setupUpdaterTest(FILE_COMPLETE_MAR);
 
-  // apply the complete mar
-  runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied, null, false);
+  setupAppFilesAsync();
 }
 
-function checkUpdateApplied() {
+function setupAppFilesFinished() {
+  runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, false);
+}
+
+function checkUpdateFinished() {
   checkFilesAfterUpdateSuccess();
 
   // We need to check the service log even though this is a bootstrap
   // because the app bin could be in use by this test by the time the next
   // test runs.
   checkCallbackServiceLog();
 }
--- a/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js
+++ b/toolkit/mozapps/update/tests/unit_service_updater/marAppApplyUpdateAppBinInUseStageSuccessSvc_win.js
@@ -1,293 +1,150 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
- * Test applying an update by applying an update in the background and
- * launching an application
- */
-
-/**
- * This test is identical to test_0201_app_launch_apply_update_svc.js, except
- * that it locks the application directory when the test is launched to
- * make the updater fall back to apply the update regularly.
+ * Test applying an update by staging an update and launching an application to
+ * apply it.
  */
 
 /**
  * The MAR file used for this test should not contain a version 2 update
  * manifest file (e.g. updatev2.manifest).
  */
 
 Components.utils.import("resource://gre/modules/ctypes.jsm");
 
-let gAppTimer;
-let gProcess;
+function run_test() {
+  if (MOZ_APP_NAME == "xulrunner") {
+    logTestInfo("Unable to run this test on xulrunner");
+    return;
+  }
 
-function run_test() {
   if (!shouldRunServiceTest()) {
     return;
   }
 
-  setupTestCommon(false);
-  do_register_cleanup(end_test);
+  setupTestCommon();
 
   if (IS_WIN) {
     Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, true);
   }
 
-  removeUpdateDirsAndFiles();
-
-  symlinkUpdateFilesIntoBundleDirectory();
-  if (IS_WIN) {
-    adjustPathsOnWindows();
-  }
-
-  if (!gAppBinPath) {
-    do_throw("Main application binary not found... expected: " +
-             APP_BIN_NAME + APP_BIN_SUFFIX);
-    return;
-  }
-
-  // Don't attempt to show a prompt when the update is finished.
-  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
-
-  gEnvSKipUpdateDirHashing = true;
   let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
   let patches = getLocalPatchString(null, null, null, null, null, "true",
                                     STATE_PENDING_SVC);
   let updates = getLocalUpdateString(patches, null, null, null, null, null,
                                      null, null, null, null, null, null,
                                      null, "true", channel);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
-
-  // Read the application.ini and use its application version
-  let processDir = getAppDir();
-  let file = processDir.clone();
-  file.append("application.ini");
-  let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-            getService(AUS_Ci.nsIINIParserFactory).
-            createINIParser(file);
-  let version = ini.getString("App", "Version");
-  writeVersionFile(version);
+  writeVersionFile(getAppVersion());
   writeStatusFile(STATE_PENDING_SVC);
 
-  // This is the directory where the update files will be located
-  let updateTestDir = getUpdateTestDir();
-  try {
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  let updatesPatchDir = getUpdatesDir();
-  updatesPatchDir.append("0");
+  let updatesPatchDir = getUpdatesPatchDir();
   let mar = getTestDirFile(FILE_SIMPLE_MAR);
   mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
 
-  // Backup the updater.ini file if it exists by moving it. This prevents the
-  // post update executable from being launched if it is specified.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK);
-  }
-
-  // Backup the updater-settings.ini file if it exists by moving it.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI_BAK);
-  }
-  updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
+  let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
 
   reloadUpdateManagerData();
   do_check_true(!!gUpdateManager.activeUpdate);
 
-  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
-
-  setEnvironment();
-
-  // Initiate a background update.
-  AUS_Cc["@mozilla.org/updates/update-processor;1"].
-    createInstance(AUS_Ci.nsIUpdateProcessor).
-    processUpdate(gUpdateManager.activeUpdate);
-
-  resetEnvironment();
+  setupAppFilesAsync();
 }
 
-function switchApp() {
-  let launchBin = getLaunchBin();
-  let args = getProcessArgs();
-  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
+function setupAppFilesFinished() {
+  stageUpdate();
+}
 
-  // Lock the installation directory
+function customLaunchAppToApplyUpdate() {
+  logTestInfo("start - locking installation directory");
   const LPCWSTR = ctypes.jschar.ptr;
   const DWORD = ctypes.uint32_t;
   const LPVOID = ctypes.voidptr_t;
   const GENERIC_READ = 0x80000000;
   const FILE_SHARE_READ = 1;
   const FILE_SHARE_WRITE = 2;
   const OPEN_EXISTING = 3;
   const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
   const INVALID_HANDLE_VALUE = LPVOID(0xffffffff);
   let kernel32 = ctypes.open("kernel32");
   let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi,
                                     LPVOID, LPCWSTR, DWORD, DWORD,
                                     LPVOID, DWORD, DWORD, LPVOID);
-  logTestInfo(gWindowsBinDir.path);
-  let handle = CreateFile(gWindowsBinDir.path, GENERIC_READ,
-                          FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
-                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
-  do_check_neq(handle.toString(), INVALID_HANDLE_VALUE.toString());
+  gHandle = CreateFile(getAppBaseDir().path, GENERIC_READ,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
+                       OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
+  do_check_neq(gHandle.toString(), INVALID_HANDLE_VALUE.toString());
   kernel32.close();
-
-  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
-                createInstance(AUS_Ci.nsIProcess);
-  gProcess.init(launchBin);
-
-  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
-  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
-                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
-
-  setEnvironment();
-
-  gProcess.runAsync(args, args.length, gProcessObserver);
-
-  resetEnvironment();
-}
-
-function end_test() {
-  if (gProcess.isRunning) {
-    logTestInfo("attempt to kill process");
-    gProcess.kill();
-  }
-
-  if (gAppTimer) {
-    logTestInfo("cancelling timer");
-    gAppTimer.cancel();
-    gAppTimer = null;
-  }
-
-  resetEnvironment();
-
-  let processDir = getAppDir();
-  // Restore the backup of the updater.ini if it exists.
-  let updaterIni = processDir.clone();
-  updaterIni.append(FILE_UPDATER_INI_BAK);
-  if (updaterIni.exists()) {
-    updaterIni.moveTo(processDir, FILE_UPDATER_INI);
-  }
-
-  // Restore the backed up updater-settings.ini if it exists.
-  let updateSettingsIni = processDir.clone();
-  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
-  if (updateSettingsIni.exists()) {
-    updateSettingsIni.moveTo(processDir, FILE_UPDATE_SETTINGS_INI);
-  }
-
-  // Remove the files added by the update.
-  let updateTestDir = getUpdateTestDir();
-  try {
-    logTestInfo("removing update test directory " + updateTestDir.path);
-    removeDirRecursive(updateTestDir);
-  }
-  catch (e) {
-    logTestInfo("unable to remove directory - path: " + updateTestDir.path +
-                ", exception: " + e);
-  }
-
-  if (IS_UNIX) {
-    // This will delete the launch script if it exists.
-    getLaunchScript();
-  }
-
-  cleanupTestCommon();
-}
-
-function shouldAdjustPathsOnMac() {
-  // When running xpcshell tests locally, xpcshell and firefox-bin do not live
-  // in the same directory.
-  let dir = getCurrentProcessDir();
-  return (IS_MACOSX && dir.leafName != "MacOS&q