Bug 981251 - Test app uninstallation. r=myk
authorMarco Castelluccio <mcastelluccio@mozilla.com>
Wed, 25 Jun 2014 02:37:28 +0200
changeset 190604 3b49cfc3c734bd98e2fd6e14208e3db20d7a15a2
parent 190603 bbb69edbebf14819adbd9d0e6d18684695344f47
child 190605 e7ae48a8fac8ab5f94c0e29ed546a36c1f2245ec
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmyk
bugs981251
milestone33.0a1
Bug 981251 - Test app uninstallation. r=myk
toolkit/webapps/tests/chrome.ini
toolkit/webapps/tests/head.js
toolkit/webapps/tests/test_hosted_uninstall.xul
toolkit/webapps/tests/test_packaged_uninstall.xul
--- a/toolkit/webapps/tests/chrome.ini
+++ b/toolkit/webapps/tests/chrome.ini
@@ -11,14 +11,18 @@ support-files =
 [test_hosted_launch.xul]
 skip-if = asan
 [test_hosted_launch_no_registry.xul]
 skip-if = asan
 [test_packaged_launch.xul]
 skip-if = asan
 [test_packaged_launch_no_registry.xul]
 skip-if = asan
+[test_hosted_uninstall.xul]
+skip-if = os == "win" && os_version == "5.1" # see bug 981251
+[test_packaged_uninstall.xul]
+skip-if = os == "win" && os_version == "5.1" # see bug 981251
 [test_hosted_update_from_webapp_runtime.xul]
 skip-if = asan
 [test_packaged_update_from_webapp_runtime.xul]
 skip-if = asan
 [test_hosted_icons.xul]
 [test_packaged_icons.xul]
--- a/toolkit/webapps/tests/head.js
+++ b/toolkit/webapps/tests/head.js
@@ -43,16 +43,49 @@ function checkDateHigherThan(files, date
         return false;
       }
     }
 
     return true;
   });
 }
 
