diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js new file mode 100644 index 0000000000..c330aaafde --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled_and_onStartup.js @@ -0,0 +1,599 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); + +const { + createAppInfo, + createTempWebExtensionFile, + promiseAddonEvent, + promiseCompleteAllInstalls, + promiseFindAddonUpdates, + promiseRestartManager, + promiseShutdownManager, + promiseStartupManager, +} = AddonTestUtils; + +AddonTestUtils.init(this); + +// Allow for unsigned addons. +AddonTestUtils.overrideCertDB(); + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "42", "42"); + +function background() { + let onInstalledDetails = null; + let onStartupFired = false; + let eventPage = browser.runtime.getManifest().background.persistent === false; + + browser.runtime.onInstalled.addListener(details => { + onInstalledDetails = details; + }); + + browser.runtime.onStartup.addListener(() => { + onStartupFired = true; + }); + + browser.test.onMessage.addListener(message => { + if (message === "get-on-installed-details") { + onInstalledDetails = onInstalledDetails || { fired: false }; + browser.test.sendMessage("on-installed-details", onInstalledDetails); + } else if (message === "did-on-startup-fire") { + browser.test.sendMessage("on-startup-fired", onStartupFired); + } else if (message === "reload-extension") { + browser.runtime.reload(); + } + }); + + browser.runtime.onUpdateAvailable.addListener(details => { + browser.test.sendMessage("reloading"); + browser.runtime.reload(); + }); + + if (eventPage) { + browser.runtime.onSuspend.addListener(() => { + browser.test.sendMessage("suspended"); + }); + // an event we use to restart the background + browser.browserSettings.homepageOverride.onChange.addListener(() => { + browser.test.sendMessage("homepageOverride"); + }); + } +} + +async function expectEvents( + extension, + { + onStartupFired, + onInstalledFired, + onInstalledReason, + onInstalledTemporary, + onInstalledPrevious, + } +) { + extension.sendMessage("get-on-installed-details"); + let details = await extension.awaitMessage("on-installed-details"); + if (onInstalledFired) { + equal( + details.reason, + onInstalledReason, + "runtime.onInstalled fired with the correct reason" + ); + equal( + details.temporary, + onInstalledTemporary, + "runtime.onInstalled fired with the correct temporary flag" + ); + if (onInstalledPrevious) { + equal( + details.previousVersion, + onInstalledPrevious, + "runtime.onInstalled after update with correct previousVersion" + ); + } + } else { + equal( + details.fired, + onInstalledFired, + "runtime.onInstalled should not have fired" + ); + } + + extension.sendMessage("did-on-startup-fire"); + let fired = await extension.awaitMessage("on-startup-fired"); + equal( + fired, + onStartupFired, + `Expected runtime.onStartup to ${onStartupFired ? "" : "not "} fire` + ); +} + +add_task(async function test_should_fire_on_addon_update() { + Preferences.set("extensions.logging.enabled", false); + + await promiseStartupManager(); + + const EXTENSION_ID = + "test_runtime_on_installed_addon_update@tests.mozilla.org"; + + const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; + + // The test extension uses an insecure update url. + Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false); + + const testServer = createHttpServer(); + const port = testServer.identity.primaryPort; + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + update_url: `http://localhost:${port}/test_update.json`, + }, + }, + }, + background, + }); + + testServer.registerPathHandler("/test_update.json", (request, response) => { + response.write(`{ + "addons": { + "${EXTENSION_ID}": { + "updates": [ + { + "version": "2.0", + "update_link": "http://localhost:${port}/addons/test_runtime_on_installed-2.0.xpi" + } + ] + } + } + }`); + }); + + let webExtensionFile = createTempWebExtensionFile({ + manifest: { + version: "2.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + }, + background, + }); + + testServer.registerFile( + "/addons/test_runtime_on_installed-2.0.xpi", + webExtensionFile + ); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "install", + }); + + let addon = await AddonManager.getAddonByID(EXTENSION_ID); + equal(addon.version, "1.0", "The installed addon has the correct version"); + + let update = await promiseFindAddonUpdates(addon); + let install = update.updateAvailable; + + let promiseInstalled = promiseAddonEvent("onInstalled"); + await promiseCompleteAllInstalls([install]); + + await extension.awaitMessage("reloading"); + + let [updated_addon] = await promiseInstalled; + equal( + updated_addon.version, + "2.0", + "The updated addon has the correct version" + ); + + await extension.awaitStartup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "update", + onInstalledPrevious: "1.0", + }); + + await extension.unload(); + + await promiseShutdownManager(); +}); + +add_task(async function test_should_fire_on_browser_update() { + const EXTENSION_ID = + "test_runtime_on_installed_browser_update@tests.mozilla.org"; + + await promiseStartupManager("1"); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "install", + }); + + // Restart the browser. + await promiseRestartManager("1"); + await extension.awaitBackgroundStarted(); + + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: false, + }); + + // Update the browser. + await promiseRestartManager("2"); + await extension.awaitBackgroundStarted(); + + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "browser_update", + }); + + // Restart the browser. + await promiseRestartManager("2"); + await extension.awaitBackgroundStarted(); + + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: false, + }); + + // Update the browser again. + await promiseRestartManager("3"); + await extension.awaitBackgroundStarted(); + + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "browser_update", + }); + + await extension.unload(); + + await promiseShutdownManager(); +}); + +add_task(async function test_should_not_fire_on_reload() { + const EXTENSION_ID = "test_runtime_on_installed_reload@tests.mozilla.org"; + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "install", + }); + + extension.sendMessage("reload-extension"); + extension.setRestarting(); + await extension.awaitStartup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: false, + }); + + await extension.unload(); + await promiseShutdownManager(); +}); + +add_task(async function test_should_not_fire_on_restart() { + const EXTENSION_ID = "test_runtime_on_installed_restart@tests.mozilla.org"; + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledTemporary: false, + onInstalledReason: "install", + }); + + let addon = await AddonManager.getAddonByID(EXTENSION_ID); + await addon.disable(); + await addon.enable(); + await extension.awaitStartup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: false, + }); + + await extension.unload(); + await promiseShutdownManager(); +}); + +add_task(async function test_temporary_installation() { + const EXTENSION_ID = + "test_runtime_on_installed_addon_temporary@tests.mozilla.org"; + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "temporary", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledReason: "install", + onInstalledTemporary: true, + }); + + await extension.unload(); + await promiseShutdownManager(); +}); + +add_task( + { + pref_set: [["extensions.eventPages.enabled", true]], + }, + async function test_runtime_eventpage() { + const EXTENSION_ID = "test_runtime_eventpage@tests.mozilla.org"; + + await promiseStartupManager("1"); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + permissions: ["browserSettings"], + background: { + persistent: false, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledReason: "install", + onInstalledTemporary: false, + }); + + info(`test onInstall does not fire after suspend`); + // we do enough here that idle timeout causes intermittent failure. + // using terminateBackground results in the same code path tested. + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + + Services.prefs.setStringPref( + "browser.startup.homepage", + "http://test.example.com" + ); + await extension.awaitMessage("homepageOverride"); + // onStartup remains persisted, but not primed + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: false, + }); + + info("test onStartup is not primed but background starts automatically"); + await promiseRestartManager(); + // onStartup is a bit special. During APP_STARTUP we do not + // prime this, we just start since it needs to. + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + await extension.awaitBackgroundStarted(); + + info("test expectEvents"); + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: false, + }); + + info("test onInstalled fired during browser update"); + await promiseRestartManager("2"); + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + await extension.awaitBackgroundStarted(); + + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: true, + onInstalledReason: "browser_update", + onInstalledTemporary: false, + }); + + info(`test onStarted does not fire after suspend`); + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + + Services.prefs.setStringPref( + "browser.startup.homepage", + "http://homepage.example.com" + ); + await extension.awaitMessage("homepageOverride"); + // onStartup remains persisted, but not primed + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: false, + }); + + await extension.unload(); + await promiseShutdownManager(); + } +); + +// Verify we don't regress the issue related to runtime.onStartup persistent +// listener being cleared from the startup data as part of priming all listeners +// while terminating the event page on idle timeout (Bug 1796586). +add_task( + { + pref_set: [["extensions.eventPages.enabled", true]], + }, + async function test_runtime_onStartup_eventpage() { + const EXTENSION_ID = "test_eventpage_onStartup@tests.mozilla.org"; + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + version: "1.0", + browser_specific_settings: { + gecko: { + id: EXTENSION_ID, + }, + }, + permissions: ["browserSettings"], + background: { + persistent: false, + }, + }, + background, + }); + + await extension.startup(); + + await expectEvents(extension, { + onStartupFired: false, + onInstalledFired: true, + onInstalledReason: "install", + onInstalledTemporary: false, + }); + + info("Simulated idle timeout"); + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + + // onStartup remains persisted, but not primed + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + info(`test onStartup after restart`); + await promiseRestartManager(); + + // onStartup is a bit special. During APP_STARTUP we do not + // prime this, we just start since it needs to. + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + await extension.awaitBackgroundStarted(); + + info("test expectEvents"); + await expectEvents(extension, { + onStartupFired: true, + onInstalledFired: false, + }); + + extension.terminateBackground(); + await extension.awaitMessage("suspended"); + await promiseExtensionEvent(extension, "shutdown-background-script"); + assertPersistentListeners(extension, "runtime", "onStartup", { + primed: false, + persisted: true, + }); + + await extension.unload(); + await promiseShutdownManager(); + } +); |