author | Rob Wu <rob@robwu.nl> |
Mon, 23 May 2022 12:39:10 +0000 | |
changeset 618537 | d8df5666ec7dab641fc5f321fac71d63229ca867 |
parent 618536 | 4aef479d5406144e414cc6302847b63a1fa8eb1e |
child 618538 | 3fb319df49c63d4dced1dc5b9a823fd36abe8f68 |
push id | 163319 |
push user | rob@robwu.nl |
push date | Mon, 23 May 2022 12:41:36 +0000 |
treeherder | autoland@d8df5666ec7d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mixedpuppy |
bugs | 1752979 |
milestone | 102.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_install_file_change.js @@ -0,0 +1,176 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +"use strict"; + +const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] }); + +// The test extension uses an insecure update url. +Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false); + +/* globals browser */ + +add_task(async function setup() { + await ExtensionTestUtils.startAddonManager(); +}); + +async function createXPIWithID(addonId, version = "1.0") { + let xpiFile = await createTempWebExtensionFile({ + manifest: { + version, + applications: { gecko: { id: addonId } }, + }, + }); + return xpiFile; +} + +const ERROR_PATTERN_INSTALL_FAIL = /Failed to install .+ from .+ to /; +const ERROR_PATTERN_POSTPONE_FAIL = /Failed to postpone install of /; + +async function promiseInstallFail(install, expectedErrorPattern) { + let { messages } = await promiseConsoleOutput(async () => { + await Assert.rejects( + install.install(), + /^Error: Install failed: onInstallFailed$/ + ); + }); + messages = messages.filter(msg => expectedErrorPattern.test(msg.message)); + equal(messages.length, 1, "Expected log messages"); + equal(install.state, AddonManager.STATE_INSTALL_FAILED); + equal(install.error, AddonManager.ERROR_FILE_ACCESS); + equal((await AddonManager.getAllInstalls()).length, 0, "no pending installs"); +} + +add_task(async function test_file_deleted() { + let xpiFile = await createXPIWithID("delete@me"); + let install = await AddonManager.getInstallForFile(xpiFile); + equal(install.state, AddonManager.STATE_DOWNLOADED); + + xpiFile.remove(false); + + await promiseInstallFail(install, ERROR_PATTERN_INSTALL_FAIL); + + equal(await AddonManager.getAddonByID("delete@me"), null); +}); + +add_task(async function test_file_emptied() { + let xpiFile = await createXPIWithID("empty@me"); + let install = await AddonManager.getInstallForFile(xpiFile); + equal(install.state, AddonManager.STATE_DOWNLOADED); + + await IOUtils.write(xpiFile.path, new Uint8Array()); + + await promiseInstallFail(install, ERROR_PATTERN_INSTALL_FAIL); + + equal(await AddonManager.getAddonByID("empty@me"), null); +}); + +add_task(async function test_file_replaced() { + let xpiFile = await createXPIWithID("replace@me"); + let install = await AddonManager.getInstallForFile(xpiFile); + equal(install.state, AddonManager.STATE_DOWNLOADED); + + await IOUtils.copy( + (await createXPIWithID("replace@me", "2")).path, + xpiFile.path + ); + + await promiseInstallFail(install, ERROR_PATTERN_INSTALL_FAIL); + + equal(await AddonManager.getAddonByID("replace@me"), null); +}); + +async function do_test_update_with_file_replaced(wantPostponeTest) { + const ADDON_ID = wantPostponeTest ? "postpone@me" : "update@me"; + function backgroundWithPostpone() { + // The registration of this listener postpones the update. + browser.runtime.onUpdateAvailable.addListener(() => { + browser.test.fail("Unusable update should not call onUpdateAvailable"); + }); + } + await promiseInstallWebExtension({ + manifest: { + version: "1.0", + applications: { + gecko: { + id: ADDON_ID, + update_url: `http://example.com/update-${ADDON_ID}.json`, + }, + }, + }, + background: wantPostponeTest ? backgroundWithPostpone : () => {}, + }); + + server.registerFile( + `/update-${ADDON_ID}.xpi`, + await createTempWebExtensionFile({ + manifest: { + version: "2.0", + applications: { gecko: { id: ADDON_ID } }, + }, + }) + ); + AddonTestUtils.registerJSON(server, `/update-${ADDON_ID}.json`, { + addons: { + [ADDON_ID]: { + updates: [ + { + version: "2.0", + update_link: `http://example.com/update-${ADDON_ID}.xpi`, + }, + ], + }, + }, + }); + + // Setup completed, let's try to verify that file corruption halts the update. + + let addon = await promiseAddonByID(ADDON_ID); + equal(addon.version, "1.0"); + + let update = await promiseFindAddonUpdates( + addon, + AddonManager.UPDATE_WHEN_USER_REQUESTED + ); + let install = update.updateAvailable; + equal(install.version, "2.0"); + equal(install.state, AddonManager.STATE_AVAILABLE); + equal(install.existingAddon, addon); + equal(install.file, null); + + let promptCount = 0; + let didReplaceFile = false; + install.promptHandler = async function() { + ++promptCount; + equal(install.state, AddonManager.STATE_DOWNLOADED); + await IOUtils.copy( + (await createXPIWithID(ADDON_ID, "3")).path, + install.file.path + ); + didReplaceFile = true; + equal(install.state, AddonManager.STATE_DOWNLOADED, "State not changed"); + }; + + if (wantPostponeTest) { + await promiseInstallFail(install, ERROR_PATTERN_POSTPONE_FAIL); + } else { + await promiseInstallFail(install, ERROR_PATTERN_INSTALL_FAIL); + } + + equal(promptCount, 1); + ok(didReplaceFile, "Replaced update with different file"); + + // Now verify that the add-on is still at the old version. + addon = await promiseAddonByID(ADDON_ID); + equal(addon.version, "1.0"); + + await addon.uninstall(); +} + +add_task(async function test_update_and_file_replaced() { + await do_test_update_with_file_replaced(); +}); + +add_task(async function test_update_postponed_and_file_replaced() { + await do_test_update_with_file_replaced(/* wantPostponeTest = */ true); +});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -48,16 +48,17 @@ tags = webextensions [test_getInstallSourceFromHost.js] [test_gmpProvider.js] skip-if = appname != "firefox" || (os == "win" && processor == "aarch64") # bug 1536637 [test_harness.js] [test_hidden.js] [test_install.js] [test_installOrigins.js] [test_install_cancel.js] +[test_install_file_change.js] [test_install_icons.js] [test_installtrigger_schemes.js] [test_installtrigger_deprecation.js] [test_isDebuggable.js] [test_isReady.js] [test_loadManifest_isPrivileged.js] [test_locale.js] [test_moved_extension_metadata.js]