Temporary workaround for Bug 1070148 - Copy maintenance service binary into its install directory when the installed binary is different. r=me
☠☠ backed out by 0fd9e14059f7 ☠ ☠
authorRobert Strong <robert.bugzilla@gmail.com>
Sat, 20 Sep 2014 17:34:26 -0700
changeset 491259 ca84f1f950b1899f2d55853a50dd897a130adb14
parent 491258 e12ab67e9f2de389a8e45c88c7c5ac1892242dcf
child 491260 0fd9e14059f70fd33bd45e428c38014d2d124033
push id47343
push userbmo:dothayer@mozilla.com
push dateWed, 01 Mar 2017 22:58:58 +0000
reviewersme
bugs1070148
milestone35.0a1
Temporary workaround for Bug 1070148 - Copy maintenance service binary into its install directory when the installed binary is different. r=me
toolkit/mozapps/update/tests/unit_aus_update/head_update.js
--- a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
@@ -1234,16 +1234,42 @@ function getTestDirPath() {
  * @throws  If the file or directory does not exist.
  */
 function getTestDirFile(aRelPath) {
   let relpath = getTestDirPath() + (aRelPath ? aRelPath : "");
   return do_get_file(relpath, false);
 }
 
 #ifdef XP_WIN
+function getSpecialFolderDir(aCSIDL) {
+  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.char16_t.ptr, /* LPTSTR lpszPath */
+                                           ctypes.int32_t, /* int csidl */
+                                           ctypes.bool /* BOOL fCreate */);
+
+  let aryPath = ctypes.char16_t.array()(260);
+  let rv = SHGetSpecialFolderPath(0, aryPath, aCSIDL, false);
+  lib.close();
+
+  let path = aryPath.readString(); // Convert the c-string to js-string
+  if (!path) {
+    return null;
+  }
+  logTestInfo("SHGetSpecialFolderPath returned path: " + path);
+  let dir = AUS_Cc["@mozilla.org/file/local;1"].
+            createInstance(AUS_Ci.nsILocalFile);
+  dir.initWithPath(path);
+  return dir;
+}
+
 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);
@@ -1271,61 +1297,23 @@ XPCOMUtils.defineLazyGetter(this, "gInst
                 ", Exception " + e);
   }
   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.char16_t.ptr, /* LPTSTR lpszPath */
-                                           ctypes.int32_t, /* int csidl */
-                                           ctypes.bool /* BOOL fCreate */);
-
-  let aryPathLocalAppData = ctypes.char16_t.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;
+  return getSpecialFolderDir(CSIDL_LOCAL_APPDATA);
 });
 
 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.char16_t.ptr, /* LPTSTR lpszPath */
-                                           ctypes.int32_t, /* int csidl */
-                                           ctypes.bool /* BOOL fCreate */);
-
-  let aryPathProgFiles = ctypes.char16_t.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;
+  return getSpecialFolderDir(CSIDL_PROGRAM_FILES);
 });
 
 /**
  * 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.
  */
@@ -1336,17 +1324,17 @@ function getMockUpdRootD() {
 
   let appDirPath = appDir.path;
   let 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 (!relPathUpdates && progFilesDir) {
     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);
@@ -1588,24 +1576,22 @@ function stageUpdate() {
 }
 
 /**
  * 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.
+ * @param  aSkipTest
+ *         Whether to skip this test if the installed maintenance service
+ *         isn't the same as the build's maintenance service.
  * @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();
-
+function shouldRunServiceTest(aFirstTest, aSkipTest) {
   let binDir = getGREDir();
   let updaterBin = binDir.clone();
   updaterBin.append(FILE_UPDATER_BIN);
   if (!updaterBin.exists()) {
     do_throw("Unable to find updater binary!");
   }
 
   let updaterBinPath = updaterBin.path;
@@ -1661,17 +1647,21 @@ function shouldRunServiceTest(aFirstTest
 #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
   if (!isBinarySigned(updaterBinPath)) {
     logTestInfo("test registry key exists but this test can only run on " +
                 "builds with signed binaries when " +
                 "DISABLE_UPDATER_AUTHENTICODE_CHECK is not defined");
     do_throw("this test can only run on builds with signed binaries.");
   }
 #endif
-  return true;
+
+  // 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 since all of the other checks passed.
+  return attemptServiceInstall(aSkipTest);
 }
 
 /**
  * Helper function to check whether the a binary is signed.
  *
  * @param  aBinPath The path to the file to check if it is signed.
  * @return true if the file is signed and false if it isn't.
  */
@@ -1861,37 +1851,92 @@ function copyFileToTestAppDir(aFileRelPa
   }
 }
 
 /**
  * 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.
+ *
+ * @param  aSkipTest
+ *         Whether to skip this test if the installed maintenance service
+ *         isn't the same as the build's maintenance service.
  */
