Bug 993690 - Enable toolkit/webapps tests on Mac by installing apps in a directory that doesn't require admin privileges. r=myk
authorMarco Castelluccio <mar.castelluccio@studenti.unina.it>
Mon, 21 Apr 2014 10:16:02 -0400
changeset 179798 43fa416d3ec387ecf4b5acaadf377764a0d90326
parent 179797 7010324e6153de232e01fe53ce555ca85f84fdce
child 179799 e6bb483835020a084c2326439e08599497902376
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersmyk
bugs993690
milestone31.0a1
Bug 993690 - Enable toolkit/webapps tests on Mac by installing apps in a directory that doesn't require admin privileges. r=myk
toolkit/webapps/MacNativeApp.js
toolkit/webapps/tests/chrome.ini
toolkit/webapps/tests/head.js
toolkit/webapps/tests/test_hosted.xul
toolkit/webapps/tests/test_hosted_launch.xul
toolkit/webapps/tests/test_hosted_launch_no_registry.xul
toolkit/webapps/tests/test_packaged.xul
toolkit/webapps/tests/test_packaged_launch.xul
toolkit/webapps/tests/test_packaged_launch_no_registry.xul
--- a/toolkit/webapps/MacNativeApp.js
+++ b/toolkit/webapps/MacNativeApp.js
@@ -25,16 +25,23 @@ function NativeApp(aApp, aManifest, aCat
   this.macOSDir = OS.Path.join(this.contentsDir, "MacOS");
   this.resourcesDir = OS.Path.join(this.contentsDir, "Resources");
   this.iconFile = OS.Path.join(this.resourcesDir, "appicon.icns");
   this.zipFile = OS.Path.join(this.resourcesDir, "application.zip");
 }
 
 NativeApp.prototype = {
   __proto__: CommonNativeApp.prototype,
+  /*
+   * The _rootInstallDir property is the path of the directory where we install
+   * apps. In production code, it's "/Applications". In tests, it's
+   * "~/Applications" because on build machines we don't have enough privileges
+   * to write to the global "/Applications" directory.
+   */
+  _rootInstallDir: LOCAL_APP_DIR,
 
   /**
    * Creates a native installation of the web app in the OS
    *
    * @param aManifest {Object} the manifest data provided by the web app
    * @param aZipPath {String} path to the zip file for packaged apps (undefined
    *                          for hosted apps)
    */
@@ -45,26 +52,26 @@ NativeApp.prototype = {
 
     // If the application is already installed, this is a reinstallation.
     if (WebappOSUtils.getInstallPath(this.app)) {
       return yield this.prepareUpdate(aManifest, aZipPath);
     }
 
     this._setData(aManifest);
 
-    let localAppDir = getFile(LOCAL_APP_DIR);
+    let localAppDir = getFile(this._rootInstallDir);
     if (!localAppDir.isWritable()) {
       throw("Not enough privileges to install apps");
     }
- 
-    let destinationName = yield getAvailableFileName([ LOCAL_APP_DIR ],
+
+    let destinationName = yield getAvailableFileName([ this._rootInstallDir ],
                                                      this.appNameAsFilename,
                                                      ".app");
 
-    let installDir = OS.Path.join(LOCAL_APP_DIR, destinationName);
+    let installDir = OS.Path.join(this._rootInstallDir, destinationName);
 
     let dir = getFile(TMP_DIR, this.appNameAsFilename + ".app");
     dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
     let tmpDir = dir.path;
 
     try {
       yield this._createDirectoryStructure(tmpDir);
       this._copyPrebuiltFiles(tmpDir);
--- a/toolkit/webapps/tests/chrome.ini
+++ b/toolkit/webapps/tests/chrome.ini
@@ -1,19 +1,17 @@
 [DEFAULT]
 support-files =
   head.js
   app.sjs
   data/app/index.html
   data/app/manifest.webapp
 
 [test_hosted.xul]
-skip-if = os == "mac"
 [test_packaged.xul]
-skip-if = os == "mac"
 [test_hosted_launch.xul]
-skip-if = os == "mac" || asan
+skip-if = asan
 [test_hosted_launch_no_registry.xul]
-skip-if = os == "mac" || asan
+skip-if = asan
 [test_packaged_launch.xul]
-skip-if = os == "mac" || asan
+skip-if = asan
 [test_packaged_launch_no_registry.xul]
-skip-if = os == "mac" || asan
+skip-if = asan
--- a/toolkit/webapps/tests/head.js
+++ b/toolkit/webapps/tests/head.js
@@ -2,16 +2,21 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
+const LINUX = navigator.platform.startsWith("Linux");
+const MAC = navigator.platform.startsWith("Mac");
+const WIN = navigator.platform.startsWith("Win");
+const MAC_106 = navigator.userAgent.contains("Mac OS X 10.6");
+
 function checkFiles(files) {
   return Task.spawn(function*() {
     for (let file of files) {
       if (!(yield OS.File.exists(file))) {
         info("File doesn't exist: " + file);
         return false;
       }
     }
@@ -50,8 +55,25 @@ function wait(time) {
 }
 
 // Helper to create a nsIFile from a set of path components
 function getFile() {
   let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
   file.initWithPath(OS.Path.join.apply(OS.Path, arguments));
   return file;
 }
+
+function setDryRunPref() {
+  let old_dry_run;
+  try {
+    old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
+  } catch (ex) {}
+
+  Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
+
+  SimpleTest.registerCleanupFunction(function() {
+    if (old_dry_run === undefined) {
+      Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
+    } else {
+      Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
+    }
+  });
+}
--- a/toolkit/webapps/tests/test_hosted.xul
+++ b/toolkit/webapps/tests/test_hosted.xul
@@ -49,17 +49,17 @@ let profilesIni;
 let installPath;
 
 let installedFiles;
 let tempUpdatedFiles;
 let updatedFiles;
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
   }
@@ -94,17 +94,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "Sample hosted app.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "Sample hosted app.lnk");
 
   installedFiles = [
     OS.Path.join(installPath, "Sample hosted app.exe"),
     OS.Path.join(installPath, "chrome", "icons", "default", "default.ico"),
@@ -160,18 +160,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "Sample hosted app.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "Sample hosted app.app");
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   installedFiles = [
     OS.Path.join(installPath, "Contents", "Info.plist"),
     OS.Path.join(installPath, "Contents", "MacOS", "webapprt"),
     OS.Path.join(installPath, "Contents", "MacOS", "webapp.ini"),
     OS.Path.join(installPath, "Contents", "Resources", "appicon.icns"),
@@ -200,52 +200,46 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
-Task.spawn(function() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   info("Test update for an uninstalled application");
   try {
     yield nativeApp.prepareUpdate(manifest);
     ok(false, "Didn't thrown");
   } catch (ex) {
     is(ex, "The application isn't installed", "Exception thrown");
   }
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
   ok((yield OS.File.exists(profilesIni)), "profiles.ini file created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(installedFiles)), "Files correctly written");
@@ -297,16 +291,25 @@ Task.spawn(function() {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(installedFiles)), "Installation not corrupted");
   ok(!(yield OS.File.exists(OS.Path.join(installPath, "update"))), "Update directory removed");
   ok((yield checkDateHigherThan(updatedFiles, installTime)), "Modification date higher");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>
--- a/toolkit/webapps/tests/test_hosted_launch.xul
+++ b/toolkit/webapps/tests/test_hosted_launch.xul
@@ -49,17 +49,17 @@ let app = {
 let profileDir;
 let installPath;
 let exePath;
 let appProcess = Cc["@mozilla.org/process/util;1"].
                  createInstance(Ci.nsIProcess);
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "webapprt-stub");
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
@@ -78,17 +78,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "test_desktop_hosted_launch.exe");
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "test_desktop_hosted_launch.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "test_desktop_hosted_launch.lnk");
 
   cleanup = function() {
     return Task.spawn(function*() {
@@ -118,18 +118,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "test_desktop_hosted_launch.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "test_desktop_hosted_launch.app");
   exePath = OS.Path.join(installPath, "Contents", "MacOS", "webapprt");
 
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   cleanup = function() {
     return Task.spawn(function*() {
       if (appProcess.isRunning) {
@@ -142,33 +142,16 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
 function wasAppSJSAccessed() {
   let deferred = Promise.defer();
 
   var xhr = new XMLHttpRequest();
 
   xhr.addEventListener("load", function() {
     let ret = (xhr.responseText == "done") ? true : false;
     deferred.resolve(ret);
@@ -178,26 +161,37 @@ function wasAppSJSAccessed() {
   xhr.addEventListener("abort", aError => deferred.reject(aError));
 
   xhr.open('GET', 'http://test/chrome/toolkit/webapps/tests/app.sjs?testreq', true);
   xhr.send();
 
   return deferred.promise;
 }
 
-Task.spawn(function*() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
@@ -211,16 +205,25 @@ Task.spawn(function*() {
   appProcess.runAsync([], 0, () => appClosed = true);
 
   while (!(yield wasAppSJSAccessed()) && !appClosed) {
     yield wait(1000);
   }
   ok(!appClosed, "App was launched and is still running");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>
--- a/toolkit/webapps/tests/test_hosted_launch_no_registry.xul
+++ b/toolkit/webapps/tests/test_hosted_launch_no_registry.xul
@@ -49,17 +49,17 @@ let app = {
 let profileDir;
 let installPath;
 let exePath;
 let appProcess = Cc["@mozilla.org/process/util;1"].
                  createInstance(Ci.nsIProcess);
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "webapprt-stub");
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
@@ -78,17 +78,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "test_desktop_hosted_launch_no_registry.exe");
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "test_desktop_hosted_launch_no_registry.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "test_desktop_hosted_launch_no_registry.lnk");
 
   cleanup = function() {
     return Task.spawn(function*() {
@@ -118,18 +118,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "test_desktop_hosted_launch_no_registry.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "test_desktop_hosted_launch_no_registry.app");
   exePath = OS.Path.join(installPath, "Contents", "MacOS", "webapprt");
 
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   cleanup = function() {
     return Task.spawn(function*() {
       if (appProcess.isRunning) {
@@ -142,33 +142,16 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
 function wasAppSJSAccessed() {
   let deferred = Promise.defer();
 
   var xhr = new XMLHttpRequest();
 
   xhr.addEventListener("load", function() {
     let ret = (xhr.responseText == "done") ? true : false;
     deferred.resolve(ret);
@@ -178,26 +161,37 @@ function wasAppSJSAccessed() {
   xhr.addEventListener("abort", aError => deferred.reject(aError));
 
   xhr.open('GET', 'http://test/chrome/toolkit/webapps/tests/app.sjs?testreq', true);
   xhr.send();
 
   return deferred.promise;
 }
 
-Task.spawn(function*() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
@@ -211,16 +205,25 @@ Task.spawn(function*() {
   appProcess.runAsync([], 0, () => appClosed = true);
 
   while (!(yield wasAppSJSAccessed()) && !appClosed) {
     yield wait(1000);
   }
   ok(!appClosed, "App was launched and is still running");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>
--- a/toolkit/webapps/tests/test_packaged.xul
+++ b/toolkit/webapps/tests/test_packaged.xul
@@ -55,17 +55,17 @@ let profilesIni;
 let installPath;
 
 let installedFiles;
 let tempUpdatedFiles;
 let updatedFiles;
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
   }
@@ -103,17 +103,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "Sample packaged app.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "Sample packaged app.lnk");
 
   installedFiles = [
     OS.Path.join(installPath, "Sample packaged app.exe"),
     OS.Path.join(installPath, "chrome", "icons", "default", "default.ico"),
@@ -172,18 +172,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "Sample packaged app.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "Sample packaged app.app");
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   installedFiles = [
     OS.Path.join(installPath, "Contents", "Info.plist"),
     OS.Path.join(installPath, "Contents", "MacOS", "webapprt"),
     OS.Path.join(installPath, "Contents", "MacOS", "webapp.ini"),
     OS.Path.join(installPath, "Contents", "Resources", "appicon.icns"),
@@ -215,37 +215,24 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
-Task.spawn(function() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let zipFile = yield OS.File.open(zipPath, { create: true });
   yield zipFile.close();
 
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   info("Test update for an application that isn't installed");
   try {
@@ -254,16 +241,23 @@ Task.spawn(function() {
   } catch (ex) {
     is(ex, "The application isn't installed", "Exception thrown");
   }
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
   ok((yield OS.File.exists(profilesIni)), "profiles.ini file created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest, zipPath);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(installedFiles)), "Files correctly written");
@@ -323,16 +317,25 @@ Task.spawn(function() {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(installedFiles)), "Installation not corrupted");
   ok(!(yield OS.File.exists(OS.Path.join(installPath, "update"))), "Update directory removed");
   ok((yield checkDateHigherThan(updatedFiles, installTime)), "Modification date higher");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>
--- a/toolkit/webapps/tests/test_packaged_launch.xul
+++ b/toolkit/webapps/tests/test_packaged_launch.xul
@@ -59,17 +59,17 @@ let app = {
 let profileDir;
 let installPath;
 let exePath;
 let appProcess = Cc["@mozilla.org/process/util;1"].
                  createInstance(Ci.nsIProcess);
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "webapprt-stub");
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
@@ -88,17 +88,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "test_desktop_packaged_launch.exe");
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "test_desktop_packaged_launch.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "test_desktop_packaged_launch.lnk");
 
   cleanup = function() {
     return Task.spawn(function*() {
@@ -128,18 +128,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "test_desktop_packaged_launch.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "test_desktop_packaged_launch.app");
   exePath = OS.Path.join(installPath, "Contents", "MacOS", "webapprt");
 
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   cleanup = function() {
     return Task.spawn(function*() {
       if (appProcess.isRunning) {
@@ -152,33 +152,16 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
 function buildAppPackage() {
   let zipFile = getFile(OS.Constants.Path.profileDir, "sample.zip");
 
   let zipWriter = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
   zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
   zipWriter.addEntryFile("index.html",
                          Ci.nsIZipWriter.COMPRESSION_NONE,
                          getFile(getTestFilePath("data/app/index.html")),
@@ -206,28 +189,39 @@ function wasAppSJSAccessed() {
   xhr.addEventListener("abort", aError => deferred.reject(aError));
 
   xhr.open('GET', 'http://test/chrome/toolkit/webapps/tests/app.sjs?testreq', true);
   xhr.send();
 
   return deferred.promise;
 }
 
-Task.spawn(function() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let zipPath = buildAppPackage();
 
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest, zipPath);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
@@ -241,16 +235,25 @@ Task.spawn(function() {
   appProcess.runAsync([], 0, () => appClosed = true);
 
   while (!(yield wasAppSJSAccessed()) && !appClosed) {
     yield wait(1000);
   }
   ok(!appClosed, "App was launched and is still running");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>
--- a/toolkit/webapps/tests/test_packaged_launch_no_registry.xul
+++ b/toolkit/webapps/tests/test_packaged_launch_no_registry.xul
@@ -59,17 +59,17 @@ let app = {
 let profileDir;
 let installPath;
 let exePath;
 let appProcess = Cc["@mozilla.org/process/util;1"].
                  createInstance(Ci.nsIProcess);
 
 let cleanup;
 
-if (navigator.platform.startsWith("Linux")) {
+if (LINUX) {
   installPath = OS.Path.join(OS.Constants.Path.homeDir, "." + WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "webapprt-stub");
 
   let xdg_data_home = Cc["@mozilla.org/process/environment;1"].
                       getService(Ci.nsIEnvironment).
                       get("XDG_DATA_HOME");
   if (!xdg_data_home) {
     xdg_data_home = OS.Path.join(OS.Constants.Path.homeDir, ".local", "share");
@@ -88,17 +88,17 @@ if (navigator.platform.startsWith("Linux
         yield OS.File.removeDir(profileDir.parent.path, { ignoreAbsent: true });
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopINI, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Win")) {
+} else if (WIN) {
   installPath = OS.Path.join(OS.Constants.Path.winAppDataDir, WebappOSUtils.getUniqueName(app));
   exePath = OS.Path.join(installPath, "test_desktop_packaged_launch_no_registry.exe");
 
   let desktopShortcut = OS.Path.join(OS.Constants.Path.desktopDir, "test_desktop_packaged_launch_no_registry.lnk");
   let startMenuShortcut = OS.Path.join(OS.Constants.Path.winStartMenuProgsDir, "test_desktop_packaged_launch_no_registry.lnk");
 
   cleanup = function() {
     return Task.spawn(function*() {
@@ -128,18 +128,18 @@ if (navigator.platform.startsWith("Linux
       }
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.remove(desktopShortcut, { ignoreAbsent: true });
       yield OS.File.remove(startMenuShortcut, { ignoreAbsent: true });
     });
   };
-} else if (navigator.platform.startsWith("Mac")) {
-  installPath = OS.Path.join(OS.Constants.Path.macLocalApplicationsDir, "test_desktop_packaged_launch_no_registry.app");
+} else if (MAC) {
+  installPath = OS.Path.join(OS.Constants.Path.homeDir, "Applications", "test_desktop_packaged_launch_no_registry.app");
   exePath = OS.Path.join(installPath, "Contents", "MacOS", "webapprt");
 
   let appProfileDir = OS.Path.join(OS.Constants.Path.macUserLibDir, "Application Support",
                                    WebappOSUtils.getUniqueName(app));
 
   cleanup = function() {
     return Task.spawn(function*() {
       if (appProcess.isRunning) {
@@ -152,33 +152,16 @@ if (navigator.platform.startsWith("Linux
 
       yield OS.File.removeDir(installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   };
 }
 
-let old_dry_run;
-try {
-  old_dry_run = Services.prefs.getBoolPref("browser.mozApps.installer.dry_run");
-} catch (ex) {}
-
-Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", false);
-
-SimpleTest.registerCleanupFunction(function() {
-  if (old_dry_run === undefined) {
-    Services.prefs.clearUserPref("browser.mozApps.installer.dry_run");
-  } else {
-    Services.prefs.setBoolPref("browser.mozApps.installer.dry_run", old_dry_run);
-  }
-
-  cleanup();
-});
-
 function buildAppPackage() {
   let zipFile = getFile(OS.Constants.Path.profileDir, "sample.zip");
 
   let zipWriter = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter);
   zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
   zipWriter.addEntryFile("index.html",
                          Ci.nsIZipWriter.COMPRESSION_NONE,
                          getFile(getTestFilePath("data/app/index.html")),
@@ -206,28 +189,39 @@ function wasAppSJSAccessed() {
   xhr.addEventListener("abort", aError => deferred.reject(aError));
 
   xhr.open('GET', 'http://test/chrome/toolkit/webapps/tests/app.sjs?testreq', true);
   xhr.send();
 
   return deferred.promise;
 }
 
-Task.spawn(function() {
+let runTest = Task.async(function*() {
   // Get to a clean state before the test
   yield cleanup();
 
+  SimpleTest.registerCleanupFunction(cleanup);
+
+  setDryRunPref();
+
   let zipPath = buildAppPackage();
 
   let nativeApp = new NativeApp(app, manifest, app.categories);
   ok(nativeApp, "NativeApp object created");
 
   profileDir = nativeApp.createProfile();
   ok(profileDir && profileDir.exists(), "Profile directory created");
 
+  // On Mac build servers, we don't have enough privileges to write to /Applications,
+  // so we install apps in a user-owned directory.
+  if (MAC) {
+    nativeApp._rootInstallDir = OS.Path.join(OS.Constants.Path.homeDir, "Applications");
+    yield OS.File.makeDir(nativeApp._rootInstallDir, { ignoreExisting: true });
+  }
+
   // Install application
   info("Test installation");
   yield nativeApp.install(manifest, zipPath);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
 
@@ -241,16 +235,25 @@ Task.spawn(function() {
   appProcess.runAsync([], 0, () => appClosed = true);
 
   while (!(yield wasAppSJSAccessed()) && !appClosed) {
     yield wait(1000);
   }
   ok(!appClosed, "App was launched and is still running");
 
   SimpleTest.finish();
-}).then(null, function(e) {
-  ok(false, "Error during test: " + e);
+});
+
+// The test doesn't work yet on Mac OS X 10.6 machines.
+// See bug 993690.
+if (MAC_106) {
+  todo(false, "The test doesn't work on Mac OS X 10.6 machines");
   SimpleTest.finish();
-});
+} else {
+  runTest().then(null, function(e) {
+    ok(false, "Error during test: " + e);
+    SimpleTest.finish();
+  });
+}
 
 ]]>
 </script>
 </window>