diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /toolkit/mozapps/update/tests/unit_aus_update | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'toolkit/mozapps/update/tests/unit_aus_update')
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] |