diff options
Diffstat (limited to 'toolkit/mozapps/extensions/test/browser/head.js')
-rw-r--r-- | toolkit/mozapps/extensions/test/browser/head.js | 1468 |
1 files changed, 0 insertions, 1468 deletions
diff --git a/toolkit/mozapps/extensions/test/browser/head.js b/toolkit/mozapps/extensions/test/browser/head.js deleted file mode 100644 index 5a749099d..000000000 --- a/toolkit/mozapps/extensions/test/browser/head.js +++ /dev/null @@ -1,1468 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -/* globals end_test*/ - -Components.utils.import("resource://gre/modules/NetUtil.jsm"); - -var tmp = {}; -Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp); -Components.utils.import("resource://gre/modules/Log.jsm", tmp); -var AddonManager = tmp.AddonManager; -var AddonManagerPrivate = tmp.AddonManagerPrivate; -var Log = tmp.Log; - -var pathParts = gTestPath.split("/"); -// Drop the test filename -pathParts.splice(pathParts.length - 1, pathParts.length); - -var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]); - -// Drop the UI type -if (gTestInWindow) { - pathParts.splice(pathParts.length - 1, pathParts.length); -} - -const RELATIVE_DIR = pathParts.slice(4).join("/") + "/"; - -const TESTROOT = "http://example.com/" + RELATIVE_DIR; -const SECURE_TESTROOT = "https://example.com/" + RELATIVE_DIR; -const TESTROOT2 = "http://example.org/" + RELATIVE_DIR; -const SECURE_TESTROOT2 = "https://example.org/" + RELATIVE_DIR; -const CHROMEROOT = pathParts.join("/") + "/"; -const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; -const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; -const PREF_XPI_ENABLED = "xpinstall.enabled"; -const PREF_UPDATEURL = "extensions.update.url"; -const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; -const PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI = "xpinstall.customConfirmationUI"; -const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory"; - -const MANAGER_URI = "about:addons"; -const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; -const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; -const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults"; -const PREF_STRICT_COMPAT = "extensions.strictCompatibility"; - -var PREF_CHECK_COMPATIBILITY; -(function() { - var channel = "default"; - try { - channel = Services.prefs.getCharPref("app.update.channel"); - } catch (e) { } - if (channel != "aurora" && - channel != "beta" && - channel != "release" && - channel != "esr") { - var version = "nightly"; - } else { - version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1"); - } - PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version; -})(); - -var gPendingTests = []; -var gTestsRun = 0; -var gTestStart = null; - -var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window); - -var gRestorePrefs = [{name: PREF_LOGGING_ENABLED}, - {name: PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI}, - {name: "extensions.webservice.discoverURL"}, - {name: "extensions.update.url"}, - {name: "extensions.update.background.url"}, - {name: "extensions.update.enabled"}, - {name: "extensions.update.autoUpdateDefault"}, - {name: "extensions.getAddons.get.url"}, - {name: "extensions.getAddons.getWithPerformance.url"}, - {name: "extensions.getAddons.search.browseURL"}, - {name: "extensions.getAddons.search.url"}, - {name: "extensions.getAddons.cache.enabled"}, - {name: "devtools.chrome.enabled"}, - {name: PREF_SEARCH_MAXRESULTS}, - {name: PREF_STRICT_COMPAT}, - {name: PREF_CHECK_COMPATIBILITY}]; - -for (let pref of gRestorePrefs) { - if (!Services.prefs.prefHasUserValue(pref.name)) { - pref.type = "clear"; - continue; - } - pref.type = Services.prefs.getPrefType(pref.name); - if (pref.type == Services.prefs.PREF_BOOL) - pref.value = Services.prefs.getBoolPref(pref.name); - else if (pref.type == Services.prefs.PREF_INT) - pref.value = Services.prefs.getIntPref(pref.name); - else if (pref.type == Services.prefs.PREF_STRING) - pref.value = Services.prefs.getCharPref(pref.name); -} - -// Turn logging on for all tests -Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); - -Services.prefs.setBoolPref(PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI, false); - -// Helper to register test failures and close windows if any are left open -function checkOpenWindows(aWindowID) { - let windows = Services.wm.getEnumerator(aWindowID); - let found = false; - while (windows.hasMoreElements()) { - let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); - if (!win.closed) { - found = true; - win.close(); - } - } - if (found) - ok(false, "Found unexpected " + aWindowID + " window still open"); -} - -// Tools to disable and re-enable the background update and blocklist timers -// so that tests can protect themselves from unwanted timer events. -var gCatMan = Components.classes["@mozilla.org/categorymanager;1"] - .getService(Components.interfaces.nsICategoryManager); -// Default values from toolkit/mozapps/extensions/extensions.manifest, but disable*UpdateTimer() -// records the actual value so we can put it back in enable*UpdateTimer() -var backgroundUpdateConfig = "@mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400"; -var blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400"; - -var UTIMER = "update-timer"; -var AMANAGER = "addonManager"; -var BLOCKLIST = "nsBlocklistService"; - -function disableBackgroundUpdateTimer() { - info("Disabling " + UTIMER + " " + AMANAGER); - backgroundUpdateConfig = gCatMan.getCategoryEntry(UTIMER, AMANAGER); - gCatMan.deleteCategoryEntry(UTIMER, AMANAGER, true); -} - -function enableBackgroundUpdateTimer() { - info("Enabling " + UTIMER + " " + AMANAGER); - gCatMan.addCategoryEntry(UTIMER, AMANAGER, backgroundUpdateConfig, false, true); -} - -function disableBlocklistUpdateTimer() { - info("Disabling " + UTIMER + " " + BLOCKLIST); - blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST); - gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true); -} - -function enableBlocklistUpdateTimer() { - info("Enabling " + UTIMER + " " + BLOCKLIST); - gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true); -} - -registerCleanupFunction(function() { - // Restore prefs - for (let pref of gRestorePrefs) { - if (pref.type == "clear") - Services.prefs.clearUserPref(pref.name); - else if (pref.type == Services.prefs.PREF_BOOL) - Services.prefs.setBoolPref(pref.name, pref.value); - else if (pref.type == Services.prefs.PREF_INT) - Services.prefs.setIntPref(pref.name, pref.value); - else if (pref.type == Services.prefs.PREF_STRING) - Services.prefs.setCharPref(pref.name, pref.value); - } - - // Throw an error if the add-ons manager window is open anywhere - checkOpenWindows("Addons:Manager"); - checkOpenWindows("Addons:Compatibility"); - checkOpenWindows("Addons:Install"); - - return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve)) - .then(aInstalls => { - for (let install of aInstalls) { - if (install instanceof MockInstall) - continue; - - ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state); - install.cancel(); - } - }); -}); - -function log_exceptions(aCallback, ...aArgs) { - try { - return aCallback.apply(null, aArgs); - } - catch (e) { - info("Exception thrown: " + e); - throw e; - } -} - -function log_callback(aPromise, aCallback) { - aPromise.then(aCallback) - .then(null, e => info("Exception thrown: " + e)); - return aPromise; -} - -function add_test(test) { - gPendingTests.push(test); -} - -function run_next_test() { - // Make sure we're not calling run_next_test from inside an add_task() test - // We're inside the browser_test.js 'testScope' here - if (this.__tasks) { - throw new Error("run_next_test() called from an add_task() test function. " + - "run_next_test() should not be called from inside add_task() " + - "under any circumstances!"); - } - if (gTestsRun > 0) - info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms"); - - if (gPendingTests.length == 0) { - executeSoon(end_test); - return; - } - - gTestsRun++; - var test = gPendingTests.shift(); - if (test.name) - info("Running test " + gTestsRun + " (" + test.name + ")"); - else - info("Running test " + gTestsRun); - - gTestStart = Date.now(); - executeSoon(() => log_exceptions(test)); -} - -var get_tooltip_info = Task.async(function*(addon) { - let managerWindow = addon.ownerDocument.defaultView; - - // The popup code uses a triggering event's target to set the - // document.tooltipNode property. - let nameNode = addon.ownerDocument.getAnonymousElementByAttribute(addon, "anonid", "name"); - let event = new managerWindow.CustomEvent("TriggerEvent"); - nameNode.dispatchEvent(event); - - let tooltip = managerWindow.document.getElementById("addonitem-tooltip"); - - let promise = BrowserTestUtils.waitForEvent(tooltip, "popupshown"); - tooltip.openPopup(nameNode, "after_start", 0, 0, false, false, event); - yield promise; - - let tiptext = tooltip.label; - - promise = BrowserTestUtils.waitForEvent(tooltip, "popuphidden"); - tooltip.hidePopup(); - yield promise; - - let expectedName = addon.getAttribute("name"); - ok(tiptext.substring(0, expectedName.length), expectedName, - "Tooltip should always start with the expected name"); - - if (expectedName.length == tiptext.length) { - return { - name: tiptext, - version: undefined - }; - } - return { - name: tiptext.substring(0, expectedName.length), - version: tiptext.substring(expectedName.length + 1) - }; -}); - -function get_addon_file_url(aFilename) { - try { - var cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIChromeRegistry); - var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename)); - return fileurl.QueryInterface(Ci.nsIFileURL); - } catch (ex) { - var jar = getJar(CHROMEROOT + "addons/" + aFilename); - var tmpDir = extractJarToTmp(jar); - tmpDir.append(aFilename); - - return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL); - } -} - -function get_current_view(aManager) { - let view = aManager.document.getElementById("view-port").selectedPanel; - if (view.id == "headered-views") { - view = aManager.document.getElementById("headered-views-content").selectedPanel; - } - is(view, aManager.gViewController.displayedView, "view controller is tracking the displayed view correctly"); - return view; -} - -function get_test_items_in_list(aManager) { - var tests = "@tests.mozilla.org"; - - let view = get_current_view(aManager); - let listid = view.id == "search-view" ? "search-list" : "addon-list"; - let item = aManager.document.getElementById(listid).firstChild; - let items = []; - - while (item) { - if (item.localName != "richlistitem") { - item = item.nextSibling; - continue; - } - - if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests) - items.push(item); - item = item.nextSibling; - } - - return items; -} - -function check_all_in_list(aManager, aIds, aIgnoreExtras) { - var doc = aManager.document; - var view = get_current_view(aManager); - var listid = view.id == "search-view" ? "search-list" : "addon-list"; - var list = doc.getElementById(listid); - - var inlist = []; - var node = list.firstChild; - while (node) { - if (node.value) - inlist.push(node.value); - node = node.nextSibling; - } - - for (let id of aIds) { - if (inlist.indexOf(id) == -1) - ok(false, "Should find " + id + " in the list"); - } - - if (aIgnoreExtras) - return; - - for (let inlistItem of inlist) { - if (aIds.indexOf(inlistItem) == -1) - ok(false, "Shouldn't have seen " + inlistItem + " in the list"); - } -} - -function get_addon_element(aManager, aId) { - var doc = aManager.document; - var view = get_current_view(aManager); - var listid = "addon-list"; - if (view.id == "search-view") - listid = "search-list"; - else if (view.id == "updates-view") - listid = "updates-list"; - var list = doc.getElementById(listid); - - var node = list.firstChild; - while (node) { - if (node.value == aId) - return node; - node = node.nextSibling; - } - return null; -} - -function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) { - requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); - - if (!aForceWait && !aManagerWindow.gViewController.isLoading) { - log_exceptions(aCallback, aManagerWindow); - return; - } - - aManagerWindow.document.addEventListener("ViewChanged", function() { - aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false); - log_exceptions(aCallback, aManagerWindow); - }, false); -} - -function wait_for_manager_load(aManagerWindow, aCallback) { - if (!aManagerWindow.gIsInitializing) { - log_exceptions(aCallback, aManagerWindow); - return; - } - - info("Waiting for initialization"); - aManagerWindow.document.addEventListener("Initialized", function() { - aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false); - log_exceptions(aCallback, aManagerWindow); - }, false); -} - -function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) { - let p = new Promise((resolve, reject) => { - - function setup_manager(aManagerWindow) { - if (aLoadCallback) - log_exceptions(aLoadCallback, aManagerWindow); - - if (aView) - aManagerWindow.loadView(aView); - - ok(aManagerWindow != null, "Should have an add-ons manager window"); - is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI"); - - waitForFocus(function() { - info("window has focus, waiting for manager load"); - wait_for_manager_load(aManagerWindow, function() { - info("Manager waiting for view load"); - wait_for_view_load(aManagerWindow, function() { - resolve(aManagerWindow); - }, null, aLongerTimeout); - }); - }, aManagerWindow); - } - - if (gUseInContentUI) { - info("Loading manager window in tab"); - Services.obs.addObserver(function (aSubject, aTopic, aData) { - Services.obs.removeObserver(arguments.callee, aTopic); - if (aSubject.location.href != MANAGER_URI) { - info("Ignoring load event for " + aSubject.location.href); - return; - } - setup_manager(aSubject); - }, "EM-loaded", false); - - gBrowser.selectedTab = gBrowser.addTab(); - switchToTabHavingURI(MANAGER_URI, true); - } else { - info("Loading manager window in dialog"); - Services.obs.addObserver(function (aSubject, aTopic, aData) { - Services.obs.removeObserver(arguments.callee, aTopic); - setup_manager(aSubject); - }, "EM-loaded", false); - - openDialog(MANAGER_URI); - } - }); - - // The promise resolves with the manager window, so it is passed to the callback - return log_callback(p, aCallback); -} - -function close_manager(aManagerWindow, aCallback, aLongerTimeout) { - let p = new Promise((resolve, reject) => { - requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); - - ok(aManagerWindow != null, "Should have an add-ons manager window to close"); - is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI"); - - aManagerWindow.addEventListener("unload", function() { - try { - dump("Manager window unload handler\n"); - this.removeEventListener("unload", arguments.callee, false); - resolve(); - } catch (e) { - reject(e); - } - }, false); - }); - - info("Telling manager window to close"); - aManagerWindow.close(); - info("Manager window close() call returned"); - - return log_callback(p, aCallback); -} - -function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) { - if (!aManagerWindow) { - return open_manager(aView, aCallback, aLoadCallback); - } - - return close_manager(aManagerWindow) - .then(() => open_manager(aView, aCallback, aLoadCallback)); -} - -function wait_for_window_open(aCallback) { - Services.wm.addListener({ - onOpenWindow: function(aWindow) { - Services.wm.removeListener(this); - - let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - domwindow.addEventListener("load", function() { - domwindow.removeEventListener("load", arguments.callee, false); - executeSoon(function() { - aCallback(domwindow); - }); - }, false); - }, - - onCloseWindow: function(aWindow) { - }, - - onWindowTitleChange: function(aWindow, aTitle) { - } - }); -} - -function get_string(aName, ...aArgs) { - var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); - if (aArgs.length == 0) - return bundle.GetStringFromName(aName); - return bundle.formatStringFromName(aName, aArgs, aArgs.length); -} - -function formatDate(aDate) { - const locale = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry) - .getSelectedLocale("global", true); - const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' }; - return aDate.toLocaleDateString(locale, dtOptions); -} - -function is_hidden(aElement) { - var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, ""); - if (style.display == "none") - return true; - if (style.visibility != "visible") - return true; - - // Hiding a parent element will hide all its children - if (aElement.parentNode != aElement.ownerDocument) - return is_hidden(aElement.parentNode); - - return false; -} - -function is_element_visible(aElement, aMsg) { - isnot(aElement, null, "Element should not be null, when checking visibility"); - ok(!is_hidden(aElement), aMsg || (aElement + " should be visible")); -} - -function is_element_hidden(aElement, aMsg) { - isnot(aElement, null, "Element should not be null, when checking visibility"); - ok(is_hidden(aElement), aMsg || (aElement + " should be hidden")); -} - -function promiseAddonByID(aId) { - return new Promise(resolve => { - AddonManager.getAddonByID(aId, resolve); - }); -} - -function promiseAddonsByIDs(aIDs) { - return new Promise(resolve => { - AddonManager.getAddonsByIDs(aIDs, resolve); - }); -} -/** - * Install an add-on and call a callback when complete. - * - * The callback will receive the Addon for the installed add-on. - */ -function install_addon(path, cb, pathPrefix=TESTROOT) { - let p = new Promise((resolve, reject) => { - AddonManager.getInstallForURL(pathPrefix + path, (install) => { - install.addListener({ - onInstallEnded: () => resolve(install.addon), - }); - - install.install(); - }, "application/x-xpinstall"); - }); - - return log_callback(p, cb); -} - -function CategoryUtilities(aManagerWindow) { - this.window = aManagerWindow; - - var self = this; - this.window.addEventListener("unload", function() { - self.window.removeEventListener("unload", arguments.callee, false); - self.window = null; - }, false); -} - -CategoryUtilities.prototype = { - window: null, - - get selectedCategory() { - isnot(this.window, null, "Should not get selected category when manager window is not loaded"); - var selectedItem = this.window.document.getElementById("categories").selectedItem; - isnot(selectedItem, null, "A category should be selected"); - var view = this.window.gViewController.parseViewId(selectedItem.value); - return (view.type == "list") ? view.param : view.type; - }, - - get: function(aCategoryType, aAllowMissing) { - isnot(this.window, null, "Should not get category when manager window is not loaded"); - var categories = this.window.document.getElementById("categories"); - - var viewId = "addons://list/" + aCategoryType; - var items = categories.getElementsByAttribute("value", viewId); - if (items.length) - return items[0]; - - viewId = "addons://" + aCategoryType + "/"; - items = categories.getElementsByAttribute("value", viewId); - if (items.length) - return items[0]; - - if (!aAllowMissing) - ok(false, "Should have found a category with type " + aCategoryType); - return null; - }, - - getViewId: function(aCategoryType) { - isnot(this.window, null, "Should not get view id when manager window is not loaded"); - return this.get(aCategoryType).value; - }, - - isVisible: function(aCategory) { - isnot(this.window, null, "Should not check visible state when manager window is not loaded"); - if (aCategory.hasAttribute("disabled") && - aCategory.getAttribute("disabled") == "true") - return false; - - return !is_hidden(aCategory); - }, - - isTypeVisible: function(aCategoryType) { - return this.isVisible(this.get(aCategoryType)); - }, - - open: function(aCategory, aCallback) { - - isnot(this.window, null, "Should not open category when manager window is not loaded"); - ok(this.isVisible(aCategory), "Category should be visible if attempting to open it"); - - EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window); - let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve)); - - return log_callback(p, aCallback); - }, - - openType: function(aCategoryType, aCallback) { - return this.open(this.get(aCategoryType), aCallback); - } -} - -function CertOverrideListener(host, bits) { - this.host = host; - this.bits = bits; -} - -CertOverrideListener.prototype = { - host: null, - bits: null, - - getInterface: function (aIID) { - return this.QueryInterface(aIID); - }, - - QueryInterface: function(aIID) { - if (aIID.equals(Ci.nsIBadCertListener2) || - aIID.equals(Ci.nsIInterfaceRequestor) || - aIID.equals(Ci.nsISupports)) - return this; - - throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); - }, - - notifyCertProblem: function (socketInfo, sslStatus, targetHost) { - var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus) - .serverCert; - var cos = Cc["@mozilla.org/security/certoverride;1"]. - getService(Ci.nsICertOverrideService); - cos.rememberValidityOverride(this.host, -1, cert, this.bits, false); - return true; - } -} - -// Add overrides for the bad certificates -function addCertOverride(host, bits) { - var req = new XMLHttpRequest(); - try { - req.open("GET", "https://" + host + "/", false); - req.channel.notificationCallbacks = new CertOverrideListener(host, bits); - req.send(null); - } - catch (e) { - // This request will fail since the SSL server is not trusted yet - } -} - -/** *** Mock Provider *****/ - -function MockProvider(aUseAsyncCallbacks, aTypes) { - this.addons = []; - this.installs = []; - this.callbackTimers = []; - this.timerLocations = new Map(); - this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks; - this.types = (aTypes === undefined) ? [{ - id: "extension", - name: "Extensions", - uiPriority: 4000, - flags: AddonManager.TYPE_UI_VIEW_LIST | - AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL, - }] : aTypes; - - var self = this; - registerCleanupFunction(function() { - if (self.started) - self.unregister(); - }); - - this.register(); -} - -MockProvider.prototype = { - addons: null, - installs: null, - started: null, - apiDelay: 10, - callbackTimers: null, - timerLocations: null, - useAsyncCallbacks: null, - types: null, - - /** *** Utility functions *****/ - - /** - * Register this provider with the AddonManager - */ - register: function MP_register() { - info("Registering mock add-on provider"); - AddonManagerPrivate.registerProvider(this, this.types); - }, - - /** - * Unregister this provider with the AddonManager - */ - unregister: function MP_unregister() { - info("Unregistering mock add-on provider"); - AddonManagerPrivate.unregisterProvider(this); - }, - - /** - * Adds an add-on to the list of add-ons that this provider exposes to the - * AddonManager, dispatching appropriate events in the process. - * - * @param aAddon - * The add-on to add - */ - addAddon: function MP_addAddon(aAddon) { - var oldAddons = this.addons.filter(aOldAddon => aOldAddon.id == aAddon.id); - var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null; - - this.addons = this.addons.filter(aOldAddon => aOldAddon.id != aAddon.id); - - this.addons.push(aAddon); - aAddon._provider = this; - - if (!this.started) - return; - - let requiresRestart = (aAddon.operationsRequiringRestart & - AddonManager.OP_NEEDS_RESTART_INSTALL) != 0; - AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon, - oldAddon, requiresRestart) - }, - - /** - * Removes an add-on from the list of add-ons that this provider exposes to - * the AddonManager, dispatching the onUninstalled event in the process. - * - * @param aAddon - * The add-on to add - */ - removeAddon: function MP_removeAddon(aAddon) { - var pos = this.addons.indexOf(aAddon); - if (pos == -1) { - ok(false, "Tried to remove an add-on that wasn't registered with the mock provider"); - return; - } - - this.addons.splice(pos, 1); - - if (!this.started) - return; - - AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon); - }, - - /** - * Adds an add-on install to the list of installs that this provider exposes - * to the AddonManager, dispatching appropriate events in the process. - * - * @param aInstall - * The add-on install to add - */ - addInstall: function MP_addInstall(aInstall) { - this.installs.push(aInstall); - aInstall._provider = this; - - if (!this.started) - return; - - aInstall.callListeners("onNewInstall"); - }, - - removeInstall: function MP_removeInstall(aInstall) { - var pos = this.installs.indexOf(aInstall); - if (pos == -1) { - ok(false, "Tried to remove an install that wasn't registered with the mock provider"); - return; - } - - this.installs.splice(pos, 1); - }, - - /** - * Creates a set of mock add-on objects and adds them to the list of add-ons - * managed by this provider. - * - * @param aAddonProperties - * An array of objects containing properties describing the add-ons - * @return Array of the new MockAddons - */ - createAddons: function MP_createAddons(aAddonProperties) { - var newAddons = []; - for (let addonProp of aAddonProperties) { - let addon = new MockAddon(addonProp.id); - for (let prop in addonProp) { - if (prop == "id") - continue; - if (prop == "applyBackgroundUpdates") { - addon._applyBackgroundUpdates = addonProp[prop]; - continue; - } - if (prop == "appDisabled") { - addon._appDisabled = addonProp[prop]; - continue; - } - addon[prop] = addonProp[prop]; - } - if (!addon.optionsType && !!addon.optionsURL) - addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG; - - // Make sure the active state matches the passed in properties - addon.isActive = addon.shouldBeActive; - - this.addAddon(addon); - newAddons.push(addon); - } - - return newAddons; - }, - - /** - * Creates a set of mock add-on install objects and adds them to the list - * of installs managed by this provider. - * - * @param aInstallProperties - * An array of objects containing properties describing the installs - * @return Array of the new MockInstalls - */ - createInstalls: function MP_createInstalls(aInstallProperties) { - var newInstalls = []; - for (let installProp of aInstallProperties) { - let install = new MockInstall(installProp.name || null, - installProp.type || null, - null); - for (let prop in installProp) { - switch (prop) { - case "name": - case "type": - break; - case "sourceURI": - install[prop] = NetUtil.newURI(installProp[prop]); - break; - default: - install[prop] = installProp[prop]; - } - } - this.addInstall(install); - newInstalls.push(install); - } - - return newInstalls; - }, - - /** *** AddonProvider implementation *****/ - - /** - * Called to initialize the provider. - */ - startup: function MP_startup() { - this.started = true; - }, - - /** - * Called when the provider should shutdown. - */ - shutdown: function MP_shutdown() { - if (this.callbackTimers.length) { - info("MockProvider: pending callbacks at shutdown(): calling immediately"); - } - while (this.callbackTimers.length > 0) { - // When we notify the callback timer, it removes itself from our array - let timer = this.callbackTimers[0]; - try { - let setAt = this.timerLocations.get(timer); - info("Notifying timer set at " + (setAt || "unknown location")); - timer.callback.notify(timer); - timer.cancel(); - } catch (e) { - info("Timer notify failed: " + e); - } - } - this.callbackTimers = []; - this.timerLocations = null; - - this.started = false; - }, - - /** - * Called to get an Addon with a particular ID. - * - * @param aId - * The ID of the add-on to retrieve - * @param aCallback - * A callback to pass the Addon to - */ - getAddonByID: function MP_getAddon(aId, aCallback) { - for (let addon of this.addons) { - if (addon.id == aId) { - this._delayCallback(aCallback, addon); - return; - } - } - - aCallback(null); - }, - - /** - * Called to get Addons of a particular type. - * - * @param aTypes - * An array of types to fetch. Can be null to get all types. - * @param callback - * A callback to pass an array of Addons to - */ - getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) { - var addons = this.addons.filter(function(aAddon) { - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) - return false; - return true; - }); - this._delayCallback(aCallback, addons); - }, - - /** - * Called to get Addons that have pending operations. - * - * @param aTypes - * An array of types to fetch. Can be null to get all types - * @param aCallback - * A callback to pass an array of Addons to - */ - getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) { - var addons = this.addons.filter(function(aAddon) { - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) - return false; - return aAddon.pendingOperations != 0; - }); - this._delayCallback(aCallback, addons); - }, - - /** - * Called to get the current AddonInstalls, optionally restricting by type. - * - * @param aTypes - * An array of types or null to get all types - * @param aCallback - * A callback to pass the array of AddonInstalls to - */ - getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) { - var installs = this.installs.filter(function(aInstall) { - // Appear to have actually removed cancelled installs from the provider - if (aInstall.state == AddonManager.STATE_CANCELLED) - return false; - - if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1) - return false; - - return true; - }); - this._delayCallback(aCallback, installs); - }, - - /** - * Called when a new add-on has been enabled when only one add-on of that type - * can be enabled. - * - * @param aId - * The ID of the newly enabled add-on - * @param aType - * The type of the newly enabled add-on - * @param aPendingRestart - * true if the newly enabled add-on will only become enabled after a - * restart - */ - addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { - // Not implemented - }, - - /** - * Update the appDisabled property for all add-ons. - */ - updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() { - // Not needed - }, - - /** - * Called to get an AddonInstall to download and install an add-on from a URL. - * - * @param aUrl - * The URL to be installed - * @param aHash - * A hash for the install - * @param aName - * A name for the install - * @param aIconURL - * An icon URL for the install - * @param aVersion - * A version for the install - * @param aLoadGroup - * An nsILoadGroup to associate requests with - * @param aCallback - * A callback to pass the AddonInstall to - */ - getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL, - aVersion, aLoadGroup, aCallback) { - // Not yet implemented - }, - - /** - * Called to get an AddonInstall to install an add-on from a local file. - * - * @param aFile - * The file to be installed - * @param aCallback - * A callback to pass the AddonInstall to - */ - getInstallForFile: function MP_getInstallForFile(aFile, aCallback) { - // Not yet implemented - }, - - /** - * Called to test whether installing add-ons is enabled. - * - * @return true if installing is enabled - */ - isInstallEnabled: function MP_isInstallEnabled() { - return false; - }, - - /** - * Called to test whether this provider supports installing a particular - * mimetype. - * - * @param aMimetype - * The mimetype to check for - * @return true if the mimetype is supported - */ - supportsMimetype: function MP_supportsMimetype(aMimetype) { - return false; - }, - - /** - * Called to test whether installing add-ons from a URI is allowed. - * - * @param aUri - * The URI being installed from - * @return true if installing is allowed - */ - isInstallAllowed: function MP_isInstallAllowed(aUri) { - return false; - }, - - - /** *** Internal functions *****/ - - /** - * Delay calling a callback to fake a time-consuming async operation. - * The delay is specified by the apiDelay property, in milliseconds. - * Parameters to send to the callback should be specified as arguments after - * the aCallback argument. - * - * @param aCallback Callback to eventually call - */ - _delayCallback: function MP_delayCallback(aCallback, ...aArgs) { - if (!this.useAsyncCallbacks) { - aCallback(...aArgs); - return; - } - - let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - // Need to keep a reference to the timer, so it doesn't get GC'ed - this.callbackTimers.push(timer); - // Capture a stack trace where the timer was set - // needs the 'new Error' hack until bug 1007656 - this.timerLocations.set(timer, Log.stackTrace(new Error("dummy"))); - timer.initWithCallback(() => { - let idx = this.callbackTimers.indexOf(timer); - if (idx == -1) { - dump("MockProvider._delayCallback lost track of timer set at " - + (this.timerLocations.get(timer) || "unknown location") + "\n"); - } else { - this.callbackTimers.splice(idx, 1); - } - this.timerLocations.delete(timer); - aCallback(...aArgs); - }, this.apiDelay, timer.TYPE_ONE_SHOT); - } -}; - -/** *** Mock Addon object for the Mock Provider *****/ - -function MockAddon(aId, aName, aType, aOperationsRequiringRestart) { - // Only set required attributes. - this.id = aId || ""; - this.name = aName || ""; - this.type = aType || "extension"; - this.version = ""; - this.isCompatible = true; - this.providesUpdatesSecurely = true; - this.blocklistState = 0; - this._appDisabled = false; - this._userDisabled = false; - this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE; - this.scope = AddonManager.SCOPE_PROFILE; - this.isActive = true; - this.creator = ""; - this.pendingOperations = 0; - this._permissions = AddonManager.PERM_CAN_UNINSTALL | - AddonManager.PERM_CAN_ENABLE | - AddonManager.PERM_CAN_DISABLE | - AddonManager.PERM_CAN_UPGRADE; - this.operationsRequiringRestart = (aOperationsRequiringRestart != undefined) ? - aOperationsRequiringRestart : - (AddonManager.OP_NEEDS_RESTART_INSTALL | - AddonManager.OP_NEEDS_RESTART_UNINSTALL | - AddonManager.OP_NEEDS_RESTART_ENABLE | - AddonManager.OP_NEEDS_RESTART_DISABLE); -} - -MockAddon.prototype = { - get isCorrectlySigned() { - if (this.signedState === AddonManager.SIGNEDSTATE_NOT_REQUIRED) - return true; - return this.signedState > AddonManager.SIGNEDSTATE_MISSING; - }, - - get shouldBeActive() { - return !this.appDisabled && !this._userDisabled && - !(this.pendingOperations & AddonManager.PENDING_UNINSTALL); - }, - - get appDisabled() { - return this._appDisabled; - }, - - set appDisabled(val) { - if (val == this._appDisabled) - return val; - - AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]); - - var currentActive = this.shouldBeActive; - this._appDisabled = val; - var newActive = this.shouldBeActive; - this._updateActiveState(currentActive, newActive); - - return val; - }, - - get userDisabled() { - return this._userDisabled; - }, - - set userDisabled(val) { - if (val == this._userDisabled) - return val; - - var currentActive = this.shouldBeActive; - this._userDisabled = val; - var newActive = this.shouldBeActive; - this._updateActiveState(currentActive, newActive); - - return val; - }, - - get permissions() { - let permissions = this._permissions; - if (this.appDisabled || !this._userDisabled) - permissions &= ~AddonManager.PERM_CAN_ENABLE; - if (this.appDisabled || this._userDisabled) - permissions &= ~AddonManager.PERM_CAN_DISABLE; - return permissions; - }, - - set permissions(val) { - return this._permissions = val; - }, - - get applyBackgroundUpdates() { - return this._applyBackgroundUpdates; - }, - - set applyBackgroundUpdates(val) { - if (val != AddonManager.AUTOUPDATE_DEFAULT && - val != AddonManager.AUTOUPDATE_DISABLE && - val != AddonManager.AUTOUPDATE_ENABLE) { - ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val); - } - this._applyBackgroundUpdates = val; - AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]); - }, - - isCompatibleWith: function(aAppVersion, aPlatformVersion) { - return true; - }, - - findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { - // Tests can implement this if they need to - }, - - uninstall: function(aAlwaysAllowUndo = false) { - if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL) - && this.pendingOperations & AddonManager.PENDING_UNINSTALL) - throw Components.Exception("Add-on is already pending uninstall"); - - var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL); - this.pendingOperations |= AddonManager.PENDING_UNINSTALL; - AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart); - if (!needsRestart) { - this.pendingOperations -= AddonManager.PENDING_UNINSTALL; - this._provider.removeAddon(this); - } else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) { - this.isActive = false; - } - }, - - cancelUninstall: function() { - if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL)) - throw Components.Exception("Add-on is not pending uninstall"); - - this.pendingOperations -= AddonManager.PENDING_UNINSTALL; - this.isActive = this.shouldBeActive; - AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); - }, - - markAsSeen: function() { - this.seen = true; - }, - - _updateActiveState: function(currentActive, newActive) { - if (currentActive == newActive) - return; - - if (newActive == this.isActive) { - this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE); - AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); - } - else if (newActive) { - let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE); - this.pendingOperations |= AddonManager.PENDING_ENABLE; - AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart); - if (!needsRestart) { - this.isActive = newActive; - this.pendingOperations -= AddonManager.PENDING_ENABLE; - AddonManagerPrivate.callAddonListeners("onEnabled", this); - } - } - else { - let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE); - this.pendingOperations |= AddonManager.PENDING_DISABLE; - AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart); - if (!needsRestart) { - this.isActive = newActive; - this.pendingOperations -= AddonManager.PENDING_DISABLE; - AddonManagerPrivate.callAddonListeners("onDisabled", this); - } - } - } -}; - -/** *** Mock AddonInstall object for the Mock Provider *****/ - -function MockInstall(aName, aType, aAddonToInstall) { - this.name = aName || ""; - // Don't expose type until download completed - this._type = aType || "extension"; - this.type = null; - this.version = "1.0"; - this.iconURL = ""; - this.infoURL = ""; - this.state = AddonManager.STATE_AVAILABLE; - this.error = 0; - this.sourceURI = null; - this.file = null; - this.progress = 0; - this.maxProgress = -1; - this.certificate = null; - this.certName = ""; - this.existingAddon = null; - this.addon = null; - this._addonToInstall = aAddonToInstall; - this.listeners = []; - - // Another type of install listener for tests that want to check the results - // of code run from standard install listeners - this.testListeners = []; -} - -MockInstall.prototype = { - install: function() { - switch (this.state) { - case AddonManager.STATE_AVAILABLE: - this.state = AddonManager.STATE_DOWNLOADING; - if (!this.callListeners("onDownloadStarted")) { - this.state = AddonManager.STATE_CANCELLED; - this.callListeners("onDownloadCancelled"); - return; - } - - this.type = this._type; - - // Adding addon to MockProvider to be implemented when needed - if (this._addonToInstall) - this.addon = this._addonToInstall; - else { - this.addon = new MockAddon("", this.name, this.type); - this.addon.version = this.version; - this.addon.pendingOperations = AddonManager.PENDING_INSTALL; - } - this.addon.install = this; - if (this.existingAddon) { - if (!this.addon.id) - this.addon.id = this.existingAddon.id; - this.existingAddon.pendingUpgrade = this.addon; - this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE; - } - - this.state = AddonManager.STATE_DOWNLOADED; - this.callListeners("onDownloadEnded"); - - case AddonManager.STATE_DOWNLOADED: - this.state = AddonManager.STATE_INSTALLING; - if (!this.callListeners("onInstallStarted")) { - this.state = AddonManager.STATE_CANCELLED; - this.callListeners("onInstallCancelled"); - return; - } - - let needsRestart = (this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_INSTALL); - AddonManagerPrivate.callAddonListeners("onInstalling", this.addon, needsRestart); - if (!needsRestart) { - AddonManagerPrivate.callAddonListeners("onInstalled", this.addon); - } - - this.state = AddonManager.STATE_INSTALLED; - this.callListeners("onInstallEnded"); - break; - case AddonManager.STATE_DOWNLOADING: - case AddonManager.STATE_CHECKING: - case AddonManager.STATE_INSTALLING: - // Installation is already running - return; - default: - ok(false, "Cannot start installing when state = " + this.state); - } - }, - - cancel: function() { - switch (this.state) { - case AddonManager.STATE_AVAILABLE: - this.state = AddonManager.STATE_CANCELLED; - break; - case AddonManager.STATE_INSTALLED: - this.state = AddonManager.STATE_CANCELLED; - this._provider.removeInstall(this); - this.callListeners("onInstallCancelled"); - break; - default: - // Handling cancelling when downloading to be implemented when needed - ok(false, "Cannot cancel when state = " + this.state); - } - }, - - - addListener: function(aListener) { - if (!this.listeners.some(i => i == aListener)) - this.listeners.push(aListener); - }, - - removeListener: function(aListener) { - this.listeners = this.listeners.filter(i => i != aListener); - }, - - addTestListener: function(aListener) { - if (!this.testListeners.some(i => i == aListener)) - this.testListeners.push(aListener); - }, - - removeTestListener: function(aListener) { - this.testListeners = this.testListeners.filter(i => i != aListener); - }, - - callListeners: function(aMethod) { - var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners, - this, this.addon); - - // Call test listeners after standard listeners to remove race condition - // between standard and test listeners - for (let listener of this.testListeners) { - try { - if (aMethod in listener) - if (listener[aMethod].call(listener, this, this.addon) === false) - result = false; - } - catch (e) { - ok(false, "Test listener threw exception: " + e); - } - } - - return result; - } -}; - -function waitForCondition(condition, nextTest, errorMsg) { - let tries = 0; - let interval = setInterval(function() { - if (tries >= 30) { - ok(false, errorMsg); - moveOn(); - } - var conditionPassed; - try { - conditionPassed = condition(); - } catch (e) { - ok(false, e + "\n" + e.stack); - conditionPassed = false; - } - if (conditionPassed) { - moveOn(); - } - tries++; - }, 100); - let moveOn = function() { clearInterval(interval); nextTest(); }; -} - -function getTestPluginTag() { - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - let tags = ph.getPluginTags(); - - // Find the test plugin - for (let i = 0; i < tags.length; i++) { - if (tags[i].name == "Test Plug-in") - return tags[i]; - } - ok(false, "Unable to find plugin"); - return null; -} |