Bug 900553 - Unit tests for updating apps. r=fabrice, r=ferjm
authorAntonio M. Amaya <amac@tid.es>
Thu, 05 Sep 2013 15:21:14 +0200
changeset 146627 56ec76b4037bf7b99ec15609ed8026b75c5216e1
parent 146626 e00feb59df108fa2576a333d70db6732575de85d
child 146628 ecc322e666c8074294ff3febd6e9177e0bfcc78a
push id25267
push userryanvm@gmail.com
push dateThu, 12 Sep 2013 00:58:25 +0000
treeherdermozilla-central@2f11fad2f307 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice, ferjm
bugs900553
milestone26.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 900553 - Unit tests for updating apps. r=fabrice, r=ferjm
dom/apps/tests/Makefile.in
dom/apps/tests/file_packaged_app.sjs
dom/apps/tests/test_packaged_app_common.js
dom/apps/tests/test_packaged_app_install.html
dom/apps/tests/test_packaged_app_update.html
--- a/dom/apps/tests/Makefile.in
+++ b/dom/apps/tests/Makefile.in
@@ -8,13 +8,15 @@ MOCHITEST_FILES = \
   file_cached_app.template.webapp \
   file_cached_app.template.appcache \
   file_hosted_app.template.webapp \
   test_app_update.html \
   file_packaged_app.sjs \
   file_packaged_app.template.webapp \
   file_packaged_app.template.html \
   test_packaged_app_install.html \
+  test_packaged_app_update.html \
+  test_packaged_app_common.js \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
   test_apps_service.xul \
   $(NULL)
