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 197888 43fa416d3ec387ecf4b5acaadf377764a0d90326
parent 197887 7010324e6153de232e01fe53ce555ca85f84fdce
child 197889 e6bb483835020a084c2326439e08599497902376
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmyk
bugs993690
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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>