summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/webextensions/test/browser/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/webextensions/test/browser/head.js')
-rw-r--r--toolkit/mozapps/webextensions/test/browser/head.js1468
1 files changed, 0 insertions, 1468 deletions
diff --git a/toolkit/mozapps/webextensions/test/browser/head.js b/toolkit/mozapps/webextensions/test/browser/head.js
deleted file mode 100644
index 5a749099d..000000000
--- a/toolkit/mozapps/webextensions/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;
-}