+function dirContainsOnly(dir, expectedFiles) {
+  return Task.spawn(function*() {
+    let iterator = new OS.File.DirectoryIterator(dir);
+
+    let entries;
+    try {
+      entries = yield iterator.nextBatch();
+    } finally {
+      iterator.close();
+    }
+
+    let ret = true;
+
+    // Find unexpected files
+    for each (let {path} in entries) {
+      if (expectedFiles.indexOf(path) == -1) {
+        info("Unexpected file: " + path);
+        ret = false;
+      }
+    }
+
+    // Find missing files
+    for each (let expectedPath in expectedFiles) {
+      if (entries.findIndex(({path}) => path == expectedPath) == -1) {
+        info("Missing file: " + expectedPath);
+        ret = false;
+      }
+    }
+
+    return ret;
+  });
+}
+
 function wait(time) {
   let deferred = Promise.defer();
 
   setTimeout(function() {
     deferred.resolve();
   }, time);
 
   return deferred.promise;
@@ -284,16 +317,20 @@ function TestAppInfo(aApp) {
       if (this.appProcess && this.appProcess.isRunning) {
         this.appProcess.kill();
       }
 
       if (this.profileDir) {
         yield OS.File.removeDir(this.profileDir.parent.path, { ignoreAbsent: true });
       }
 
+      if (this.trashDir) {
+        yield OS.File.removeDir(this.trashDir, { ignoreAbsent: true });
+      }
+
       yield OS.File.removeDir(this.installPath, { ignoreAbsent: true });
 
       yield OS.File.removeDir(appProfileDir, { ignoreAbsent: true });
     });
   }
 }
 
 function buildAppPackage(aManifest, aIconFile) {
copy from toolkit/webapps/tests/test_hosted.xul
copy to toolkit/webapps/tests/test_hosted_uninstall.xul
--- a/toolkit/webapps/tests/test_hosted.xul
+++ b/toolkit/webapps/tests/test_hosted_uninstall.xul
@@ -52,24 +52,16 @@ let runTest = Task.async(function*() {
 
   SimpleTest.registerCleanupFunction(() => testAppInfo.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");
-  }
-
   testAppInfo.profileDir = nativeApp.createProfile();
   ok(testAppInfo.profileDir && testAppInfo.profileDir.exists(), "Profile directory created");
   ok((yield OS.File.exists(testAppInfo.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");
@@ -81,65 +73,70 @@ let runTest = Task.async(function*() {
   yield nativeApp.install(manifest);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(testAppInfo.installedFiles)), "Files correctly written");
   is(WebappOSUtils.getInstallPath(app), testAppInfo.installPath, "getInstallPath == installPath");
 
-  let stat = yield OS.File.stat(testAppInfo.installPath);
-  let installTime = stat.lastModificationDate;
-
-  // Wait one second, otherwise the last modification date is the same.
-  yield wait(1000);
+  // Uninstall application
+  info("Test uninstallation");
+  ok((yield WebappOSUtils.uninstall(app)), "Application uninstalled");
 
-  // Reinstall application
-  info("Test reinstallation");
-  yield nativeApp.install(manifest);
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
-  }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok((yield checkFiles(testAppInfo.tempUpdatedFiles)), "Files correctly written in the update subdirectory");
-
-  yield nativeApp.applyUpdate();
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
-  }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok(!(yield OS.File.exists(OS.Path.join(testAppInfo.installPath, "update"))), "Update directory removed");
-  ok((yield checkDateHigherThan(testAppInfo.updatedFiles, installTime)), "Modification date higher");
+  ok(testAppInfo.profileDir.exists(), "Profile directory still existent");
 
-  stat = yield OS.File.stat(testAppInfo.installPath);
-  installTime = stat.lastModificationDate;
-
-  // Wait one second, otherwise the last modification date is the same.
-  yield wait(1000);
-
-  // Update application
-  info("Test update");
-  yield nativeApp.prepareUpdate(manifest);
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
+  if (LINUX) {
+    ok((yield dirContainsOnly(testAppInfo.installPath,
+                              [
+                                testAppInfo.profileDir.path,
+                                testAppInfo.profilesIni
+                              ])),
+       "Files correctly removed");
+  } else if (WIN) {
+    ok((yield dirContainsOnly(testAppInfo.installPath, 
+                              [
+                                testAppInfo.profileDir.parent.path,
+                                testAppInfo.profilesIni,
+                                OS.Path.join(testAppInfo.installPath, "uninstall")
+                              ])),
+       "Files correctly removed");
+  } else if (MAC) {
+    ok(!(yield OS.File.exists(testAppInfo.installPath)), "Files correctly removed");
   }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok((yield checkFiles(testAppInfo.tempUpdatedFiles)), "Files correctly written in the update subdirectory");
+  // On Mac, the app is moved to the trash, it is still considered launchable
+  // (because it does have a install path).
+  if (!MAC) {
+    ok(!WebappOSUtils.isLaunchable(app), "App not launchable");
+    is(WebappOSUtils.getInstallPath(app), null, "getInstallPath == null");
+  } else {
+    testAppInfo.trashDir = WebappOSUtils.getInstallPath(app);
+    ok(testAppInfo.trashDir.contains(".Trash"), "App moved to Trash");
+  }
+
+  is(WebappOSUtils.launch(app), false, "Launch fails");
 
-  yield nativeApp.applyUpdate();
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
+  // On Mac, after we've tried to launch the app, its install path becomes null
+  // We can now repeat the tests we've already done on the other platforms:
+  if (MAC) {
+    while (WebappOSUtils.isLaunchable(app)) {
+      yield wait(1000);
+    }
+    ok(true, "App not launchable");
+
+    is(WebappOSUtils.getInstallPath(app), null, "getInstallPath == null");
   }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok(!(yield OS.File.exists(OS.Path.join(testAppInfo.installPath, "update"))), "Update directory removed");
-  ok((yield checkDateHigherThan(testAppInfo.updatedFiles, installTime)), "Modification date higher");
+
+  let exc;
+  try {
+    yield WebappOSUtils.uninstall(app);
+  } catch (e) {
+    exc = e;
+  }
+  ok(!!exc, "Re-uninstalling failed");
 
   SimpleTest.finish();
 });
 
 runTest().catch((e) => {
   ok(false, "Error during test: " + e);
   SimpleTest.finish();
 });
copy from toolkit/webapps/tests/test_packaged.xul
copy to toolkit/webapps/tests/test_packaged_uninstall.xul
--- a/toolkit/webapps/tests/test_packaged.xul
+++ b/toolkit/webapps/tests/test_packaged_uninstall.xul
@@ -61,24 +61,16 @@ let runTest = Task.async(function*() {
   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 {
-    yield nativeApp.prepareUpdate(manifest, zipPath);
-    ok(false, "Didn't thrown");
-  } catch (ex) {
-    is(ex, "The application isn't installed", "Exception thrown");
-  }
-
   testAppInfo.profileDir = nativeApp.createProfile();
   ok(testAppInfo.profileDir && testAppInfo.profileDir.exists(), "Profile directory created");
   ok((yield OS.File.exists(testAppInfo.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");
@@ -90,73 +82,70 @@ let runTest = Task.async(function*() {
   yield nativeApp.install(manifest, zipPath);
   while (!WebappOSUtils.isLaunchable(app)) {
     yield wait(1000);
   }
   ok(true, "App launchable");
   ok((yield checkFiles(testAppInfo.installedFiles)), "Files correctly written");
   is(WebappOSUtils.getInstallPath(app), testAppInfo.installPath, "getInstallPath == installPath");
 
-  let stat = yield OS.File.stat(testAppInfo.installPath);
-  let installTime = stat.lastModificationDate;
-
-  // Wait one second, otherwise the last modification date is the same.
-  yield wait(1000);
+  // Uninstall application
+  info("Test uninstallation");
+  ok((yield WebappOSUtils.uninstall(app)), "Application uninstalled");
 
-  // Reinstall application
-  info("Test reinstallation");
-
-  zipFile = yield OS.File.open(zipPath, { create: true });
-  yield zipFile.close();
+  ok(testAppInfo.profileDir.exists(), "Profile directory still existent");
 
-  yield nativeApp.install(manifest, zipPath);
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
+  if (LINUX) {
+    ok((yield dirContainsOnly(testAppInfo.installPath,
+                              [
+                                testAppInfo.profileDir.path,
+                                testAppInfo.profilesIni
+                              ])),
+       "Files correctly removed");
+  } else if (WIN) {
+    ok((yield dirContainsOnly(testAppInfo.installPath, 
+                              [
+                                testAppInfo.profileDir.parent.path,
+                                testAppInfo.profilesIni,
+                                OS.Path.join(testAppInfo.installPath, "uninstall")
+                              ])),
+       "Files correctly removed");
+  } else if (MAC) {
+    ok(!(yield OS.File.exists(testAppInfo.installPath)), "Files correctly removed");
   }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok((yield checkFiles(testAppInfo.tempUpdatedFiles)), "Files correctly written in the update subdirectory");
-
-  yield nativeApp.applyUpdate();
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
-  }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok(!(yield OS.File.exists(OS.Path.join(testAppInfo.installPath, "update"))), "Update directory removed");
-  ok((yield checkDateHigherThan(testAppInfo.updatedFiles, installTime)), "Modification date higher");
 
-  stat = yield OS.File.stat(testAppInfo.installPath);
-  installTime = stat.lastModificationDate;
-
-  // Wait one second, otherwise the last modification date is the same.
-  yield wait(1000);
+  // On Mac, the app is moved to the trash, it is still considered launchable
+  // (because it does have a install path).
+  if (!MAC) {
+    ok(!WebappOSUtils.isLaunchable(app), "App not launchable");
+    is(WebappOSUtils.getInstallPath(app), null, "getInstallPath == null");
+  } else {
+    testAppInfo.trashDir = WebappOSUtils.getInstallPath(app);
+    ok(testAppInfo.trashDir.contains(".Trash"), "App moved to Trash");
+  }
 
-  // Update application
-  info("Test update");
-
-  zipFile = yield OS.File.open(zipPath, { create: true });
-  yield zipFile.close();
+  is(WebappOSUtils.launch(app), false, "Launch fails");
 
-  yield nativeApp.prepareUpdate(manifest, zipPath);
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
-  }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok((yield checkFiles(testAppInfo.tempUpdatedFiles)), "Files correctly written in the update subdirectory");
+  // On Mac, after we've tried to launch the app, its install path becomes null
+  // We can now repeat the tests we've already done on the other platforms:
+  if (MAC) {
+    while (WebappOSUtils.isLaunchable(app)) {
+      yield wait(1000);
+    }
+    ok(true, "App not launchable");
 
-  yield nativeApp.applyUpdate();
-  while (!WebappOSUtils.isLaunchable(app)) {
-    yield wait(1000);
+    is(WebappOSUtils.getInstallPath(app), null, "getInstallPath == null");
   }
-  ok(true, "App launchable");
-  ok((yield checkFiles(testAppInfo.installedFiles)), "Installation not corrupted");
-  ok(!(yield OS.File.exists(OS.Path.join(testAppInfo.installPath, "update"))), "Update directory removed");
-  ok((yield checkDateHigherThan(testAppInfo.updatedFiles, installTime)), "Modification date higher");
+  let exc;
+  try {
+    yield WebappOSUtils.uninstall(app);
+  } catch (e) {
+    exc = e;
+  }
+  ok(!!exc, "Re-uninstalling failed");
 
   SimpleTest.finish();
 });
 
 runTest().catch((e) => {
   ok(false, "Error during test: " + e);
   SimpleTest.finish();
 });