summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/update/tests/unit_aus_update
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/update/tests/unit_aus_update')
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js7
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js138
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js46
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js29
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js30
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js35
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js37
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js37
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js45
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js161
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js66
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js225
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js37
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/head_update.js8
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js285
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js75
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js76
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js74
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js177
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js305
-rw-r--r--toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini27
21 files changed, 1920 insertions, 0 deletions
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js b/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js
new file mode 100644
index 000000000..d35787cd2
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+ ]
+};
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js
new file mode 100644
index 000000000..1985df959
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/canCheckForAndCanApplyUpdates.js
@@ -0,0 +1,138 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ // Verify write access to the custom app dir
+ debugDump("testing write access to the application directory");
+ let testFile = getCurrentProcessDir();
+ testFile.append("update_write_access_test");
+ testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
+ Assert.ok(testFile.exists(), MSG_SHOULD_EXIST);
+ testFile.remove(false);
+ Assert.ok(!testFile.exists(), MSG_SHOULD_NOT_EXIST);
+
+ standardInit();
+
+ if (IS_WIN) {
+ // Create a mutex to prevent being able to check for or apply updates.
+ debugDump("attempting to create mutex");
+ let handle = createMutex(getPerInstallationMutexName());
+ Assert.ok(!!handle, "the update mutex should have been created");
+
+ // Check if available updates cannot be checked for when there is a mutex
+ // for this installation.
+ Assert.ok(!gAUS.canCheckForUpdates, "should not be able to check for " +
+ "updates when there is an update mutex");
+
+ // Check if updates cannot be applied when there is a mutex for this
+ // installation.
+ Assert.ok(!gAUS.canApplyUpdates, "should not be able to apply updates " +
+ "when there is an update mutex");
+
+ debugDump("destroying mutex");
+ closeHandle(handle);
+ }
+
+ // Check if available updates can be checked for
+ Assert.ok(gAUS.canCheckForUpdates, "should be able to check for updates");
+ // Check if updates can be applied
+ Assert.ok(gAUS.canApplyUpdates, "should be able to apply updates");
+
+ if (IS_WIN) {
+ // Attempt to create a mutex when application update has already created one
+ // with the same name.
+ debugDump("attempting to create mutex");
+ let handle = createMutex(getPerInstallationMutexName());
+
+ Assert.ok(!handle, "should not be able to create the update mutex when " +
+ "the application has created the update mutex");
+ }
+
+ doTestFinish();
+}
+
+/**
+ * Determines a unique mutex name for the installation.
+ *
+ * @return Global mutex path.
+ */
+function getPerInstallationMutexName() {
+ if (!IS_WIN) {
+ do_throw("Windows only function called by a different platform!");
+ }
+
+ let hasher = Cc["@mozilla.org/security/hash;1"].
+ createInstance(Ci.nsICryptoHash);
+ hasher.init(hasher.SHA1);
+
+ let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsILocalFile);
+
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
+ createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+ let data = converter.convertToByteArray(exeFile.path.toLowerCase());
+
+ hasher.update(data, data.length);
+ return "Global\\MozillaUpdateMutex-" + hasher.finish(true);
+}
+
+/**
+ * Closes a Win32 handle.
+ *
+ * @param aHandle
+ * The handle to close.
+ */
+function closeHandle(aHandle) {
+ if (!IS_WIN) {
+ do_throw("Windows only function called by a different platform!");
+ }
+
+ let lib = ctypes.open("kernel32.dll");
+ let CloseHandle = lib.declare("CloseHandle",
+ ctypes.winapi_abi,
+ ctypes.int32_t, /* success */
+ ctypes.void_t.ptr); /* handle */
+ CloseHandle(aHandle);
+ lib.close();
+}
+
+/**
+ * Creates a mutex.
+ *
+ * @param aName
+ * The name for the mutex.
+ * @return The Win32 handle to the mutex.
+ */
+function createMutex(aName) {
+ if (!IS_WIN) {
+ do_throw("Windows only function called by a different platform!");
+ }
+
+ const INITIAL_OWN = 1;
+ const ERROR_ALREADY_EXISTS = 0xB7;
+ let lib = ctypes.open("kernel32.dll");
+ let CreateMutexW = lib.declare("CreateMutexW",
+ ctypes.winapi_abi,
+ ctypes.void_t.ptr, /* return handle */
+ ctypes.void_t.ptr, /* security attributes */
+ ctypes.int32_t, /* initial owner */
+ ctypes.char16_t.ptr); /* name */
+
+ let handle = CreateMutexW(null, INITIAL_OWN, aName);
+ lib.close();
+ let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
+ if (handle && !handle.isNull() && alreadyExists) {
+ closeHandle(handle);
+ handle = null;
+ }
+
+ if (handle && handle.isNull()) {
+ handle = null;
+ }
+
+ return handle;
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
new file mode 100644
index 000000000..a0a95af1b
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForDifferentChannel.js
@@ -0,0 +1,46 @@
+/* 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/.
+ */
+
+/* General Update Manager Tests */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing removal of an active update for a channel that is not" +
+ "valid due to switching channels (Bug 486275).");
+
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_DOWNLOADING);
+ let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_DOWNLOADING);
+
+ patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_FAILED);
+ updates = getLocalUpdateString(patches, null, "Existing", "version 3.0",
+ "3.0", "3.0", null, null, null, null,
+ getString("patchApplyFailure"));
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), false);
+
+ setUpdateChannel("original_channel");
+
+ standardInit();
+
+ Assert.equal(gUpdateManager.updateCount, 1,
+ "the update manager update count" + MSG_SHOULD_EQUAL);
+ let update = gUpdateManager.getUpdateAt(0);
+ Assert.equal(update.name, "Existing",
+ "the update's name" + MSG_SHOULD_EQUAL);
+
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "there should not be an active update");
+ // Verify that the active-update.xml file has had the update from the old
+ // channel removed.
+ let file = getUpdatesXMLFile(true);
+ Assert.equal(readFile(file), getLocalUpdatesXMLString(""),
+ "the contents of active-update.xml" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
new file mode 100644
index 000000000..fc4f09787
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForOlderAppVersion.js
@@ -0,0 +1,29 @@
+/* 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/.
+ */
+
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing cleanup of an update download in progress for an " +
+ "older version of the application on startup (Bug 485624)");
+
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_DOWNLOADING);
+ let updates = getLocalUpdateString(patches, null, null, "version 0.9", "0.9");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_DOWNLOADING);
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+
+ standardInit();
+
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "there should not be an active update");
+ Assert.equal(gUpdateManager.updateCount, 0,
+ "the update manager update count" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
new file mode 100644
index 000000000..b2d8ecbc6
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingForSameVersionAndBuildID.js
@@ -0,0 +1,30 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing removal of an update download in progress for the " +
+ "same version of the application with the same application " +
+ "build id on startup (Bug 536547)");
+
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_DOWNLOADING);
+ let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0",
+ "2007010101");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_DOWNLOADING);
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+
+ standardInit();
+
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "there should not be an active update");
+ Assert.equal(gUpdateManager.updateCount, 0,
+ "the update manager update count" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
new file mode 100644
index 000000000..13e4aeaf6
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupDownloadingIncorrectStatus.js
@@ -0,0 +1,35 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing update cleanup when reading the status file returns " +
+ "STATUS_NONE and the update xml has an update with " +
+ "STATE_DOWNLOADING (Bug 539717).");
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_DOWNLOADING);
+ let updates = getLocalUpdateString(patches);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_NONE);
+
+ standardInit();
+
+ let dir = getUpdatesDir();
+ dir.append(DIR_PATCH);
+ Assert.ok(dir.exists(), MSG_SHOULD_EXIST);
+
+ let statusFile = dir.clone();
+ statusFile.append(FILE_UPDATE_STATUS);
+ Assert.ok(!statusFile.exists(), MSG_SHOULD_NOT_EXIST);
+
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "there should not be an active update");
+ Assert.equal(gUpdateManager.updateCount, 0,
+ "the update manager update count" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
new file mode 100644
index 000000000..7661da82d
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupPendingVersionFileIncorrectStatus.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing update cleanup when reading the status file returns " +
+ "STATUS_NONE, the version file is for a newer version, and the " +
+ "update xml has an update with STATE_PENDING (Bug 601701).");
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_PENDING);
+ let updates = getLocalUpdateString(patches);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeVersionFile("99.9");
+
+ standardInit();
+
+ // Check that there is no activeUpdate first so the updates directory is
+ // cleaned up by the UpdateManager before the remaining tests.
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "there should not be an active update");
+ Assert.equal(gUpdateManager.updateCount, 0,
+ "the update manager update count" + MSG_SHOULD_EQUAL);
+
+ let dir = getUpdatesDir();
+ dir.append(DIR_PATCH);
+ Assert.ok(dir.exists(), MSG_SHOULD_EXIST);
+
+ let versionFile = dir.clone();
+ versionFile.append(FILE_UPDATE_VERSION);
+ Assert.ok(!versionFile.exists(), MSG_SHOULD_NOT_EXIST);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
new file mode 100644
index 000000000..d683b9931
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
@@ -0,0 +1,37 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing that the update.log is moved after a successful update");
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_PENDING);
+ let updates = getLocalUpdateString(patches);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_SUCCEEDED);
+
+ let log = getUpdateLog(FILE_UPDATE_LOG);
+ writeFile(log, "Last Update Log");
+
+ standardInit();
+
+ Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST);
+
+ log = getUpdateLog(FILE_LAST_UPDATE_LOG);
+ Assert.ok(log.exists(), MSG_SHOULD_EXIST);
+ Assert.equal(readFile(log), "Last Update Log",
+ "the last update log contents" + MSG_SHOULD_EQUAL);
+
+ log = getUpdateLog(FILE_BACKUP_UPDATE_LOG);
+ Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST);
+
+ let dir = getUpdatesPatchDir();
+ Assert.ok(dir.exists(), MSG_SHOULD_EXIST);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js
new file mode 100644
index 000000000..8be93d0ff
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogsFIFO.js
@@ -0,0 +1,45 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing update logs are first in first out deleted");
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_PENDING);
+ let updates = getLocalUpdateString(patches);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_SUCCEEDED);
+
+ let log = getUpdateLog(FILE_LAST_UPDATE_LOG);
+ writeFile(log, "Backup Update Log");
+
+ log = getUpdateLog(FILE_BACKUP_UPDATE_LOG);
+ writeFile(log, "To Be Deleted Backup Update Log");
+
+ log = getUpdateLog(FILE_UPDATE_LOG);
+ writeFile(log, "Last Update Log");
+
+ standardInit();
+
+ Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST);
+
+ log = getUpdateLog(FILE_LAST_UPDATE_LOG);
+ Assert.ok(log.exists(), MSG_SHOULD_EXIST);
+ Assert.equal(readFile(log), "Last Update Log",
+ "the last update log contents" + MSG_SHOULD_EQUAL);
+
+ log = getUpdateLog(FILE_BACKUP_UPDATE_LOG);
+ Assert.ok(log.exists(), MSG_SHOULD_EXIST);
+ Assert.equal(readFile(log), "Backup Update Log",
+ "the backup update log contents" + MSG_SHOULD_EQUAL);
+
+ let dir = getUpdatesPatchDir();
+ Assert.ok(dir.exists(), MSG_SHOULD_EXIST);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js
new file mode 100644
index 000000000..b715fb56e
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadAndHashCheckMar.js
@@ -0,0 +1,161 @@
+/* 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 gNextRunFunc;
+var gExpectedStatusResult;
+
+function run_test() {
+ // The network code that downloads the mar file accesses the profile to cache
+ // the download, but the profile is only available after calling
+ // do_get_profile in xpcshell tests. This prevents an error from being logged.
+ do_get_profile();
+
+ setupTestCommon();
+
+ debugDump("testing mar download and mar hash verification");
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
+ start_httpserver();
+ setUpdateURL(gURLData + gHTTPHandlerPath);
+ standardInit();
+ // Only perform the non hash check tests when mar signing is enabled since the
+ // update service doesn't perform hash checks when mar signing is enabled.
+ if (MOZ_VERIFY_MAR_SIGNATURE) {
+ do_execute_soon(run_test_pt11);
+ } else {
+ do_execute_soon(run_test_pt1);
+ }
+}
+
+// The HttpServer must be stopped before calling do_test_finished
+function finish_test() {
+ stop_httpserver(doTestFinish);
+}
+
+// Helper function for testing mar downloads that have the correct size
+// specified in the update xml.
+function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) {
+ gUpdates = null;
+ gUpdateCount = null;
+ gStatusResult = null;
+ gCheckFunc = check_test_helper_pt1_1;
+ gNextRunFunc = aNextRunFunc;
+ gExpectedStatusResult = aExpectedStatusResult;
+ debugDump(aMsg, Components.stack.caller);
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_helper_pt1_1() {
+ Assert.equal(gUpdateCount, 1,
+ "the update count" + MSG_SHOULD_EQUAL);
+ gCheckFunc = check_test_helper_pt1_2;
+ let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
+ let state = gAUS.downloadUpdate(bestUpdate, false);
+ if (state == STATE_NONE || state == STATE_FAILED) {
+ do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state);
+ }
+ gAUS.addDownloadListener(downloadListener);
+}
+
+function check_test_helper_pt1_2() {
+ Assert.equal(gStatusResult, gExpectedStatusResult,
+ "the download status result" + MSG_SHOULD_EQUAL);
+ gAUS.removeDownloadListener(downloadListener);
+ gNextRunFunc();
+}
+
+function setResponseBody(aHashFunction, aHashValue, aSize) {
+ let patches = getRemotePatchString(null, null,
+ aHashFunction, aHashValue, aSize);
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+}
+
+// mar download with a valid MD5 hash
+function run_test_pt1() {
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with a valid MD5 hash",
+ Cr.NS_OK, run_test_pt2);
+}
+
+// mar download with an invalid MD5 hash
+function run_test_pt2() {
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR + "0");
+ run_test_helper_pt1("mar download with an invalid MD5 hash",
+ Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt3);
+}
+
+// mar download with a valid SHA1 hash
+function run_test_pt3() {
+ setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with a valid SHA1 hash",
+ Cr.NS_OK, run_test_pt4);
+}
+
+// mar download with an invalid SHA1 hash
+function run_test_pt4() {
+ setResponseBody("SHA1", SHA1_HASH_SIMPLE_MAR + "0");
+ run_test_helper_pt1("mar download with an invalid SHA1 hash",
+ Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt5);
+}
+
+// mar download with a valid SHA256 hash
+function run_test_pt5() {
+ setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with a valid SHA256 hash",
+ Cr.NS_OK, run_test_pt6);
+}
+
+// mar download with an invalid SHA256 hash
+function run_test_pt6() {
+ setResponseBody("SHA256", SHA256_HASH_SIMPLE_MAR + "0");
+ run_test_helper_pt1("mar download with an invalid SHA256 hash",
+ Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt7);
+}
+
+// mar download with a valid SHA384 hash
+function run_test_pt7() {
+ setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with a valid SHA384 hash",
+ Cr.NS_OK, run_test_pt8);
+}
+
+// mar download with an invalid SHA384 hash
+function run_test_pt8() {
+ setResponseBody("SHA384", SHA384_HASH_SIMPLE_MAR + "0");
+ run_test_helper_pt1("mar download with an invalid SHA384 hash",
+ Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt9);
+}
+
+// mar download with a valid SHA512 hash
+function run_test_pt9() {
+ setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with a valid SHA512 hash",
+ Cr.NS_OK, run_test_pt10);
+}
+
+// mar download with an invalid SHA512 hash
+function run_test_pt10() {
+ setResponseBody("SHA512", SHA512_HASH_SIMPLE_MAR + "0");
+ run_test_helper_pt1("mar download with an invalid SHA512 hash",
+ Cr.NS_ERROR_CORRUPTED_CONTENT, run_test_pt11);
+}
+
+// mar download with the mar not found
+function run_test_pt11() {
+ let patches = getRemotePatchString(null, gURLData + "missing.mar");
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("mar download with the mar not found",
+ Cr.NS_ERROR_UNEXPECTED, run_test_pt12);
+}
+
+// mar download with a valid MD5 hash but invalid file size
+function run_test_pt12() {
+ const arbitraryFileSize = 1024000;
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR, arbitraryFileSize);
+ run_test_helper_pt1("mar download with a valid MD5 hash but invalid file size",
+ Cr.NS_ERROR_UNEXPECTED, finish_test);
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
new file mode 100644
index 000000000..159033792
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadCompleteAfterPartialFailure.js
@@ -0,0 +1,66 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://testing-common/MockRegistrar.jsm");
+
+const WindowWatcher = {
+ getNewPrompter: function WW_getNewPrompter(aParent) {
+ Assert.ok(!aParent,
+ "the aParent parameter should not be defined");
+ return {
+ alert: function WW_GNP_alert(aTitle, aText) {
+ let title = getString("updaterIOErrorTitle");
+ Assert.equal(aTitle, title,
+ "the ui string for title" + MSG_SHOULD_EQUAL);
+ let text = gUpdateBundle.formatStringFromName("updaterIOErrorMsg",
+ [Services.appinfo.name,
+ Services.appinfo.name], 2);
+ Assert.equal(aText, text,
+ "the ui string for message" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+ }
+ };
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher])
+};
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing download a complete on partial failure. Calling " +
+ "nsIUpdatePrompt::showUpdateError should call getNewPrompter " +
+ "and alert on the object returned by getNewPrompter when the " +
+ "update.state == " + STATE_FAILED + " and the update.errorCode " +
+ "== " + WRITE_ERROR + " (Bug 595059).");
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
+
+ let windowWatcherCID =
+ MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcher);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(windowWatcherCID);
+ });
+
+ standardInit();
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let url = URL_HOST + "/" + FILE_COMPLETE_MAR;
+ let patches = getLocalPatchString("complete", url, null, null, null, null,
+ STATE_FAILED);
+ let updates = getLocalUpdateString(patches, null, null, "version 1.0", "1.0",
+ null, null, null, null, url);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_FAILED);
+
+ reloadUpdateManagerData();
+
+ let update = gUpdateManager.activeUpdate;
+ update.errorCode = WRITE_ERROR;
+ let prompter = Cc["@mozilla.org/updates/update-prompt;1"].
+ createInstance(Ci.nsIUpdatePrompt);
+ prompter.showUpdateError(update);
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
new file mode 100644
index 000000000..ef2da26af
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadInterruptedRecovery.js
@@ -0,0 +1,225 @@
+/* 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/.
+ */
+
+/* General MAR File Download Tests */
+
+Components.utils.import("resource://testing-common/MockRegistrar.jsm");
+const INC_CONTRACT_ID = "@mozilla.org/network/incremental-download;1";
+
+// gIncrementalDownloadErrorType is used to loop through each of the connection
+// error types in the Mock incremental downloader.
+var gIncrementalDownloadErrorType = 0;
+
+var gNextRunFunc;
+var gExpectedStatusResult;
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing mar downloads, mar hash verification, and " +
+ "mar download interrupted recovery");
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
+ start_httpserver();
+ setUpdateURL(gURLData + gHTTPHandlerPath);
+ standardInit();
+ do_execute_soon(run_test_pt1);
+}
+
+// The HttpServer must be stopped before calling do_test_finished
+function finish_test() {
+ stop_httpserver(doTestFinish);
+}
+
+// Helper function for testing mar downloads that have the correct size
+// specified in the update xml.
+function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) {
+ gUpdates = null;
+ gUpdateCount = null;
+ gStatusResult = null;
+ gCheckFunc = check_test_helper_pt1_1;
+ gNextRunFunc = aNextRunFunc;
+ gExpectedStatusResult = aExpectedStatusResult;
+ debugDump(aMsg, Components.stack.caller);
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_helper_pt1_1() {
+ Assert.equal(gUpdateCount, 1,
+ "the update count" + MSG_SHOULD_EQUAL);
+ gCheckFunc = check_test_helper_pt1_2;
+ let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
+ let state = gAUS.downloadUpdate(bestUpdate, false);
+ if (state == STATE_NONE || state == STATE_FAILED) {
+ do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state);
+ }
+ gAUS.addDownloadListener(downloadListener);
+}
+
+function check_test_helper_pt1_2() {
+ Assert.equal(gStatusResult, gExpectedStatusResult,
+ "the download status result" + MSG_SHOULD_EQUAL);
+ gAUS.removeDownloadListener(downloadListener);
+ gNextRunFunc();
+}
+
+function setResponseBody(aHashFunction, aHashValue, aSize) {
+ let patches = getRemotePatchString(null, null,
+ aHashFunction, aHashValue, aSize);
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+}
+
+function initMockIncrementalDownload() {
+ let incrementalDownloadCID =
+ MockRegistrar.register(INC_CONTRACT_ID, IncrementalDownload);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(incrementalDownloadCID);
+ });
+}
+
+/* This Mock incremental downloader is used to verify that connection
+ * interrupts work correctly in updater code. The implementation of
+ * the mock incremental downloader is very simple, it simply copies
+ * the file to the destination location.
+ */
+
+function IncrementalDownload() {
+ this.wrappedJSObject = this;
+}
+
+IncrementalDownload.prototype = {
+ /* nsIIncrementalDownload */
+ init: function(uri, file, chunkSize, intervalInSeconds) {
+ this._destination = file;
+ this._URI = uri;
+ this._finalURI = uri;
+ },
+
+ start: function(observer, ctxt) {
+ let tm = Cc["@mozilla.org/thread-manager;1"].
+ getService(Ci.nsIThreadManager);
+ // Do the actual operation async to give a chance for observers
+ // to add themselves.
+ tm.mainThread.dispatch(function() {
+ this._observer = observer.QueryInterface(Ci.nsIRequestObserver);
+ this._ctxt = ctxt;
+ this._observer.onStartRequest(this, this._ctxt);
+ let mar = getTestDirFile(FILE_SIMPLE_MAR);
+ mar.copyTo(this._destination.parent, this._destination.leafName);
+ let status = Cr.NS_OK;
+ switch (gIncrementalDownloadErrorType++) {
+ case 0:
+ status = Cr.NS_ERROR_NET_RESET;
+ break;
+ case 1:
+ status = Cr.NS_ERROR_CONNECTION_REFUSED;
+ break;
+ case 2:
+ status = Cr.NS_ERROR_NET_RESET;
+ break;
+ case 3:
+ status = Cr.NS_OK;
+ break;
+ case 4:
+ status = Cr.NS_ERROR_OFFLINE;
+ // After we report offline, we want to eventually show offline
+ // status being changed to online.
+ let tm2 = Cc["@mozilla.org/thread-manager;1"].
+ getService(Ci.nsIThreadManager);
+ tm2.mainThread.dispatch(function() {
+ Services.obs.notifyObservers(gAUS,
+ "network:offline-status-changed",
+ "online");
+ }, Ci.nsIThread.DISPATCH_NORMAL);
+ break;
+ }
+ this._observer.onStopRequest(this, this._ctxt, status);
+ }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
+ },
+
+ get URI() {
+ return this._URI;
+ },
+
+ get currentSize() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ get destination() {
+ return this._destination;
+ },
+
+ get finalURI() {
+ return this._finalURI;
+ },
+
+ get totalSize() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ /* nsIRequest */
+ cancel: function(aStatus) {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+ suspend: function() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+ isPending: function() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+ _loadFlags: 0,
+ get loadFlags() {
+ return this._loadFlags;
+ },
+ set loadFlags(val) {
+ this._loadFlags = val;
+ },
+
+ _loadGroup: null,
+ get loadGroup() {
+ return this._loadGroup;
+ },
+ set loadGroup(val) {
+ this._loadGroup = val;
+ },
+
+ _name: "",
+ get name() {
+ return this._name;
+ },
+
+ _status: 0,
+ get status() {
+ return this._status;
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIIncrementalDownload])
+};
+
+// Test disconnecting during an update
+function run_test_pt1() {
+ initMockIncrementalDownload();
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with connection interruption",
+ Cr.NS_OK, run_test_pt2);
+}
+
+// Test disconnecting during an update
+function run_test_pt2() {
+ gIncrementalDownloadErrorType = 0;
+ Services.prefs.setIntPref(PREF_APP_UPDATE_SOCKET_MAXERRORS, 2);
+ Services.prefs.setIntPref(PREF_APP_UPDATE_RETRYTIMEOUT, 0);
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with connection interruption without recovery",
+ Cr.NS_ERROR_NET_RESET, run_test_pt3);
+}
+
+// Test entering offline mode while downloading
+function run_test_pt3() {
+ gIncrementalDownloadErrorType = 4;
+ setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
+ run_test_helper_pt1("mar download with offline mode",
+ Cr.NS_OK, finish_test);
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
new file mode 100644
index 000000000..ca065f573
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/downloadResumeForSameAppVersion.js
@@ -0,0 +1,37 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing resuming an update download in progress for the same " +
+ "version of the application on startup (Bug 485624)");
+
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_DOWNLOADING);
+ let updates = getLocalUpdateString(patches, null, null, "1.0", "1.0");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_DOWNLOADING);
+
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+
+ standardInit();
+
+ Assert.equal(gUpdateManager.updateCount, 1,
+ "the update manager updateCount attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(gUpdateManager.activeUpdate.state, STATE_DOWNLOADING,
+ "the update manager activeUpdate state attribute" +
+ MSG_SHOULD_EQUAL);
+
+ // Pause the download and reload the Update Manager with an empty update so
+ // the Application Update Service doesn't write the update xml files during
+ // xpcom-shutdown which will leave behind the test directory.
+ gAUS.pauseDownload();
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ reloadUpdateManagerData();
+
+ do_execute_soon(doTestFinish);
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
new file mode 100644
index 000000000..9715c5828
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js
@@ -0,0 +1,8 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const IS_SERVICE_TEST = false;
+
+/* import-globals-from ../data/xpcshellUtilsAUS.js */
+load("../data/xpcshellUtilsAUS.js");
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
new file mode 100644
index 000000000..831c87257
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/remoteUpdateXML.js
@@ -0,0 +1,285 @@
+/* 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 gNextRunFunc;
+var gExpectedCount;
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing remote update xml attributes");
+
+ start_httpserver();
+ setUpdateURL(gURLData + gHTTPHandlerPath);
+ setUpdateChannel("test_channel");
+
+ // This test expects that the app.update.download.backgroundInterval
+ // preference doesn't already exist.
+ Services.prefs.deleteBranch("app.update.download.backgroundInterval");
+
+ standardInit();
+ do_execute_soon(run_test_pt01);
+}
+
+// Helper function for testing update counts returned from an update xml
+function run_test_helper_pt1(aMsg, aExpectedCount, aNextRunFunc) {
+ gUpdates = null;
+ gUpdateCount = null;
+ gCheckFunc = check_test_helper_pt1;
+ gNextRunFunc = aNextRunFunc;
+ gExpectedCount = aExpectedCount;
+ debugDump(aMsg, Components.stack.caller);
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_helper_pt1() {
+ Assert.equal(gUpdateCount, gExpectedCount,
+ "the update count" + MSG_SHOULD_EQUAL);
+ gNextRunFunc();
+}
+
+// update xml not found
+function run_test_pt01() {
+ run_test_helper_pt1("testing update xml not available",
+ null, run_test_pt02);
+}
+
+// one update available and the update's property values
+function run_test_pt02() {
+ debugDump("testing one update available and the update's property values");
+ gUpdates = null;
+ gUpdateCount = null;
+ gCheckFunc = check_test_pt02;
+ let patches = getRemotePatchString("complete", "http://complete/", "SHA1",
+ "98db9dad8e1d80eda7e1170d0187d6f53e477059",
+ "9856459");
+ patches += getRemotePatchString("partial", "http://partial/", "SHA1",
+ "e6678ca40ae7582316acdeddf3c133c9c8577de4",
+ "1316138");
+ let updates = getRemoteUpdateString(patches, "minor", "Minor Test",
+ "version 2.1a1pre", "2.1a1pre",
+ "20080811053724",
+ "http://details/",
+ "true",
+ "true", "345600", "1200",
+ "custom1_attr=\"custom1 value\"",
+ "custom2_attr=\"custom2 value\"");
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_pt02() {
+ // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244
+ // and until this is fixed this will not test the value for detailsURL when it
+ // isn't specified in the update xml.
+// let defaultDetailsURL;
+// try {
+ // Try using a default details URL supplied by the distribution
+ // if the update XML does not supply one.
+// let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
+// getService(Ci.nsIURLFormatter);
+// defaultDetailsURL = formatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS);
+// } catch (e) {
+// defaultDetailsURL = "";
+// }
+
+ Assert.equal(gUpdateCount, 1,
+ "the update count" + MSG_SHOULD_EQUAL);
+ let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount).QueryInterface(Ci.nsIPropertyBag);
+ Assert.equal(bestUpdate.type, "minor",
+ "the update type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.name, "Minor Test",
+ "the update name attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.displayVersion, "version 2.1a1pre",
+ "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.appVersion, "2.1a1pre",
+ "the update appVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.buildID, "20080811053724",
+ "the update buildID attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.detailsURL, "http://details/",
+ "the update detailsURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(bestUpdate.showPrompt,
+ "the update showPrompt attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(bestUpdate.showNeverForVersion,
+ "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.promptWaitTime, "345600",
+ "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
+ // The default and maximum value for backgroundInterval is 600
+ Assert.equal(bestUpdate.getProperty("backgroundInterval"), "600",
+ "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.serviceURL, gURLData + gHTTPHandlerPath + "?force=1",
+ "the update serviceURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.channel, "test_channel",
+ "the update channel attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!bestUpdate.isCompleteUpdate,
+ "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!bestUpdate.isSecurityUpdate,
+ "the update isSecurityUpdate attribute" + MSG_SHOULD_EQUAL);
+ // Check that installDate is within 10 seconds of the current date.
+ Assert.ok((Date.now() - bestUpdate.installDate) < 10000,
+ "the update installDate attribute should be within 10 seconds of " +
+ "the current time");
+ Assert.ok(!bestUpdate.statusText,
+ "the update statusText attribute" + MSG_SHOULD_EQUAL);
+ // nsIUpdate:state returns an empty string when no action has been performed
+ // on an available update
+ Assert.equal(bestUpdate.state, "",
+ "the update state attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.errorCode, 0,
+ "the update errorCode attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.patchCount, 2,
+ "the update patchCount attribute" + MSG_SHOULD_EQUAL);
+ // XXX TODO - test nsIUpdate:serialize
+
+ Assert.equal(bestUpdate.getProperty("custom1_attr"), "custom1 value",
+ "the update custom1_attr property" + MSG_SHOULD_EQUAL);
+ Assert.equal(bestUpdate.getProperty("custom2_attr"), "custom2 value",
+ "the update custom2_attr property" + MSG_SHOULD_EQUAL);
+
+ let patch = bestUpdate.getPatchAt(0);
+ Assert.equal(patch.type, "complete",
+ "the update patch type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.URL, "http://complete/",
+ "the update patch URL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashFunction, "SHA1",
+ "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashValue, "98db9dad8e1d80eda7e1170d0187d6f53e477059",
+ "the update patch hashValue attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.size, 9856459,
+ "the update patch size attribute" + MSG_SHOULD_EQUAL);
+ // The value for patch.state can be the string 'null' as a valid value. This
+ // is confusing if it returns null which is an invalid value since the test
+ // failure output will show a failure for null == null. To lessen the
+ // confusion first check that the typeof for patch.state is string.
+ Assert.equal(typeof patch.state, "string",
+ "the update patch state typeof value should equal |string|");
+ Assert.equal(patch.state, STATE_NONE,
+ "the update patch state attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!patch.selected,
+ "the update patch selected attribute" + MSG_SHOULD_EQUAL);
+ // XXX TODO - test nsIUpdatePatch:serialize
+
+ patch = bestUpdate.getPatchAt(1);
+ Assert.equal(patch.type, "partial",
+ "the update patch type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.URL, "http://partial/",
+ "the update patch URL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashFunction, "SHA1",
+ "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashValue, "e6678ca40ae7582316acdeddf3c133c9c8577de4",
+ "the update patch hashValue attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.size, 1316138,
+ "the update patch size attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.state, STATE_NONE,
+ "the update patch state attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!patch.selected,
+ "the update patch selected attribute" + MSG_SHOULD_EQUAL);
+ // XXX TODO - test nsIUpdatePatch:serialize
+
+ run_test_pt03();
+}
+
+// Empty update xml (an empty xml file returns a root node name of parsererror)
+function run_test_pt03() {
+ gResponseBody = "<parsererror/>";
+ run_test_helper_pt1("testing empty update xml",
+ null, run_test_pt04);
+}
+
+// no updates available
+function run_test_pt04() {
+ gResponseBody = getRemoteUpdatesXMLString("");
+ run_test_helper_pt1("testing no updates available",
+ 0, run_test_pt05);
+}
+
+// one update available with two patches
+function run_test_pt05() {
+ let patches = getRemotePatchString("complete");
+ patches += getRemotePatchString("partial");
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing one update available",
+ 1, run_test_pt06);
+}
+
+// three updates available each with two patches
+function run_test_pt06() {
+ let patches = getRemotePatchString("complete");
+ patches += getRemotePatchString("partial");
+ let updates = getRemoteUpdateString(patches);
+ updates += getRemoteUpdateString(patches);
+ updates += getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing three updates available",
+ 3, run_test_pt07);
+}
+
+// one update with complete and partial patches with size 0 specified in the
+// update xml
+function run_test_pt07() {
+ let patches = getRemotePatchString("complete", null, null, null, "0");
+ patches += getRemotePatchString("partial", null, null, null, "0");
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing one update with complete and partial " +
+ "patches with size 0", 0, run_test_pt08);
+}
+
+// one update with complete patch with size 0 specified in the update xml
+function run_test_pt08() {
+ let patches = getRemotePatchString("complete", null, null, null, "0");
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing one update with complete patch with size 0",
+ 0, run_test_pt9);
+}
+
+// one update with partial patch with size 0 specified in the update xml
+function run_test_pt9() {
+ let patches = getRemotePatchString("partial", null, null, null, "0");
+ let updates = getRemoteUpdateString(patches);
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing one update with partial patch with size 0",
+ 0, run_test_pt10);
+}
+
+// check that updates for older versions of the application aren't selected
+function run_test_pt10() {
+ let patches = getRemotePatchString("complete");
+ patches += getRemotePatchString("partial");
+ let updates = getRemoteUpdateString(patches, "minor", null, null, "1.0pre");
+ updates += getRemoteUpdateString(patches, "minor", null, null, "1.0a");
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing two updates older than the current version",
+ 2, check_test_pt10);
+}
+
+function check_test_pt10() {
+ let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
+ Assert.ok(!bestUpdate,
+ "there should be no update available");
+ run_test_pt11();
+}
+
+// check that updates for the current version of the application are selected
+function run_test_pt11() {
+ let patches = getRemotePatchString("complete");
+ patches += getRemotePatchString("partial");
+ let updates = getRemoteUpdateString(patches, "minor", null, "version 1.0");
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ run_test_helper_pt1("testing one update equal to the current version",
+ 1, check_test_pt11);
+}
+
+function check_test_pt11() {
+ let bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
+ Assert.ok(!!bestUpdate,
+ "there should be one update available");
+ Assert.equal(bestUpdate.displayVersion, "version 1.0",
+ "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js
new file mode 100644
index 000000000..ee1c40bfd
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiAutoPref.js
@@ -0,0 +1,75 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://testing-common/MockRegistrar.jsm");
+
+const WindowWatcher = {
+ openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) {
+ gCheckFunc();
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher])
+};
+
+const WindowMediator = {
+ getMostRecentWindow: function(aWindowType) {
+ do_execute_soon(check_status);
+ return { getInterface: XPCOMUtils.generateQI([Ci.nsIDOMWindow]) };
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator])
+};
+
+function run_test() {
+ setupTestCommon();
+ // Calling do_get_profile prevents an error from being logged
+ do_get_profile();
+
+ debugDump("testing that an update download doesn't start when the " +
+ PREF_APP_UPDATE_AUTO + " preference is false");
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_AUTO, false);
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
+
+ start_httpserver();
+ setUpdateURL(gURLData + gHTTPHandlerPath);
+ standardInit();
+
+ let windowWatcherCID =
+ MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcher);
+ let windowMediatorCID =
+ MockRegistrar.register("@mozilla.org/appshell/window-mediator;1",
+ WindowMediator);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(windowWatcherCID);
+ MockRegistrar.unregister(windowMediatorCID);
+ });
+
+ gCheckFunc = check_showUpdateAvailable;
+ let patches = getRemotePatchString("complete");
+ let updates = getRemoteUpdateString(patches, "minor", null, null, "1.0");
+ gResponseBody = getRemoteUpdatesXMLString(updates);
+ gAUS.notify(null);
+}
+
+function check_status() {
+ let status = readStatusFile();
+ Assert.notEqual(status, STATE_DOWNLOADING,
+ "the update state" + MSG_SHOULD_EQUAL);
+
+ // Pause the download and reload the Update Manager with an empty update so
+ // the Application Update Service doesn't write the update xml files during
+ // xpcom-shutdown which will leave behind the test directory.
+ gAUS.pauseDownload();
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), true);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ reloadUpdateManagerData();
+
+ do_execute_soon(doTestFinish);
+}
+
+function check_showUpdateAvailable() {
+ do_throw("showUpdateAvailable should not have called openWindow!");
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
new file mode 100644
index 000000000..25110be8c
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://testing-common/MockRegistrar.jsm");
+
+/**
+ * Test that nsIUpdatePrompt doesn't display UI for showUpdateAvailable and
+ * showUpdateError when the app.update.silent preference is true.
+ */
+
+const WindowWatcher = {
+ openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) {
+ gCheckFunc();
+ },
+
+ getNewPrompter: function(aParent) {
+ gCheckFunc();
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher])
+};
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing nsIUpdatePrompt notifications should not be seen " +
+ "when the " + PREF_APP_UPDATE_SILENT + " preference is true");
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
+
+ let windowWatcherCID =
+ MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcher);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(windowWatcherCID);
+ });
+
+ standardInit();
+
+ debugDump("testing showUpdateAvailable should not call openWindow");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
+ let patches = getLocalPatchString(null, null, null, null, null, null,
+ STATE_FAILED);
+ let updates = getLocalUpdateString(patches);
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_FAILED);
+ reloadUpdateManagerData();
+
+ gCheckFunc = check_showUpdateAvailable;
+ let update = gUpdateManager.activeUpdate;
+ gUP.showUpdateAvailable(update);
+ // Report a successful check after the call to showUpdateAvailable since it
+ // didn't throw and otherwise it would report no tests run.
+ Assert.ok(true,
+ "calling showUpdateAvailable should not attempt to open a window");
+
+ debugDump("testing showUpdateError should not call getNewPrompter");
+ gCheckFunc = check_showUpdateError;
+ update.errorCode = WRITE_ERROR;
+ gUP.showUpdateError(update);
+ // Report a successful check after the call to showUpdateError since it
+ // didn't throw and otherwise it would report no tests run.
+ Assert.ok(true,
+ "calling showUpdateError should not attempt to open a window");
+
+ doTestFinish();
+}
+
+function check_showUpdateAvailable() {
+ do_throw("showUpdateAvailable should not have called openWindow!");
+}
+
+function check_showUpdateError() {
+ do_throw("showUpdateError should not have seen getNewPrompter!");
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js
new file mode 100644
index 000000000..5b694ed30
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/uiUnsupportedAlreadyNotified.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Cu.import("resource://testing-common/MockRegistrar.jsm");
+
+const WindowWatcher = {
+ openWindow: function(aParent, aUrl, aName, aFeatures, aArgs) {
+ check_showUpdateAvailable();
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowWatcher])
+};
+
+const WindowMediator = {
+ getMostRecentWindow: function(aWindowType) {
+ return null;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediator])
+};
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing nsIUpdatePrompt notifications should not be displayed " +
+ "when showUpdateAvailable is called for an unsupported system " +
+ "update when the unsupported notification has already been " +
+ "shown (bug 843497)");
+
+ start_httpserver();
+ setUpdateURL(gURLData + gHTTPHandlerPath);
+ standardInit();
+
+ let windowWatcherCID =
+ MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcher);
+ let windowMediatorCID =
+ MockRegistrar.register("@mozilla.org/appshell/window-mediator;1",
+ WindowMediator);
+ do_register_cleanup(() => {
+ MockRegistrar.unregister(windowWatcherCID);
+ MockRegistrar.unregister(windowMediatorCID);
+ });
+
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, false);
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED, true);
+ // This preference is used to determine when the background update check has
+ // completed since a successful check will clear the preference.
+ Services.prefs.setIntPref(PREF_APP_UPDATE_BACKGROUNDERRORS, 1);
+
+ gResponseBody = getRemoteUpdatesXMLString(" <update type=\"major\" " +
+ "name=\"Unsupported Update\" " +
+ "unsupported=\"true\" " +
+ "detailsURL=\"" + URL_HOST +
+ "\"></update>\n");
+ gAUS.notify(null);
+ do_execute_soon(check_test);
+}
+
+function check_test() {
+ if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) {
+ do_execute_soon(check_test);
+ return;
+ }
+ Assert.ok(true,
+ PREF_APP_UPDATE_BACKGROUNDERRORS + " preference should not exist");
+
+ stop_httpserver(doTestFinish);
+}
+
+function check_showUpdateAvailable() {
+ do_throw("showUpdateAvailable should not have called openWindow!");
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
new file mode 100644
index 000000000..e46469455
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateManagerXML.js
@@ -0,0 +1,177 @@
+/* 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/.
+ */
+
+function run_test() {
+ setupTestCommon();
+
+ debugDump("testing addition of a successful update to " + FILE_UPDATES_XML +
+ " and verification of update properties including the format " +
+ "prior to bug 530872");
+
+ setUpdateChannel("test_channel");
+
+ // This test expects that the app.update.download.backgroundInterval
+ // preference doesn't already exist.
+ Services.prefs.deleteBranch("app.update.download.backgroundInterval");
+
+ // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244
+ // and until bug 470244 is fixed this will not test the value for detailsURL
+ // when it isn't specified in the update xml.
+ let patches = getLocalPatchString("partial", "http://partial/", "SHA256",
+ "cd43", "86", "true", STATE_PENDING);
+ let updates = getLocalUpdateString(patches, "major", "New", "version 4",
+ "4.0", "20070811053724",
+ "http://details1/",
+ "http://service1/", "1238441300314",
+ "test status text", "false",
+ "test_channel", "true", "true", "true",
+ "345600", "300", "3.0",
+ "custom1_attr=\"custom1 value\"",
+ "custom2_attr=\"custom2 value\"");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
+ writeStatusFile(STATE_SUCCEEDED);
+
+ patches = getLocalPatchString("complete", "http://complete/", "SHA1", "6232",
+ "75", "true", STATE_FAILED);
+ updates = getLocalUpdateString(patches, "major", "Existing", null, "3.0",
+ null,
+ "http://details2/",
+ "http://service2/", null,
+ getString("patchApplyFailure"), "true",
+ "test_channel", "false", null, null, "691200",
+ null, null,
+ "custom3_attr=\"custom3 value\"",
+ "custom4_attr=\"custom4 value\"");
+ writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), false);
+
+ standardInit();
+
+ Assert.ok(!gUpdateManager.activeUpdate,
+ "the update manager activeUpdate attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(gUpdateManager.updateCount, 2,
+ "the update manager updateCount attribute" + MSG_SHOULD_EQUAL);
+
+ debugDump("checking the activeUpdate properties");
+ let update = gUpdateManager.getUpdateAt(0).QueryInterface(Ci.nsIPropertyBag);
+ Assert.equal(update.state, STATE_SUCCEEDED,
+ "the update state attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.type, "major",
+ "the update type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.name, "New",
+ "the update name attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.displayVersion, "version 4",
+ "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.appVersion, "4.0",
+ "the update appVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.buildID, "20070811053724",
+ "the update buildID attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.detailsURL, "http://details1/",
+ "the update detailsURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.serviceURL, "http://service1/",
+ "the update serviceURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.installDate, "1238441300314",
+ "the update installDate attribute" + MSG_SHOULD_EQUAL);
+ // statusText is updated
+ Assert.equal(update.statusText, getString("installSuccess"),
+ "the update statusText attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!update.isCompleteUpdate,
+ "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.channel, "test_channel",
+ "the update channel attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!!update.showPrompt,
+ "the update showPrompt attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!!update.showNeverForVersion,
+ "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.promptWaitTime, "345600",
+ "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.getProperty("backgroundInterval"), "300",
+ "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.previousAppVersion, "3.0",
+ "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
+ // Custom attributes
+ Assert.equal(update.getProperty("custom1_attr"), "custom1 value",
+ "the update custom1_attr property" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.getProperty("custom2_attr"), "custom2 value",
+ "the update custom2_attr property" + MSG_SHOULD_EQUAL);
+
+ debugDump("checking the activeUpdate patch properties");
+ let patch = update.selectedPatch;
+ Assert.equal(patch.type, "partial",
+ "the update patch type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.URL, "http://partial/",
+ "the update patch URL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashFunction, "SHA256",
+ "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashValue, "cd43",
+ "the update patch hashValue attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.size, "86",
+ "the update patch size attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!!patch.selected,
+ "the update patch selected attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.state, STATE_SUCCEEDED,
+ "the update patch state attribute" + MSG_SHOULD_EQUAL);
+
+ debugDump("checking the first update properties");
+ update = gUpdateManager.getUpdateAt(1).QueryInterface(Ci.nsIPropertyBag);
+ Assert.equal(update.state, STATE_FAILED,
+ "the update state attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.name, "Existing",
+ "the update name attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.type, "major",
+ "the update type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.displayVersion, "3.0",
+ "the update displayVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.appVersion, "3.0",
+ "the update appVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.detailsURL, "http://details2/",
+ "the update detailsURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.serviceURL, "http://service2/",
+ "the update serviceURL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.installDate, "1238441400314",
+ "the update installDate attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.statusText, getString("patchApplyFailure"),
+ "the update statusText attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.buildID, "20080811053724",
+ "the update buildID attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!!update.isCompleteUpdate,
+ "the update isCompleteUpdate attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.channel, "test_channel",
+ "the update channel attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!update.showPrompt,
+ "the update showPrompt attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!update.showNeverForVersion,
+ "the update showNeverForVersion attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.promptWaitTime, "691200",
+ "the update promptWaitTime attribute" + MSG_SHOULD_EQUAL);
+ // The default and maximum value for backgroundInterval is 600
+ Assert.equal(update.getProperty("backgroundInterval"), "600",
+ "the update backgroundInterval attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.previousAppVersion, null,
+ "the update previousAppVersion attribute" + MSG_SHOULD_EQUAL);
+ // Custom attributes
+ Assert.equal(update.getProperty("custom3_attr"), "custom3 value",
+ "the update custom3_attr property" + MSG_SHOULD_EQUAL);
+ Assert.equal(update.getProperty("custom4_attr"), "custom4 value",
+ "the update custom4_attr property" + MSG_SHOULD_EQUAL);
+
+ debugDump("checking the first update patch properties");
+ patch = update.selectedPatch;
+ Assert.equal(patch.type, "complete",
+ "the update patch type attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.URL, "http://complete/",
+ "the update patch URL attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashFunction, "SHA1",
+ "the update patch hashFunction attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.hashValue, "6232",
+ "the update patch hashValue attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.size, "75",
+ "the update patch size attribute" + MSG_SHOULD_EQUAL);
+ Assert.ok(!!patch.selected,
+ "the update patch selected attribute" + MSG_SHOULD_EQUAL);
+ Assert.equal(patch.state, STATE_FAILED,
+ "the update patch state attribute" + MSG_SHOULD_EQUAL);
+
+ doTestFinish();
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js
new file mode 100644
index 000000000..db7d90094
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/urlConstruction.js
@@ -0,0 +1,305 @@
+/* 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/.
+ */
+
+/* General URL Construction Tests */
+
+const URL_PREFIX = URL_HOST + "/";
+
+var gAppInfo;
+
+// Since gUpdateChecker.checkForUpdates uses XMLHttpRequest and XMLHttpRequest
+// can be slow it combines the checks whenever possible.
+function run_test() {
+ // This test needs access to omni.ja to read the update.locale file so don't
+ // use a custom directory for the application directory.
+ gUseTestAppDir = false;
+ setupTestCommon();
+
+ standardInit();
+ gAppInfo = Cc["@mozilla.org/xre/app-info;1"].
+ getService(Ci.nsIXULAppInfo).
+ QueryInterface(Ci.nsIXULRuntime);
+ do_execute_soon(run_test_pt1);
+}
+
+
+// url constructed with:
+// %PRODUCT%
+// %VERSION%
+// %BUILD_ID%
+// %BUILD_TARGET%
+// %LOCALE%
+// %CHANNEL%
+// %PLATFORM_VERSION%
+// %OS_VERSION%
+// %SYSTEM_CAPABILITIES%
+// %DISTRIBUTION%
+// %DISTRIBUTION_VERSION%
+function run_test_pt1() {
+ gCheckFunc = check_test_pt1;
+ // The code that gets the locale accesses the profile which is only available
+ // after calling do_get_profile in xpcshell tests. This prevents an error from
+ // being logged.
+ do_get_profile();
+
+ setUpdateChannel("test_channel");
+ gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro");
+ gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_VERSION, "test_distro_version");
+
+ let url = URL_PREFIX + "%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/" +
+ "%LOCALE%/%CHANNEL%/%PLATFORM_VERSION%/%OS_VERSION%/" +
+ "%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/" +
+ "updates.xml";
+ debugDump("testing url construction - url: " + url);
+ setUpdateURL(url);
+ try {
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+ } catch (e) {
+ debugDump("The following error is most likely due to a missing " +
+ "update.locale file");
+ do_throw(e);
+ }
+}
+
+function check_test_pt1() {
+ let url = URL_PREFIX + gAppInfo.name + "/" + gAppInfo.version + "/" +
+ gAppInfo.appBuildID + "/" + gAppInfo.OS + "_" + getABI() + "/" +
+ INSTALL_LOCALE + "/test_channel/" + gAppInfo.platformVersion + "/" +
+ getOSVersion() + "/" + getSystemCapabilities() +
+ "/test_distro/test_distro_version/updates.xml?force=1";
+ // Log the urls since Assert.equal won't print the entire urls to the log.
+ if (gRequestURL != url) {
+ logTestInfo("expected url: " + url);
+ logTestInfo("returned url: " + gRequestURL);
+ }
+ Assert.equal(gRequestURL, url,
+ "the url" + MSG_SHOULD_EQUAL);
+ run_test_pt2();
+}
+
+// url constructed with:
+// %CHANNEL% with distribution partners
+// %CUSTOM% parameter
+// force param when there already is a param - bug 454357
+function run_test_pt2() {
+ gCheckFunc = check_test_pt2;
+ let url = URL_PREFIX + "%CHANNEL%/updates.xml?custom=%CUSTOM%";
+ debugDump("testing url constructed with %CHANNEL% - " + url);
+ setUpdateURL(url);
+ gDefaultPrefBranch.setCharPref(PREFBRANCH_APP_PARTNER + "test_partner1",
+ "test_partner1");
+ gDefaultPrefBranch.setCharPref(PREFBRANCH_APP_PARTNER + "test_partner2",
+ "test_partner2");
+ Services.prefs.setCharPref("app.update.custom", "custom");
+ gUpdateChecker.checkForUpdates(updateCheckListener, true);
+}
+
+function check_test_pt2() {
+ let url = URL_PREFIX + "test_channel-cck-test_partner1-test_partner2/" +
+ "updates.xml?custom=custom&force=1";
+ Assert.equal(gRequestURL, url,
+ "the url" + MSG_SHOULD_EQUAL);
+ doTestFinish();
+}
+
+function getABI() {
+ let abi;
+ try {
+ abi = gAppInfo.XPCOMABI;
+ } catch (e) {
+ do_throw("nsIXULAppInfo:XPCOMABI not defined\n");
+ }
+
+ if (IS_MACOSX) {
+ // Mac universal build should report a different ABI than either macppc
+ // or mactel. This is necessary since nsUpdateService.js will set the ABI to
+ // Universal-gcc3 for Mac universal builds.
+ let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
+ getService(Ci.nsIMacUtils);
+
+ if (macutils.isUniversalBinary) {
+ abi += "-u-" + macutils.architecturesInBinary;
+ }
+ } else if (IS_WIN) {
+ // Windows build should report the CPU architecture that it's running on.
+ abi += "-" + getProcArchitecture();
+ }
+ return abi;
+}
+
+function getOSVersion() {
+ let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
+ let osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
+
+ if (IS_WIN) {
+ try {
+ let servicePack = getServicePack();
+ osVersion += "." + servicePack;
+ } catch (e) {
+ do_throw("Failure obtaining service pack: " + e);
+ }
+
+ if ("5.0" === sysInfo.getProperty("version")) { // Win2K
+ osVersion += " (unknown)";
+ } else {
+ try {
+ osVersion += " (" + getProcArchitecture() + ")";
+ } catch (e) {
+ do_throw("Failed to obtain processor architecture: " + e);
+ }
+ }
+ }
+
+ if (osVersion) {
+ try {
+ osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
+ } catch (e) {
+ // Not all platforms have a secondary widget library, so an error is
+ // nothing to worry about.
+ }
+ osVersion = encodeURIComponent(osVersion);
+ }
+ return osVersion;
+}
+
+function getServicePack() {
+ // NOTE: This function is a helper function and not a test. Thus,
+ // it uses throw() instead of do_throw(). Any tests that use this function
+ // should catch exceptions thrown in this function and deal with them
+ // appropriately (usually by calling do_throw).
+ const BYTE = ctypes.uint8_t;
+ const WORD = ctypes.uint16_t;
+ const DWORD = ctypes.uint32_t;
+ const WCHAR = ctypes.char16_t;
+ const BOOL = ctypes.int;
+
+ // This structure is described at:
+ // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
+ const SZCSDVERSIONLENGTH = 128;
+ const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
+ [
+ {dwOSVersionInfoSize: DWORD},
+ {dwMajorVersion: DWORD},
+ {dwMinorVersion: DWORD},
+ {dwBuildNumber: DWORD},
+ {dwPlatformId: DWORD},
+ {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
+ {wServicePackMajor: WORD},
+ {wServicePackMinor: WORD},
+ {wSuiteMask: WORD},
+ {wProductType: BYTE},
+ {wReserved: BYTE}
+ ]);
+
+ let kernel32 = ctypes.open("kernel32");
+ try {
+ let GetVersionEx = kernel32.declare("GetVersionExW",
+ ctypes.default_abi,
+ BOOL,
+ OSVERSIONINFOEXW.ptr);
+ let winVer = OSVERSIONINFOEXW();
+ winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
+
+ if (0 === GetVersionEx(winVer.address())) {
+ // Using "throw" instead of "do_throw" (see NOTE above)
+ throw ("Failure in GetVersionEx (returned 0)");
+ }
+
+ return winVer.wServicePackMajor + "." + winVer.wServicePackMinor;
+ } finally {
+ kernel32.close();
+ }
+}
+
+function getProcArchitecture() {
+ // NOTE: This function is a helper function and not a test. Thus,
+ // it uses throw() instead of do_throw(). Any tests that use this function
+ // should catch exceptions thrown in this function and deal with them
+ // appropriately (usually by calling do_throw).
+ const WORD = ctypes.uint16_t;
+ const DWORD = ctypes.uint32_t;
+
+ // This structure is described at:
+ // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
+ const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
+ [
+ {wProcessorArchitecture: WORD},
+ {wReserved: WORD},
+ {dwPageSize: DWORD},
+ {lpMinimumApplicationAddress: ctypes.voidptr_t},
+ {lpMaximumApplicationAddress: ctypes.voidptr_t},
+ {dwActiveProcessorMask: DWORD.ptr},
+ {dwNumberOfProcessors: DWORD},
+ {dwProcessorType: DWORD},
+ {dwAllocationGranularity: DWORD},
+ {wProcessorLevel: WORD},
+ {wProcessorRevision: WORD}
+ ]);
+
+ let kernel32 = ctypes.open("kernel32");
+ try {
+ let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
+ ctypes.default_abi,
+ ctypes.void_t,
+ SYSTEM_INFO.ptr);
+ let sysInfo = SYSTEM_INFO();
+ // Default to unknown
+ sysInfo.wProcessorArchitecture = 0xffff;
+
+ GetNativeSystemInfo(sysInfo.address());
+ switch (sysInfo.wProcessorArchitecture) {
+ case 9:
+ return "x64";
+ case 6:
+ return "IA64";
+ case 0:
+ return "x86";
+ default:
+ // Using "throw" instead of "do_throw" (see NOTE above)
+ throw ("Unknown architecture returned from GetNativeSystemInfo: " + sysInfo.wProcessorArchitecture);
+ }
+ } finally {
+ kernel32.close();
+ }
+}
+
+/**
+ * Provides system capability information for application update though it may
+ * be used by other consumers.
+ */
+function getSystemCapabilities() {
+ if (IS_WIN) {
+ const PF_MMX_INSTRUCTIONS_AVAILABLE = 3; // MMX
+ const PF_XMMI_INSTRUCTIONS_AVAILABLE = 6; // SSE
+ const PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10; // SSE2
+ const PF_SSE3_INSTRUCTIONS_AVAILABLE = 13; // SSE3
+
+ let lib = ctypes.open("kernel32.dll");
+ let IsProcessorFeaturePresent = lib.declare("IsProcessorFeaturePresent",
+ ctypes.winapi_abi,
+ ctypes.int32_t, /* success */
+ ctypes.uint32_t); /* DWORD */
+ let instructionSet = "unknown";
+ try {
+ if (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE)) {
+ instructionSet = "SSE3";
+ } else if (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) {
+ instructionSet = "SSE2";
+ } else if (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) {
+ instructionSet = "SSE";
+ } else if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE)) {
+ instructionSet = "MMX";
+ }
+ } catch (e) {
+ Cu.reportError("Error getting processor instruction set. " +
+ "Exception: " + e);
+ }
+
+ lib.close();
+ return instructionSet;
+ }
+
+ return "NA";
+}
diff --git a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini
new file mode 100644
index 000000000..0d2205046
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini
@@ -0,0 +1,27 @@
+; 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/.
+
+[DEFAULT]
+tags = appupdate
+head = head_update.js
+tail =
+
+[canCheckForAndCanApplyUpdates.js]
+[urlConstruction.js]
+[updateManagerXML.js]
+[remoteUpdateXML.js]
+[downloadAndHashCheckMar.js]
+[cleanupDownloadingForOlderAppVersion.js]
+[cleanupDownloadingForDifferentChannel.js]
+[cleanupDownloadingForSameVersionAndBuildID.js]
+[cleanupDownloadingIncorrectStatus.js]
+[cleanupPendingVersionFileIncorrectStatus.js]
+[cleanupSuccessLogMove.js]
+[cleanupSuccessLogsFIFO.js]
+[downloadInterruptedRecovery.js]
+[downloadResumeForSameAppVersion.js]
+[downloadCompleteAfterPartialFailure.js]
+[uiSilentPref.js]
+[uiUnsupportedAlreadyNotified.js]
+[uiAutoPref.js]