--- a/dom/apps/tests/file_packaged_app.sjs
+++ b/dom/apps/tests/file_packaged_app.sjs
@@ -27,44 +27,47 @@ function handleRequest(request, response
   var devName = ("devName" in query) ? query.devName : gDevName;
   var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl;
 
   // If this is a version update, update state, prepare the manifest,
   // the application package and return.
   if ("setVersion" in query) {
     var version = query.setVersion;
     setState("version", version);
+    var packageVersion = ("dontUpdatePackage" in query) ? version - 1 : version;
+    var packageName = "test_packaged_app_" + packageVersion + ".zip";
 
-    var packageName = "test_packaged_app_" + version + ".zip";
     setState("packageName", packageName);
     var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" +
                       packageName;
     setState("packagePath", packagePath);
 
-    // Create the application package.
-    var zipWriter = Cc["@mozilla.org/zipwriter;1"]
-                    .createInstance(Ci.nsIZipWriter);
-    var zipFile = FileUtils.getFile("TmpD", [packageName]);
-    zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
+    if (version == packageVersion) {
+      // Create the application package.
+      var zipWriter = Cc["@mozilla.org/zipwriter;1"]
+                        .createInstance(Ci.nsIZipWriter);
+      var zipFile = FileUtils.getFile("TmpD", [packageName]);
+      zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
 
-    // We want to run some tests without the manifest included in the zip.
-    if (version != "0") {
-      var manifestTemplate = gBasePath + gMiniManifestTemplate;
-      var manifest = makeResource(manifestTemplate, version, packagePath,
-                                  packageSize, appName, devName, devUrl);
-      addZipEntry(zipWriter, manifest, "manifest.webapp");
+      // We want to run some tests without the manifest included in the zip.
+      if (version != "0") {
+        var manifestTemplate = gBasePath + gMiniManifestTemplate;
+        var manifest = makeResource(manifestTemplate, version, packagePath,
+                                    packageSize, appName, devName, devUrl);
+        addZipEntry(zipWriter, manifest, "manifest.webapp");
+      }
+
+      var appTemplate = gBasePath + gAppTemplate;
+      var app = makeResource(appTemplate, version, packagePath, packageSize,
+                             appName, devName, devUrl);
+      addZipEntry(zipWriter, app, "index.html");
+
+      zipWriter.close();
     }
 
-    var appTemplate = gBasePath + gAppTemplate;
-    var app = makeResource(appTemplate, version, packagePath, packageSize,
-                           appName, devName, devUrl);
-    addZipEntry(zipWriter, app, "index.html");
-
-    zipWriter.close();
-
     response.setHeader("Content-Type", "text/html", false);
     response.write("OK");
     return;
   }
 
   // Get the version from server state
   var version = Number(getState("version"));
   var packageName = String(getState("packageName"));
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/test_packaged_app_common.js
@@ -0,0 +1,229 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var PackagedTestHelper = (function PackagedTestHelper() {
+  "use strict";
+
+  var launchableValue;
+  var steps;
+  var index = -1;
+  var gSJSPath = "tests/dom/apps/tests/file_packaged_app.sjs";
+  var gSJS = "http://test/" + gSJSPath;
+  var gAppName = "appname";
+  var gApp = null;
+  var gInstallOrigin = "http://mochi.test:8888";
+
+  function debug(aMsg) {
+    //dump("== PackageTestHelper debug == " + aMsg + "\n");
+  }
+
+  function next() {
+    index += 1;
+    if (index >= steps.length) {
+      ok(false, "Shouldn't get here!");
+      return;
+    }
+    try {
+      steps[index]();
+    } catch(ex) {
+      ok(false, "Caught exception", ex);
+    }
+  }
+
+  function start() {
+    next();
+  }
+
+  function finish() {
+    SpecialPowers.setAllAppsLaunchable(launchableValue);
+    SpecialPowers.removePermission("webapps-manage", document);
+    SimpleTest.finish();
+  }
+
+  function mozAppsError() {
+    ok(false, "mozApps error: " + self.error.name);
+    finish();
+  }
+
+  function xhrError(event, url) {
+    var xhr = event.target;
+    ok(false, "XHR error loading " + url + ": " + xhr.status + " - " +
+       xhr.statusText);
+    finish();
+  }
+
+  function xhrAbort(url) {
+    ok(false, "XHR abort loading " + url);
+    finish();
+  }
+
+  function setAppVersion(aVersion, aCb, aDontUpdatePackage) {
+    var xhr = new XMLHttpRequest();
+    var dontUpdate = "";
+    if (aDontUpdatePackage) {
+      dontUpdate = "&dontUpdatePackage=1";
+    }
+    var url = gSJS + "?setVersion=" + aVersion + dontUpdate;
+    xhr.addEventListener("load", function() {
+                           is(xhr.responseText, "OK", "setAppVersion OK");
+                           aCb();
+                         });
+    xhr.addEventListener("error", event => xhrError(event, url));
+    xhr.addEventListener("abort", event => xhrAbort(url));
+    xhr.open("GET", url, true);
+    xhr.send();
+  }
+
+  function checkAppDownloadError(aMiniManifestURL,
+                                 aExpectedError,
+                                 aVersion,
+                                 aUninstall,
+                                 aDownloadAvailable,
+                                 aName,
+                                 aCb) {
+    var req = navigator.mozApps.installPackage(aMiniManifestURL);
+    req.onsuccess = function(evt) {
+      ok(true, "App installed");
+      if (!aUninstall) {
+        // Save it for later.
+        gApp = req.result;
+      }
+    };
+    req.onerror = function(evt) {
+      ok(false, "Got unexpected " + evt.target.error.name);
+      finish();
+    };
+
+    navigator.mozApps.mgmt.oninstall = function(evt) {
+      var aApp = evt.application;
+      aApp.ondownloaderror = function(evt) {
+        var error = aApp.downloadError.name;
+        if (error == aExpectedError) {
+          ok(true, "Got expected " + aExpectedError);
+          var expected = {
+            name: aName,
+            manifestURL: aMiniManifestURL,
+            installOrigin: gInstallOrigin,
+            progress: 0,
+            installState: "pending",
+            downloadAvailable: aDownloadAvailable,
+            downloading: false,
+            downloadSize: 0,
+            size: 0,
+            readyToApplyDownload: false
+          };
+          checkAppState(aApp, aVersion, expected, false, aUninstall,
+                        aCb || next);
+        } else {
+          ok(false, "Got unexpected " + error);
+          finish();
+        }
+      };
+      aApp.ondownloadsuccess = function(evt) {
+        ok(false, "We are supposed to throw " + aExpectedError);
+        finish();
+      };
+    };
+  }
+
+  function checkAppState(aApp,
+                         aVersion,
+                         aExpectedApp,
+                         aLaunchable,
+                         aUninstall,
+                         aCb) {
+    debug(JSON.stringify(aApp, null, 2));
+    if (aApp.manifest) {
+      debug(JSON.stringify(aApp.manifest, null, 2));
+    }
+
+    if (aExpectedApp.name) {
+      if (aApp.manifest) {
+        is(aApp.manifest.name, aExpectedApp.name, "Check name");
+      }
+      is(aApp.updateManifest.name, aExpectedApp.name, "Check name mini-manifest");
+    }
+    if (aApp.manifest) {
+      is(aApp.manifest.version, aVersion, "Check version");
+    }
+    if (typeof aExpectedApp.size !== "undefined" && aApp.manifest) {
+      is(aApp.manifest.size, aExpectedApp.size, "Check size");
+    }
+    if (aApp.manifest) {
+      is(aApp.manifest.launch_path, gSJSPath, "Check launch path");
+    }
+    if (aExpectedApp.manifestURL) {
+      is(aApp.manifestURL, aExpectedApp.manifestURL, "Check manifestURL");
+    }
+    if (aExpectedApp.installOrigin) {
+      is(aApp.installOrigin, aExpectedApp.installOrigin, "Check installOrigin");
+    }
+    ok(aApp.removable, "Removable app");
+    if (typeof aExpectedApp.progress !== "undefined") {
+      todo(aApp.progress == aExpectedApp.progress, "Check progress");
+    }
+    if (aExpectedApp.installState) {
+      is(aApp.installState, aExpectedApp.installState, "Check installState");
+    }
+    if (typeof aExpectedApp.downloadAvailable !== "undefined") {
+      is(aApp.downloadAvailable, aExpectedApp.downloadAvailable,
+         "Check download available");
+    }
+    if (typeof aExpectedApp.downloading !== "undefined") {
+      is(aApp.downloading, aExpectedApp.downloading, "Check downloading");
+    }
+    if (typeof aExpectedApp.downloadSize !== "undefined") {
+      is(aApp.downloadSize, aExpectedApp.downloadSize, "Check downloadSize");
+    }
+    if (typeof aExpectedApp.readyToApplyDownload !== "undefined") {
+      is(aApp.readyToApplyDownload, aExpectedApp.readyToApplyDownload,
+         "Check readyToApplyDownload");
+    }
+    if (aLaunchable) {
+      if (aUninstall) {
+        checkUninstallApp(aApp);
+      } else if (aCb && typeof aCb === "function") {
+        aCb();
+      }
+      return;
+    }
+
+    // Check if app is not launchable.
+    var req = aApp.launch();
+    req.onsuccess = function () {
+      ok(false, "We shouldn't be here");
+      finish();
+    };
+    req.onerror = function() {
+      ok(true, "App is not launchable");
+      if (aUninstall) {
+        checkUninstallApp(aApp);
+      } else if (aCb && typeof aCb === "function") {
+        aCb();
+      }
+      return;
+    };
+  }
+
+  return {
+    setSteps: function (aSteps) {
+      steps = aSteps;
+    },
+    next: next,
+    start: start,
+    finish: finish,
+    mozAppsError: mozAppsError,
+    setAppVersion: setAppVersion,
+    checkAppState: checkAppState,
+    checkAppDownloadError: checkAppDownloadError,
+    get gSJSPath() { return gSJSPath; },
+    get gSJS() { return gSJS; },
+    get gAppName() { return gAppName;},
+    get gApp() { return gApp; },
+    set gApp(aValue) { gApp = aValue; },
+    gInstallOrigin: gInstallOrigin,
+    launchableValue: launchableValue
+  };
+
+})();
--- a/dom/apps/tests/test_packaged_app_install.html
+++ b/dom/apps/tests/test_packaged_app_install.html
@@ -2,411 +2,232 @@
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id={821589}
 -->
 <head>
   <title>Test for Bug {821589} Packaged apps installation and update</title>
   <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="test_packaged_app_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={821589}">Mozilla Bug {821589}</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-
 "use strict";
 
-var gInstallOrigin = "http://mochi.test:8888";
-var gSJSPath = "tests/dom/apps/tests/file_packaged_app.sjs";
-var gSJS = "http://test/" + gSJSPath;
-var gAppName = "appname";
-var gApp = null;
-
-var launchableValue = undefined;
-
-var index = -1;
-
 function debug(aMsg) {
   //dump("== Tests debug == " + aMsg + "\n");
 }
 
-function next() {
-  index += 1;
-  if (index >= steps.length) {
-    ok(false, "Shouldn't get here!");
-    return;
-  }
-  try {
-    steps[index]();
-  } catch(ex) {
-    ok(false, "Caught exception", ex);
-  }
-}
-
-function go() {
-  next();
-}
-
-function finish() {
-  SpecialPowers.setAllAppsLaunchable(launchableValue);
-  SpecialPowers.removePermission("webapps-manage", document);
-  SimpleTest.finish();
-}
-
-function mozAppsError() {
-  ok(false, "mozApps error: " + this.error.name);
-  finish();
-}
-
-function xhrError(event, url) {
-  var xhr = event.target;
-  ok(false, "XHR error loading " + url + ": " + xhr.status + " - " +
-            xhr.statusText);
-  finish();
-}
-
-function xhrAbort(url) {
-  ok(false, "XHR abort loading " + url);
-  finish();
-}
-
-function setAppVersion(aVersion, aCb) {
-  var xhr = new XMLHttpRequest();
-  var url = gSJS + "?setVersion=" + aVersion;
-  xhr.addEventListener("load", function() {
-    is(xhr.responseText, "OK", "setAppVersion OK");
-    aCb();
-  });
-  xhr.addEventListener("error", event => xhrError(event, url));
-  xhr.addEventListener("abort", event => xhrAbort(url));
-  xhr.open("GET", url, true);
-  xhr.send();
-}
-
 function checkAppInstallError(aMiniManifestURL, aExpectedError) {
   var req = navigator.mozApps.installPackage(aMiniManifestURL);
   req.onsuccess = function() {
     ok(false, "We are supposed to throw " + aExpectedError);
-    finish();
+    PackagedTestHelper.finish();
   };
   req.onerror = function(evt) {
     var error = evt.target.error.name;
     if (error == aExpectedError) {
       ok(true, "Got expected " + aExpectedError);
-      next();
+      PackagedTestHelper.next();
     } else {
       ok(false, "Got unexpected " + aError);
-      finish();
+      PackagedTestHelper.finish();
     }
   };
 }
 
 function checkUninstallApp(aApp) {
   var req = navigator.mozApps.mgmt.uninstall(aApp);
   req.onsuccess = function() {
     ok(true, "App uninstalled");
     aApp.ondownloadsuccess = null;
     aApp.ondownloaderror = null;
     aApp.onprogress = null;
-    next();
-  };
-  req.onerror = function(evt) {
-    ok(false, "Got unexpected " + evt.target.error.name);
-    finish();
-  };
-}
-
-function checkAppDownloadError(aMiniManifestURL,
-                               aExpectedError,
-                               aVersion,
-                               aUninstall,
-                               aDownloadAvailable,
-                               aName) {
-  var req = navigator.mozApps.installPackage(aMiniManifestURL);
-  req.onsuccess = function() {
-    ok(true, "App installed");
+    PackagedTestHelper.next();
   };
   req.onerror = function(evt) {
     ok(false, "Got unexpected " + evt.target.error.name);
-    finish();
-  };
-
-  navigator.mozApps.mgmt.oninstall = function(evt) {
-    var aApp = evt.application;
-    aApp.ondownloaderror = function(evt) {
-      var error = aApp.downloadError.name;
-      if (error == aExpectedError) {
-        ok(true, "Got expected " + aExpectedError);
-        var expected = {
-          name: aName,
-          manifestURL: aMiniManifestURL,
-          installOrigin: gInstallOrigin,
-          progress: 0,
-          installState: "pending",
-          downloadAvailable: aDownloadAvailable,
-          downloading: false,
-          downloadSize: 0,
-          size: 0,
-          readyToApplyDownload: false,
-        };
-        checkAppState(aApp, aVersion, expected, false, aUninstall, next);
-      } else {
-        ok(false, "Got unexpected " + error);
-        finish();
-      }
-    };
-    aApp.ondownloadsuccess = function(evt) {
-      ok(false, "We are supposed to throw " + aExpectedError);
-      finish();
-    };
+    PackagedTestHelper.finish();
   };
 }
 
 function checkInstalledApp(aMiniManifestURL,
                            aVersion,
                            aExpectedApp,
                            aLaunchable,
                            aCb) {
   var req = navigator.mozApps.checkInstalled(aMiniManifestURL);
   req.onsuccess = function(evt) {
     ok(true, "The app is installed");
-    checkAppState(evt.application, aVersion, aExpectedApp, aLaunchable,
-                  false, aCb);
+    PackagedTestHelper.checkAppState(evt.application, aVersion, aExpectedApp,
+                                     aLaunchable, false, aCb);
   };
   req.onerror = function() {
     ok(false, "The app is not installed");
-    finish();
-  };
-}
-
-function checkAppState(aApp,
-                       aVersion,
-                       aExpectedApp,
-                       aLaunchable,
-                       aUninstall,
-                       aCb) {
-  debug(JSON.stringify(aApp, null, 2));
-  if (aApp.manifest) {
-    debug(JSON.stringify(aApp.manifest, null, 2));
-  }
-
-  if (aExpectedApp.name) {
-    if (aApp.manifest) {
-      is(aApp.manifest.name, aExpectedApp.name, "Check name");
-    }
-    is(aApp.updateManifest.name, aExpectedApp.name, "Check name mini-manifest");
-  }
-  if (aApp.manifest) {
-    is(aApp.manifest.version, aVersion, "Check version");
-  }
-  if (typeof aExpectedApp.size !== "undefined" && aApp.manifest) {
-    is(aApp.manifest.size, aExpectedApp.size, "Check size");
-  }
-  if (aApp.manifest) {
-    is(aApp.manifest.launch_path, gSJSPath, "Check launch path");
-  }
-  if (aExpectedApp.manifestURL) {
-    is(aApp.manifestURL, aExpectedApp.manifestURL, "Check manifestURL");
-  }
-  if (aExpectedApp.installOrigin) {
-    is(aApp.installOrigin, aExpectedApp.installOrigin, "Check installOrigin");
-  }
-  ok(aApp.removable, "Removable app");
-  if (typeof aExpectedApp.progress !== "undefined") {
-    todo(aApp.progress == aExpectedApp.progress, "Check progress");
-  }
-  if (aExpectedApp.installState) {
-    is(aApp.installState, aExpectedApp.installState, "Check installState");
-  }
-  if (typeof aExpectedApp.downloadAvailable !== "undefined") {
-    is(aApp.downloadAvailable, aExpectedApp.downloadAvailable,
-       "Check download available");
-  }
-  if (typeof aExpectedApp.downloading !== "undefined") {
-    is(aApp.downloading, aExpectedApp.downloading, "Check downloading");
-  }
-  if (typeof aExpectedApp.downloadSize !== "undefined") {
-    is(aApp.downloadSize, aExpectedApp.downloadSize, "Check downloadSize");
-  }
-  if (typeof aExpectedApp.readyToApplyDownload !== "undefined") {
-    is(aApp.readyToApplyDownload, aExpectedApp.readyToApplyDownload,
-       "Check readyToApplyDownload");
-  }
-  if (aLaunchable) {
-    if (aUninstall) {
-      checkUninstallApp(aApp);
-    } else if (aCb && typeof aCb === 'function') {
-      aCb();
-    }
-    return;
-  }
-
-  // Check if app is not launchable.
-  var req = aApp.launch();
-  req.onsuccess = function () {
-    ok(false, "We shouldn't be here");
-    finish();
-  };
-  req.onerror = function() {
-    ok(true, "App is not launchable");
-    if (aUninstall) {
-      checkUninstallApp(aApp);
-    } else if (aCb && typeof aCb === 'function') {
-      aCb();
-    }
-    return;
+    PackagedTestHelper.finish();
   };
 }
 
 SimpleTest.waitForExplicitFinish();
 
 var steps = [
   function() {
     // Set up
-    launchableValue = SpecialPowers.setAllAppsLaunchable(true);
+    PackagedTestHelper.launchableValue =
+      SpecialPowers.setAllAppsLaunchable(true);
     SpecialPowers.addPermission("webapps-manage", true, document);
     ok(true, "Set up");
-    next();
+    PackagedTestHelper.next();
   },
   function() {
     ok(true, "autoConfirmAppInstall");
-    SpecialPowers.autoConfirmAppInstall(next);
+    SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
   },
   function() {
-    setAppVersion(0, next);
+    PackagedTestHelper.setAppVersion(0, PackagedTestHelper.next);
   },
   function() {
     // Test network error.
     ok(true, "== TEST == Network error");
     checkAppInstallError("http://notvalidurl", "NETWORK_ERROR");
   },
   function() {
     // Test wrong mini-manifest content type.
     ok(true, "== TEST == Not valid mini-manifest content type");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&noManifestContentType=true";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test mini-manifest 'size' value is not number. Bug 839435.
     ok(true, "== TEST == Size value is not a number");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&packageSize=\"NotANumber\"";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test mini-manifest  negative 'size' value. Bug 839435.
     ok(true, "== TEST == Negative size value");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&packageSize=-1";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test wrong package path
     ok(true, "== TEST == Installing app with wrong package path");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&wrongPackagePath=true";
     checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
   },
   function() {
     // Test no manifest in zip file.
     ok(true, "== TEST == No manifest in the zip file");
-    var miniManifestURL = gSJS + "?getManifest=true";
-    checkAppDownloadError(miniManifestURL, "MISSING_MANIFEST", 0, true, true,
-                          gAppName);
+    var miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true";
+    PackagedTestHelper.checkAppDownloadError(miniManifestURL,
+                                            "MISSING_MANIFEST", 0, true, true,
+                                             PackagedTestHelper.gAppName);
   },
   function() {
-    setAppVersion(1, next);
+      PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next);
   },
   function() {
     // Test mini-manifest app name is different from the webapp manifest name.
     // Bug 844243.
     ok(true, "== TEST == Mini-manifest app name is different from webapp " +
              "manifest name");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&appName=arandomname";
-    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
-                          "arandomname");
+    PackagedTestHelper.checkAppDownloadError(miniManifestURL,
+                                             "MANIFEST_MISMATCH", 1, true, true,
+                                             "arandomname");
   },
   function() {
     // Test mini-manifest dev name is different from the webapp manifest dev
     // name.
     ok (true, "== TEST == Mini-manifest dev name is different from manifest " +
               "dev name");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&devName=arandomdevname";
-    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
-                          gAppName);
+    PackagedTestHelper.checkAppDownloadError(miniManifestURL,
+                                             "MANIFEST_MISMATCH", 1, true, true,
+                                             PackagedTestHelper.gAppName);
   },
   function() {
     // Test mini-manifest dev url is different from the webapp manifest dev
     // url.
     ok (true, "== TEST == Mini-manifest dev url is different from manifest " +
               "dev url");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true" +
                           "&devUrl=arandomdevurl";
-    checkAppDownloadError(miniManifestURL, "MANIFEST_MISMATCH", 1, true, true,
-                          gAppName);
+    PackagedTestHelper.checkAppDownloadError(miniManifestURL,
+                                             "MANIFEST_MISMATCH", 1, true, true,
+                                             PackagedTestHelper.gAppName);
   },
   function() {
-    setAppVersion(2, next);
+    PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next);
   },
   function() {
     ok(true, "== TEST == Install packaged app");
-    var miniManifestURL = gSJS +
+    var miniManifestURL = PackagedTestHelper.gSJS +
                           "?getManifest=true";
     navigator.mozApps.mgmt.oninstall = function(evt) {
       ok(true, "Got oninstall event");
-      gApp = evt.application;
-      gApp.ondownloaderror = function() {
-        ok(false, "Download error " + gApp.downloadError.name);
-        finish();
+      PackagedTestHelper.gApp = evt.application;
+      PackagedTestHelper.gApp.ondownloaderror = function() {
+        ok(false, "Download error " +
+                  PackagedTestHelper.gApp.downloadError.name);
+        PackagedTestHelper.finish();
       };
-      gApp.ondownloadsuccess = function() {
+      PackagedTestHelper.gApp.ondownloadsuccess = function() {
         ok(true, "App downloaded");
         var expected = {
-          name: gAppName,
+          name: PackagedTestHelper.gAppName,
           manifestURL: miniManifestURL,
-          installOrigin: gInstallOrigin,
+          installOrigin: PackagedTestHelper.gInstallOrigin,
           progress: 0,
           installState: "installed",
           downloadAvailable: false,
           downloading: false,
           downloadSize: 0,
           size: 0,
-          readyToApplyDownload: false,
+          readyToApplyDownload: false
         };
-        checkAppState(gApp, 2, expected, true, false, next);
+        PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, 2, expected,
+                                         true, false, PackagedTestHelper.next);
       };
     };
 
     var request = navigator.mozApps.installPackage(miniManifestURL);
-    request.onerror = mozAppsError;
+    request.onerror = PackagedTestHelper.mozAppsError;
     request.onsuccess = function() {
       ok(true, "Application installed");
     };
   },
   function() {
     ok(true, "all done!\n");
-    SimpleTest.finish();
+    PackagedTestHelper.finish();
   }
 ];
 
