diff options
Diffstat (limited to 'toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js')
-rw-r--r-- | toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js | 1403 |
1 files changed, 1403 insertions, 0 deletions
diff --git a/toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js b/toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js new file mode 100644 index 000000000..ff58599bc --- /dev/null +++ b/toolkit/mozapps/webextensions/test/xpcshell/test_bootstrap.js @@ -0,0 +1,1403 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const APP_STARTUP = 1; +const APP_SHUTDOWN = 2; +const ADDON_ENABLE = 3; +const ADDON_DISABLE = 4; +const ADDON_INSTALL = 5; +const ADDON_UNINSTALL = 6; +const ADDON_UPGRADE = 7; +const ADDON_DOWNGRADE = 8; + +const ID1 = "bootstrap1@tests.mozilla.org"; +const ID2 = "bootstrap2@tests.mozilla.org"; + +// This verifies that bootstrappable add-ons can be used without restarts. +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/Promise.jsm"); + +// Enable loading extensions from the user scopes +Services.prefs.setIntPref("extensions.enabledScopes", + AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER); + +BootstrapMonitor.init(); + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + +const profileDir = gProfD.clone(); +profileDir.append("extensions"); +const userExtDir = gProfD.clone(); +userExtDir.append("extensions2"); +userExtDir.append(gAppInfo.ID); +registerDirectory("XREUSysExt", userExtDir.parent); + +Components.utils.import("resource://testing-common/httpd.js"); +var testserver = new HttpServer(); +testserver.start(undefined); +gPort = testserver.identity.primaryPort; + +testserver.registerDirectory("/addons/", do_get_file("addons")); + +function getStartupReason() { + let info = BootstrapMonitor.started.get(ID1); + return info ? info.reason : undefined; +} + +function getShutdownReason() { + let info = BootstrapMonitor.stopped.get(ID1); + return info ? info.reason : undefined; +} + +function getInstallReason() { + let info = BootstrapMonitor.installed.get(ID1); + return info ? info.reason : undefined; +} + +function getUninstallReason() { + let info = BootstrapMonitor.uninstalled.get(ID1); + return info ? info.reason : undefined; +} + +function getStartupOldVersion() { + let info = BootstrapMonitor.started.get(ID1); + return info ? info.data.oldVersion : undefined; +} + +function getShutdownNewVersion() { + let info = BootstrapMonitor.stopped.get(ID1); + return info ? info.data.newVersion : undefined; +} + +function getInstallOldVersion() { + let info = BootstrapMonitor.installed.get(ID1); + return info ? info.data.oldVersion : undefined; +} + +function getUninstallNewVersion() { + let info = BootstrapMonitor.uninstalled.get(ID1); + return info ? info.data.newVersion : undefined; +} + +function do_check_bootstrappedPref(aCallback) { + let data = Services.prefs.getCharPref("extensions.bootstrappedAddons"); + data = JSON.parse(data); + + AddonManager.getAddonsByTypes(["extension"], function(aAddons) { + for (let addon of aAddons) { + if (!addon.id.endsWith("@tests.mozilla.org")) + continue; + if (!addon.isActive) + continue; + if (addon.operationsRequiringRestart != AddonManager.OP_NEEDS_RESTART_NONE) + continue; + + do_check_true(addon.id in data); + let addonData = data[addon.id]; + delete data[addon.id]; + + do_check_eq(addonData.version, addon.version); + do_check_eq(addonData.type, addon.type); + let file = addon.getResourceURI().QueryInterface(Components.interfaces.nsIFileURL).file; + do_check_eq(addonData.descriptor, file.persistentDescriptor); + } + do_check_eq(Object.keys(data).length, 0); + + do_execute_soon(aCallback); + }); +} + + +function run_test() { + do_test_pending(); + + startupManager(); + + do_check_false(gExtensionsJSON.exists()); + + do_check_false(gExtensionsINI.exists()); + + run_test_1(); +} + +// Tests that installing doesn't require a restart +function run_test_1() { + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_1"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "1.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + do_check_neq(install.addon.syncGUID, null); + do_check_true(install.addon.hasResource("install.rdf")); + do_check_true(install.addon.hasResource("bootstrap.js")); + do_check_false(install.addon.hasResource("foo.bar")); + do_check_eq(install.addon.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_INSTALL, 0); + do_check_not_in_crash_annotation(ID1, "1.0"); + + let addon = install.addon; + + BootstrapMonitor.promiseAddonStartup(ID1).then(function() { + do_check_bootstrappedPref(function() { + check_test_1(addon.syncGUID); + }); + }); + + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], function() { + do_check_true(addon.hasResource("install.rdf")); + + // startup should not have been called yet. + BootstrapMonitor.checkAddonNotStarted(ID1); + }); + install.install(); + }); +} + +function check_test_1(installSyncGUID) { + do_check_false(gExtensionsINI.exists()); + + AddonManager.getAllInstalls(function(installs) { + // There should be no active installs now since the install completed and + // doesn't require a restart. + do_check_eq(installs.length, 0); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_neq(b1.syncGUID, null); + do_check_eq(b1.syncGUID, installSyncGUID); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_INSTALL); + do_check_eq(getStartupOldVersion(), undefined); + do_check_true(b1.hasResource("install.rdf")); + do_check_true(b1.hasResource("bootstrap.js")); + do_check_false(b1.hasResource("foo.bar")); + do_check_in_crash_annotation(ID1, "1.0"); + + let dir = do_get_addon_root_uri(profileDir, ID1); + do_check_eq(b1.getResourceURI("bootstrap.js").spec, dir + "bootstrap.js"); + + AddonManager.getAddonsWithOperationsByTypes(null, function(list) { + do_check_eq(list.length, 0); + + do_execute_soon(run_test_2); + }); + }); + }); +} + +// Tests that disabling doesn't require a restart +function run_test_2() { + AddonManager.getAddonByID(ID1, function(b1) { + prepare_test({ + [ID1]: [ + ["onDisabling", false], + "onDisabled" + ] + }); + + do_check_eq(b1.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_DISABLE, 0); + b1.userDisabled = true; + ensure_test_completed(); + + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_true(b1.userDisabled); + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), ADDON_DISABLE); + do_check_eq(getShutdownNewVersion(), undefined); + do_check_not_in_crash_annotation(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, function(newb1) { + do_check_neq(newb1, null); + do_check_eq(newb1.version, "1.0"); + do_check_false(newb1.appDisabled); + do_check_true(newb1.userDisabled); + do_check_false(newb1.isActive); + + do_check_bootstrappedPref(run_test_3); + }); + }); +} + +// Test that restarting doesn't accidentally re-enable +function run_test_3() { + shutdownManager(); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), ADDON_DISABLE); + do_check_eq(getShutdownNewVersion(), undefined); + startupManager(false); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), ADDON_DISABLE); + do_check_eq(getShutdownNewVersion(), undefined); + do_check_not_in_crash_annotation(ID1, "1.0"); + + do_check_false(gExtensionsINI.exists()); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_true(b1.userDisabled); + do_check_false(b1.isActive); + + do_check_bootstrappedPref(run_test_4); + }); +} + +// Tests that enabling doesn't require a restart +function run_test_4() { + AddonManager.getAddonByID(ID1, function(b1) { + prepare_test({ + [ID1]: [ + ["onEnabling", false], + "onEnabled" + ] + }); + + do_check_eq(b1.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_ENABLE, 0); + b1.userDisabled = false; + ensure_test_completed(); + + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_ENABLE); + do_check_eq(getStartupOldVersion(), undefined); + do_check_in_crash_annotation(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, function(newb1) { + do_check_neq(newb1, null); + do_check_eq(newb1.version, "1.0"); + do_check_false(newb1.appDisabled); + do_check_false(newb1.userDisabled); + do_check_true(newb1.isActive); + + do_check_bootstrappedPref(run_test_5); + }); + }); +} + +// Tests that a restart shuts down and restarts the add-on +function run_test_5() { + shutdownManager(); + // By the time we've shut down, the database must have been written + do_check_true(gExtensionsJSON.exists()); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), APP_SHUTDOWN); + do_check_eq(getShutdownNewVersion(), undefined); + do_check_not_in_crash_annotation(ID1, "1.0"); + startupManager(false); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), APP_STARTUP); + do_check_eq(getStartupOldVersion(), undefined); + do_check_in_crash_annotation(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + do_check_false(isExtensionInAddonsList(profileDir, b1.id)); + + do_check_bootstrappedPref(run_test_6); + }); +} + +// Tests that installing an upgrade doesn't require a restart +function run_test_6() { + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_2"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "2.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + + BootstrapMonitor.promiseAddonStartup(ID1).then(check_test_6); + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], function() { + }); + install.install(); + }); +} + +function check_test_6() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "2.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonStarted(ID1, "2.0"); + do_check_eq(getStartupReason(), ADDON_UPGRADE); + do_check_eq(getInstallOldVersion(), 1); + do_check_eq(getStartupOldVersion(), 1); + do_check_eq(getShutdownReason(), ADDON_UPGRADE); + do_check_eq(getShutdownNewVersion(), 2); + do_check_eq(getUninstallNewVersion(), 2); + do_check_not_in_crash_annotation(ID1, "1.0"); + do_check_in_crash_annotation(ID1, "2.0"); + + do_check_bootstrappedPref(run_test_7); + }); +} + +// Tests that uninstalling doesn't require a restart +function run_test_7() { + AddonManager.getAddonByID(ID1, function(b1) { + prepare_test({ + [ID1]: [ + ["onUninstalling", false], + "onUninstalled" + ] + }); + + do_check_eq(b1.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_UNINSTALL, 0); + b1.uninstall(); + + do_check_bootstrappedPref(check_test_7); + }); +} + +function check_test_7() { + ensure_test_completed(); + BootstrapMonitor.checkAddonNotInstalled(ID1); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), ADDON_UNINSTALL); + do_check_eq(getShutdownNewVersion(), undefined); + do_check_not_in_crash_annotation(ID1, "2.0"); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + do_check_eq(b1, null); + + restartManager(); + + AddonManager.getAddonByID(ID1, function(newb1) { + do_check_eq(newb1, null); + + do_check_bootstrappedPref(run_test_8); + }); + })); +} + +// Test that a bootstrapped extension dropped into the profile loads properly +// on startup and doesn't cause an EM restart +function run_test_8() { + shutdownManager(); + + manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir, + ID1); + + startupManager(false); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_INSTALL); + do_check_eq(getStartupOldVersion(), undefined); + do_check_in_crash_annotation(ID1, "1.0"); + + do_check_bootstrappedPref(run_test_9); + }); +} + +// Test that items detected as removed during startup get removed properly +function run_test_9() { + shutdownManager(); + + manuallyUninstall(profileDir, ID1); + BootstrapMonitor.clear(ID1); + + startupManager(false); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_eq(b1, null); + do_check_not_in_crash_annotation(ID1, "1.0"); + + do_check_bootstrappedPref(run_test_10); + }); +} + + +// Tests that installing a downgrade sends the right reason +function run_test_10() { + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_2"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "2.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + do_check_true(install.addon.hasResource("install.rdf")); + do_check_true(install.addon.hasResource("bootstrap.js")); + do_check_false(install.addon.hasResource("foo.bar")); + do_check_not_in_crash_annotation(ID1, "2.0"); + + BootstrapMonitor.promiseAddonStartup(ID1).then(check_test_10_pt1); + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], function() { + do_print("Waiting for startup of bootstrap1_2"); + }); + install.install(); + }); +} + +function check_test_10_pt1() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "2.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonStarted(ID1, "2.0"); + do_check_eq(getStartupReason(), ADDON_INSTALL); + do_check_eq(getStartupOldVersion(), undefined); + do_check_true(b1.hasResource("install.rdf")); + do_check_true(b1.hasResource("bootstrap.js")); + do_check_false(b1.hasResource("foo.bar")); + do_check_in_crash_annotation(ID1, "2.0"); + + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_1"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "1.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + + BootstrapMonitor.promiseAddonStartup(ID1).then(check_test_10_pt2); + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], function() { }); + install.install(); + }); + }); +} + +function check_test_10_pt2() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_DOWNGRADE); + do_check_eq(getInstallOldVersion(), 2); + do_check_eq(getStartupOldVersion(), 2); + do_check_eq(getShutdownReason(), ADDON_DOWNGRADE); + do_check_eq(getShutdownNewVersion(), 1); + do_check_eq(getUninstallNewVersion(), 1); + do_check_in_crash_annotation(ID1, "1.0"); + do_check_not_in_crash_annotation(ID1, "2.0"); + + do_check_bootstrappedPref(run_test_11); + }); +} + +// Tests that uninstalling a disabled add-on still calls the uninstall method +function run_test_11() { + AddonManager.getAddonByID(ID1, function(b1) { + prepare_test({ + [ID1]: [ + ["onDisabling", false], + "onDisabled", + ["onUninstalling", false], + "onUninstalled" + ] + }); + + b1.userDisabled = true; + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_eq(getShutdownReason(), ADDON_DISABLE); + do_check_eq(getShutdownNewVersion(), undefined); + do_check_not_in_crash_annotation(ID1, "1.0"); + + b1.uninstall(); + + check_test_11(); + }); +} + +function check_test_11() { + ensure_test_completed(); + BootstrapMonitor.checkAddonNotInstalled(ID1); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_not_in_crash_annotation(ID1, "1.0"); + + do_check_bootstrappedPref(run_test_12); +} + +// Tests that bootstrapped extensions are correctly loaded even if the app is +// upgraded at the same time +function run_test_12() { + shutdownManager(); + + manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir, + ID1); + + startupManager(true); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_INSTALL); + do_check_eq(getStartupOldVersion(), undefined); + do_check_in_crash_annotation(ID1, "1.0"); + + b1.uninstall(); + do_execute_soon(test_12_restart); + }); +} + +function test_12_restart() { + restartManager(); + do_check_bootstrappedPref(run_test_13); +} + + +// Tests that installing a bootstrapped extension with an invalid application +// entry doesn't call it's startup method +function run_test_13() { + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_3"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "3.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + do_check_not_in_crash_annotation(ID1, "3.0"); + + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], callback_soon(check_test_13)); + install.install(); + }); +} + +function check_test_13() { + AddonManager.getAllInstalls(function(installs) { + // There should be no active installs now since the install completed and + // doesn't require a restart. + do_check_eq(installs.length, 0); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "3.0"); + do_check_true(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "3.0"); // We call install even for disabled add-ons + BootstrapMonitor.checkAddonNotStarted(ID1); // Should not have called startup though + do_check_not_in_crash_annotation(ID1, "3.0"); + + do_execute_soon(test_13_restart); + }); + }); +} + +function test_13_restart() { + restartManager(); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "3.0"); + do_check_true(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "3.0"); // We call install even for disabled add-ons + BootstrapMonitor.checkAddonNotStarted(ID1); // Should not have called startup though + do_check_not_in_crash_annotation(ID1, "3.0"); + + do_check_bootstrappedPref(function() { + b1.uninstall(); + do_execute_soon(run_test_14); + }); + }); +} + +// Tests that a bootstrapped extension with an invalid target application entry +// does not get loaded when detected during startup +function run_test_14() { + restartManager(); + + shutdownManager(); + + manuallyInstall(do_get_addon("test_bootstrap1_3"), profileDir, + ID1); + + startupManager(false); + + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "3.0"); + do_check_true(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "3.0"); // We call install even for disabled add-ons + BootstrapMonitor.checkAddonNotStarted(ID1); // Should not have called startup though + do_check_not_in_crash_annotation(ID1, "3.0"); + + do_check_bootstrappedPref(function() { + b1.uninstall(); + + run_test_15(); + }); + }); +} + +// Tests that upgrading a disabled bootstrapped extension still calls uninstall +// and install but doesn't startup the new version +function run_test_15() { + BootstrapMonitor.promiseAddonStartup(ID1).then(function test_15_after_startup() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + b1.userDisabled = true; + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bootstrap1_2"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + do_check_true(install.addon.userDisabled); + + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], callback_soon(check_test_15)); + install.install(); + }); + }); + }); + installAllFiles([do_get_addon("test_bootstrap1_1")], function test_15_addon_installed() { }); +} + +function check_test_15() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "2.0"); + do_check_false(b1.appDisabled); + do_check_true(b1.userDisabled); + do_check_false(b1.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + do_check_bootstrappedPref(function() { + restartManager(); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1_2) { + do_check_neq(b1_2, null); + do_check_eq(b1_2.version, "2.0"); + do_check_false(b1_2.appDisabled); + do_check_true(b1_2.userDisabled); + do_check_false(b1_2.isActive); + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + b1_2.uninstall(); + + run_test_16(); + })); + }); + }); +} + +// Tests that bootstrapped extensions don't get loaded when in safe mode +function run_test_16() { + BootstrapMonitor.promiseAddonStartup(ID1).then(function test_16_after_startup() { + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + do_check_eq(b1.iconURL, "chrome://foo/skin/icon.png"); + do_check_eq(b1.aboutURL, "chrome://foo/content/about.xul"); + do_check_eq(b1.optionsURL, "chrome://foo/content/options.xul"); + + shutdownManager(); + + // Should have stopped + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + gAppInfo.inSafeMode = true; + startupManager(false); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1_2) { + // Should still be stopped + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + do_check_false(b1_2.isActive); + do_check_eq(b1_2.iconURL, null); + do_check_eq(b1_2.aboutURL, null); + do_check_eq(b1_2.optionsURL, null); + + shutdownManager(); + gAppInfo.inSafeMode = false; + startupManager(false); + + // Should have started + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, function(b1_3) { + b1_3.uninstall(); + + do_execute_soon(run_test_17); + }); + })); + })); + }); + installAllFiles([do_get_addon("test_bootstrap1_1")], function() { }); +} + +// Check that a bootstrapped extension in a non-profile location is loaded +function run_test_17() { + shutdownManager(); + + manuallyInstall(do_get_addon("test_bootstrap1_1"), userExtDir, + ID1); + + startupManager(); + + AddonManager.getAddonByID(ID1, function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + do_check_bootstrappedPref(run_test_18); + }); +} + +// Check that installing a new bootstrapped extension in the profile replaces +// the existing one +function run_test_18() { + BootstrapMonitor.promiseAddonStartup(ID1).then(function test_18_after_startup() { + AddonManager.getAddonByID(ID1, function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonStarted(ID1, "2.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "2.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + do_check_eq(getShutdownReason(), ADDON_UPGRADE); + do_check_eq(getUninstallReason(), ADDON_UPGRADE); + do_check_eq(getInstallReason(), ADDON_UPGRADE); + do_check_eq(getStartupReason(), ADDON_UPGRADE); + + do_check_eq(getShutdownNewVersion(), 2); + do_check_eq(getUninstallNewVersion(), 2); + do_check_eq(getInstallOldVersion(), 1); + do_check_eq(getStartupOldVersion(), 1); + + do_check_bootstrappedPref(run_test_19); + }); + }); + installAllFiles([do_get_addon("test_bootstrap1_2")], function() { }); +} + +// Check that uninstalling the profile version reveals the non-profile one +function run_test_19() { + AddonManager.getAddonByID(ID1, function(b1) { + // The revealed add-on gets activated asynchronously + prepare_test({ + [ID1]: [ + ["onUninstalling", false], + "onUninstalled", + ["onInstalling", false], + "onInstalled" + ] + }, [], check_test_19); + + b1.uninstall(); + }); +} + +function check_test_19() { + AddonManager.getAddonByID(ID1, function(b1) { + // Should have reverted to the older version + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + // TODO these reasons really should be ADDON_DOWNGRADE (bug 607818) + do_check_eq(getShutdownReason(), ADDON_UNINSTALL); + do_check_eq(getUninstallReason(), ADDON_UNINSTALL); + do_check_eq(getInstallReason(), ADDON_INSTALL); + do_check_eq(getStartupReason(), ADDON_INSTALL); + + do_check_eq(getShutdownNewVersion(), undefined); + do_check_eq(getUninstallNewVersion(), undefined); + do_check_eq(getInstallOldVersion(), undefined); + do_check_eq(getStartupOldVersion(), undefined); + + do_check_bootstrappedPref(run_test_20); + }); +} + +// Check that a new profile extension detected at startup replaces the non-profile +// one +function run_test_20() { + shutdownManager(); + + manuallyInstall(do_get_addon("test_bootstrap1_2"), profileDir, + ID1); + + startupManager(); + + AddonManager.getAddonByID(ID1, function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonStarted(ID1, "2.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "2.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + do_check_eq(getShutdownReason(), APP_SHUTDOWN); + do_check_eq(getUninstallReason(), ADDON_UPGRADE); + do_check_eq(getInstallReason(), ADDON_UPGRADE); + do_check_eq(getStartupReason(), APP_STARTUP); + + do_check_eq(getShutdownNewVersion(), undefined); + do_check_eq(getUninstallNewVersion(), 2); + do_check_eq(getInstallOldVersion(), 1); + do_check_eq(getStartupOldVersion(), undefined); + + do_execute_soon(run_test_21); + }); +} + +// Check that a detected removal reveals the non-profile one +function run_test_21() { + shutdownManager(); + + do_check_eq(getShutdownReason(), APP_SHUTDOWN); + do_check_eq(getShutdownNewVersion(), undefined); + + manuallyUninstall(profileDir, ID1); + BootstrapMonitor.clear(ID1); + + startupManager(); + + AddonManager.getAddonByID(ID1, function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + // This won't be set as the bootstrap script was gone so we couldn't + // uninstall it properly + do_check_eq(getUninstallReason(), undefined); + do_check_eq(getUninstallNewVersion(), undefined); + + do_check_eq(getInstallReason(), ADDON_DOWNGRADE); + do_check_eq(getInstallOldVersion(), 2); + + do_check_eq(getStartupReason(), APP_STARTUP); + do_check_eq(getStartupOldVersion(), undefined); + + do_check_bootstrappedPref(function() { + shutdownManager(); + + manuallyUninstall(userExtDir, ID1); + BootstrapMonitor.clear(ID1); + + startupManager(false); + run_test_22(); + }); + }); +} + +// Check that an upgrade from the filesystem is detected and applied correctly +function run_test_22() { + shutdownManager(); + + let file = manuallyInstall(do_get_addon("test_bootstrap1_1"), profileDir, + ID1); + + // Make it look old so changes are detected + setExtensionModifiedTime(file, file.lastModifiedTime - 5000); + + startupManager(); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + + shutdownManager(); + + do_check_eq(getShutdownReason(), APP_SHUTDOWN); + do_check_eq(getShutdownNewVersion(), undefined); + + manuallyUninstall(profileDir, ID1); + BootstrapMonitor.clear(ID1); + manuallyInstall(do_get_addon("test_bootstrap1_2"), profileDir, + ID1); + + startupManager(); + + AddonManager.getAddonByID(ID1, function(b1_2) { + // Should have installed and started + BootstrapMonitor.checkAddonInstalled(ID1, "2.0"); + BootstrapMonitor.checkAddonStarted(ID1, "2.0"); + do_check_neq(b1_2, null); + do_check_eq(b1_2.version, "2.0"); + do_check_true(b1_2.isActive); + do_check_false(b1_2.isSystem); + + // This won't be set as the bootstrap script was gone so we couldn't + // uninstall it properly + do_check_eq(getUninstallReason(), undefined); + do_check_eq(getUninstallNewVersion(), undefined); + + do_check_eq(getInstallReason(), ADDON_UPGRADE); + do_check_eq(getInstallOldVersion(), 1); + do_check_eq(getStartupReason(), APP_STARTUP); + do_check_eq(getStartupOldVersion(), undefined); + + do_check_bootstrappedPref(function() { + b1_2.uninstall(); + + run_test_23(); + }); + }); + })); +} + + +// Tests that installing from a URL doesn't require a restart +function run_test_23() { + prepare_test({ }, [ + "onNewInstall" + ]); + + let url = "http://localhost:" + gPort + "/addons/test_bootstrap1_1.xpi"; + AddonManager.getInstallForURL(url, function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + + prepare_test({ }, [ + "onDownloadStarted", + "onDownloadEnded" + ], function() { + do_check_eq(install.type, "extension"); + do_check_eq(install.version, "1.0"); + do_check_eq(install.name, "Test Bootstrap 1"); + do_check_eq(install.state, AddonManager.STATE_DOWNLOADED); + do_check_true(install.addon.hasResource("install.rdf")); + do_check_true(install.addon.hasResource("bootstrap.js")); + do_check_false(install.addon.hasResource("foo.bar")); + do_check_eq(install.addon.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_INSTALL, 0); + do_check_not_in_crash_annotation(ID1, "1.0"); + + let addon = install.addon; + prepare_test({ + [ID1]: [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], function() { + do_check_true(addon.hasResource("install.rdf")); + do_check_bootstrappedPref(check_test_23); + }); + }); + install.install(); + }, "application/x-xpinstall"); +} + +function check_test_23() { + AddonManager.getAllInstalls(function(installs) { + // There should be no active installs now since the install completed and + // doesn't require a restart. + do_check_eq(installs.length, 0); + + AddonManager.getAddonByID(ID1, function(b1) { + do_execute_soon(function test_23_after_startup() { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.appDisabled); + do_check_false(b1.userDisabled); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + do_check_eq(getStartupReason(), ADDON_INSTALL); + do_check_eq(getStartupOldVersion(), undefined); + do_check_true(b1.hasResource("install.rdf")); + do_check_true(b1.hasResource("bootstrap.js")); + do_check_false(b1.hasResource("foo.bar")); + do_check_in_crash_annotation(ID1, "1.0"); + + let dir = do_get_addon_root_uri(profileDir, ID1); + do_check_eq(b1.getResourceURI("bootstrap.js").spec, dir + "bootstrap.js"); + + AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(list) { + do_check_eq(list.length, 0); + + restartManager(); + AddonManager.getAddonByID(ID1, callback_soon(function(b1_2) { + b1_2.uninstall(); + restartManager(); + + testserver.stop(run_test_24); + })); + })); + }); + }); + }); +} + +// Tests that we recover from a broken preference +function run_test_24() { + do_print("starting 24"); + + Promise.all([BootstrapMonitor.promiseAddonStartup(ID2), + promiseInstallAllFiles([do_get_addon("test_bootstrap1_1"), do_get_addon("test_bootstrap2_1")])]) + .then(function test_24_pref() { + do_print("test 24 got prefs"); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + BootstrapMonitor.checkAddonInstalled(ID2, "1.0"); + BootstrapMonitor.checkAddonStarted(ID2, "1.0"); + + restartManager(); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + BootstrapMonitor.checkAddonInstalled(ID2, "1.0"); + BootstrapMonitor.checkAddonStarted(ID2, "1.0"); + + shutdownManager(); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + BootstrapMonitor.checkAddonInstalled(ID2, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID2); + + // Break the preference + let bootstrappedAddons = JSON.parse(Services.prefs.getCharPref("extensions.bootstrappedAddons")); + bootstrappedAddons[ID1].descriptor += "foo"; + Services.prefs.setCharPref("extensions.bootstrappedAddons", JSON.stringify(bootstrappedAddons)); + + startupManager(false); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + BootstrapMonitor.checkAddonInstalled(ID2, "1.0"); + BootstrapMonitor.checkAddonStarted(ID2, "1.0"); + + run_test_25(); + }); +} + +// Tests that updating from a bootstrappable add-on to a normal add-on calls +// the uninstall method +function run_test_25() { + BootstrapMonitor.promiseAddonStartup(ID1).then(function test_25_after_pref() { + do_print("test 25 pref change detected"); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + installAllFiles([do_get_addon("test_bootstrap1_4")], function() { + // Needs a restart to complete this so the old version stays running + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + do_check_true(hasFlag(b1.pendingOperations, AddonManager.PENDING_UPGRADE)); + + restartManager(); + + BootstrapMonitor.checkAddonNotInstalled(ID1); + do_check_eq(getUninstallReason(), ADDON_UPGRADE); + do_check_eq(getUninstallNewVersion(), 4); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, function(b1_2) { + do_check_neq(b1_2, null); + do_check_eq(b1_2.version, "4.0"); + do_check_true(b1_2.isActive); + do_check_false(b1_2.isSystem); + do_check_eq(b1_2.pendingOperations, AddonManager.PENDING_NONE); + + do_check_bootstrappedPref(run_test_26); + }); + })); + }); + }); + installAllFiles([do_get_addon("test_bootstrap1_1")], function test_25_installed() { + do_print("test 25 install done"); + }); +} + +// Tests that updating from a normal add-on to a bootstrappable add-on calls +// the install method +function run_test_26() { + installAllFiles([do_get_addon("test_bootstrap1_1")], function() { + // Needs a restart to complete this + BootstrapMonitor.checkAddonNotInstalled(ID1); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "4.0"); + do_check_true(b1.isActive); + do_check_false(b1.isSystem); + do_check_true(hasFlag(b1.pendingOperations, AddonManager.PENDING_UPGRADE)); + + restartManager(); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + do_check_eq(getInstallReason(), ADDON_DOWNGRADE); + do_check_eq(getInstallOldVersion(), 4); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + AddonManager.getAddonByID(ID1, function(b1_2) { + do_check_neq(b1_2, null); + do_check_eq(b1_2.version, "1.0"); + do_check_true(b1_2.isActive); + do_check_false(b1_2.isSystem); + do_check_eq(b1_2.pendingOperations, AddonManager.PENDING_NONE); + + do_check_bootstrappedPref(run_test_27); + }); + })); + }); +} + +// Tests that updating from a bootstrappable add-on to a normal add-on while +// disabled calls the uninstall method +function run_test_27() { + AddonManager.getAddonByID(ID1, function(b1) { + do_check_neq(b1, null); + b1.userDisabled = true; + do_check_eq(b1.version, "1.0"); + do_check_false(b1.isActive); + do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + installAllFiles([do_get_addon("test_bootstrap1_4")], function() { + // Updating disabled things happens immediately + BootstrapMonitor.checkAddonNotInstalled(ID1); + do_check_eq(getUninstallReason(), ADDON_UPGRADE); + do_check_eq(getUninstallNewVersion(), 4); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1_2) { + do_check_neq(b1_2, null); + do_check_eq(b1_2.version, "4.0"); + do_check_false(b1_2.isActive); + do_check_eq(b1_2.pendingOperations, AddonManager.PENDING_NONE); + + restartManager(); + + BootstrapMonitor.checkAddonNotInstalled(ID1); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, function(b1_3) { + do_check_neq(b1_3, null); + do_check_eq(b1_3.version, "4.0"); + do_check_false(b1_3.isActive); + do_check_eq(b1_3.pendingOperations, AddonManager.PENDING_NONE); + + do_check_bootstrappedPref(run_test_28); + }); + })); + }); + }); +} + +// Tests that updating from a normal add-on to a bootstrappable add-on when +// disabled calls the install method but not the startup method +function run_test_28() { + installAllFiles([do_get_addon("test_bootstrap1_1")], function() { + do_execute_soon(function bootstrap_disabled_downgrade_check() { + // Doesn't need a restart to complete this + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + do_check_eq(getInstallReason(), ADDON_DOWNGRADE); + do_check_eq(getInstallOldVersion(), 4); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, callback_soon(function(b1) { + do_check_neq(b1, null); + do_check_eq(b1.version, "1.0"); + do_check_false(b1.isActive); + do_check_true(b1.userDisabled); + do_check_eq(b1.pendingOperations, AddonManager.PENDING_NONE); + + restartManager(); + + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonNotStarted(ID1); + + AddonManager.getAddonByID(ID1, function(b1_2) { + do_check_neq(b1_2, null); + do_check_true(b1_2.userDisabled); + b1_2.userDisabled = false; + do_check_eq(b1_2.version, "1.0"); + do_check_true(b1_2.isActive); + do_check_false(b1_2.isSystem); + do_check_eq(b1_2.pendingOperations, AddonManager.PENDING_NONE); + BootstrapMonitor.checkAddonInstalled(ID1, "1.0"); + BootstrapMonitor.checkAddonStarted(ID1, "1.0"); + + do_check_bootstrappedPref(do_test_finished); + }); + })); + }); + }); +} |