-function attemptServiceInstall() {
-  var version = AUS_Cc["@mozilla.org/system-info;1"]
-                .getService(AUS_Ci.nsIPropertyBag2)
-                .getProperty("version");
-  var isVistaOrHigher = (parseFloat(version) >= 6.0);
-  if (isVistaOrHigher) {
-    return;
+function attemptServiceInstall(aSkipTest) {
+  const CSIDL_PROGRAM_FILES = 0x26;
+  const CSIDL_PROGRAM_FILESX86 = 0x2A;
+  // This will return an empty string on our Win XP build systems.
+  let maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILESX86);
+  if (maintSvcDir) {
+    maintSvcDir.append("Mozilla Maintenance Service");
+    logTestInfo("using CSIDL_PROGRAM_FILESX86 - maintenance service install " +
+                "directory path: " + maintSvcDir.path);
+  }
+  if (!maintSvcDir || !maintSvcDir.exists()) {
+    maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILES);
+    if (maintSvcDir) {
+      maintSvcDir.append("Mozilla Maintenance Service");
+      logTestInfo("using CSIDL_PROGRAM_FILES - maintenance service install " +
+                  "directory path: " + maintSvcDir.path);
+    }
+  }
+  if (!maintSvcDir || !maintSvcDir.exists()) {
+    do_throw("maintenance service install directory doesn't exist!");
+  }
+  let oldMaintSvcBin = maintSvcDir.clone();
+  oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN);
+  if (!oldMaintSvcBin.exists()) {
+    do_throw("maintenance service install directory binary doesn't exist! " +
+             "Path: " + oldMaintSvcBin.path);
   }
-
-  let binDir = getGREDir();
-  let installerFile = binDir.clone();
-  installerFile.append(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
-  if (!installerFile.exists()) {
-    do_throw(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN + " not found.");
+  let buildMaintSvcBin = getGREDir();
+  buildMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN);
+  if (readFileBytes(oldMaintSvcBin) == readFileBytes(buildMaintSvcBin)) {
+    logTestInfo("installed maintenance service binary is the same as the " +
+                "build's maintenance service binary");
+    return true;
   }
-  let installerProcess = AUS_Cc["@mozilla.org/process/util;1"].
-                         createInstance(AUS_Ci.nsIProcess);
-  installerProcess.init(installerFile);
-  logTestInfo("starting installer process...");
-  installerProcess.run(true, [], 0);
+  let backupMaintSvcBin = maintSvcDir.clone();
+  backupMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN + ".backup");
+  try {
+    if (backupMaintSvcBin.exists()) {
+      backupMaintSvcBin.remove(false);
+    }
+    oldMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN + ".backup");
+    buildMaintSvcBin.copyTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN);
+    backupMaintSvcBin.remove(false);
+    return true;
+  } catch (e) {
+    // Restore the original file in case the moveTo was successful.
+    if (backupMaintSvcBin.exists()) {
+      oldMaintSvcBin = maintSvcDir.clone();
+      oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN);
+      if (!oldMaintSvcBin.exists()) {
+        backupMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN);
+      }
+    }
+    logTestInfo("unable to copy new maintenance service into the " +
+                "maintenance service directory: " + maintSvcDir.path + ", " +
+                "Exception: " + e);
+  }
+
+  let version = AUS_Cc["@mozilla.org/system-info;1"].
+                getService(AUS_Ci.nsIPropertyBag2).
+                getProperty("version");
+  var isWin7 = (parseFloat(version) == 6.1);
+  // The account running the tests on Win 7 build systems appear to have write
+  // access to the maintenance service directory so throw if copying the
+  // maintenance service binary fails.
+  if (isWin7) {
+    do_throw("The account running the tests on Win 7 build systems should " +
+             "have write access to the maintenance service directory!");
+  }
+
+  return aSkipTest ? false : true;
 }
 
 /**
  * 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.