-addLoadEvent(go);
+PackagedTestHelper.setSteps(steps);
+
+addLoadEvent(PackagedTestHelper.start);
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/test_packaged_app_update.html
@@ -0,0 +1,192 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id={900533}
+-->
+<head>
+  <title>Test for Bug {900533} Packaged app update tests</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="test_packaged_app_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={900533}">Mozilla Bug {900533}</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+function debug(aMsg) {
+  //dump("== Tests debug == " + aMsg + "\n");
+}
+
+var miniManifestURL;
+
+SimpleTest.waitForExplicitFinish();
+
+function checkForUpdate(aExpected, aOnSuccess, aOnApplied, aLaunchDownload, aOnError) {
+  var lApp = PackagedTestHelper.gApp;
+
+  lApp.ondownloadsuccess = aOnSuccess || null;
+  lApp.ondownloadapplied = aOnApplied || null;
+
+  var request = lApp.checkForUpdate();
+  request.onerror = aOnError ? aOnError.bind(undefined, request) :
+                               PackagedTestHelper.mozAppsError;
+  request.onsuccess = function(event) {
+    var expectingDownload = aExpected ? "": "not ";
+    ok(lApp.downloadAvailable === aExpected,
+       "Download should " + expectingDownload + "be available");
+    if (aLaunchDownload && lApp.downloadAvailable) {
+      lApp.download();
+    } else {
+      PackagedTestHelper.next();
+    }
+  };
+}
+
+function checkLastAppState(aMiniManifestURL, aExpectedReady, aExpectedDownload,
+                           aExpectedVersion, aCb) {
+  ok(true, aExpectedReady ? "App downloaded" : "App download applied");
+  var expected = {
+    name: PackagedTestHelper.gAppName,
+    manifestURL: aMiniManifestURL,
+    installOrigin: PackagedTestHelper.gInstallOrigin,
+    progress: 0,
+    installState: aExpectedReady ? "updating" : "installed",
+    downloadAvailable: aExpectedDownload,
+    downloading: false,
+    size: 0,
+    readyToApplyDownload: aExpectedReady
+  };
+
+  PackagedTestHelper.checkAppState(PackagedTestHelper.gApp, aExpectedVersion,
+                                   expected, true, false, aCb);
+}
+
+function updateApp(aExpectedReady, aPreviousVersion, aNextVersion) {
+  var lApp = PackagedTestHelper.gApp;
+
+  var ondownloadappliedhandler =
+    checkLastAppState.bind(PackagedTestHelper, miniManifestURL, false, false,
+                           aNextVersion, PackagedTestHelper.next);
+
+    var ondownloadsuccesshandler =
+      checkLastAppState.bind(undefined, miniManifestURL,
+                             aExpectedReady, false, aPreviousVersion,
+                             function() {
+        navigator.mozApps.mgmt.applyDownload(lApp);
+    });
+
+    checkForUpdate(true, ondownloadsuccesshandler, ondownloadappliedhandler,
+                   true);
+
+}
+
+
+var steps = [
+  function() {
+    // Set up
+    PackagedTestHelper.launchableValue =
+      SpecialPowers.setAllAppsLaunchable(true);
+    SpecialPowers.addPermission("webapps-manage", true, document);
+    ok(true, "Set up");
+    PackagedTestHelper.next();
+  },
+  function() {
+    ok(true, "autoConfirmAppInstall");
+    SpecialPowers.autoConfirmAppInstall(PackagedTestHelper.next);
+  },
+  function() {
+    PackagedTestHelper.setAppVersion(2, PackagedTestHelper.next);
+  },
+  function() {
+    ok(true, "== TEST == Install packaged app");
+    navigator.mozApps.mgmt.oninstall = function(evt) {
+      ok(true, "Got oninstall event");
+      PackagedTestHelper.gApp = evt.application;
+      PackagedTestHelper.gApp.ondownloaderror = function() {
+        ok(false, "Download error " + PackagedTestHelper.gApp.downloadError.name);
+        PackagedTestHelper.finish();
+      };
+      PackagedTestHelper.gApp.ondownloadsuccess =
+        checkLastAppState.bind(undefined, miniManifestURL, false, false,
+                               2, PackagedTestHelper.next);
+    };
+
+    var request = navigator.mozApps.installPackage(miniManifestURL);
+    request.onerror = PackagedTestHelper.mozAppsError;
+    request.onsuccess = function() {
+      ok(true, "Application installed");
+    };
+  },
+  function() {
+    PackagedTestHelper.setAppVersion(3, PackagedTestHelper.next);
+  },
+  function() {
+    ok(true, "== TEST == Update packaged app");
+    updateApp(true, 2, 3);
+  },
+  function() {
+    ok(true, "== TEST == Check for Update after getting a new package");
+    checkForUpdate(false);
+  },
+  function() {
+    PackagedTestHelper.setAppVersion(4, PackagedTestHelper.next, true);
+  },
+  function() {
+    ok(true, "== TEST == Update packaged app - same package");
+    updateApp(false, 3, 4);
+  },
+  function() {
+    ok(true, "== TEST == Check for Update after getting the same package");
+    checkForUpdate(false);
+  },
+  function() {
+    PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next);
+  },
+  function() {
+    ok(true, "== TEST == Update packaged app - Updating a pending app");
+    miniManifestURL = PackagedTestHelper.gSJS +
+                      "?getManifest=true" +
+                      "&appName=arandomname" +
+                      "&appToFail1";
+    PackagedTestHelper.checkAppDownloadError(miniManifestURL,
+                                            "MANIFEST_MISMATCH", 2, false, true,
+                                             "arandomname",
+                                             function () {
+      checkForUpdate(false, null, null, false,
+                     function (request) {
+        if (request.error.name === "PENDING_APP_NOT_UPDATABLE") {
+          ok(true, "Got expected PENDING_APP_NOT_UPDATEABLE");
+        } else {
+          ok(false, "Got unexpected " + request.error.name);
+        }
+        PackagedTestHelper.next();
+      });
+    });
+  },
+  function() {
+    ok(true, "all done!\n");
+    PackagedTestHelper.finish();
+  }
+];
+
+PackagedTestHelper.setSteps(steps);
+// appToUpdate added to the URL so we get a unique URL for this app.
+// Unique in this case meaning different from the ones used on the
+// install tests
+miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true&appToUpdate";
+
+addLoadEvent(PackagedTestHelper.start);
+
+</script>
+</pre>
+</body>
+</html>