fune/browser/base/content/test/plugins/head.js
Csoregi Natalia d68661e2cc Backed out 24 changesets (bug 1682030) for bustage on ProcessHangMonitor.cpp and nsCOMPtr.h. CLOSED TREE
Backed out changeset 5b1644096477 (bug 1682030)
Backed out changeset 35ae60eea3c7 (bug 1682030)
Backed out changeset 3eca76a6d639 (bug 1682030)
Backed out changeset 259c45447ad9 (bug 1682030)
Backed out changeset de9222dc8c31 (bug 1682030)
Backed out changeset 2986c7e14349 (bug 1682030)
Backed out changeset 6af3410bdb93 (bug 1682030)
Backed out changeset 42b0621c2927 (bug 1682030)
Backed out changeset 366e3e371858 (bug 1682030)
Backed out changeset 9adb2865adea (bug 1682030)
Backed out changeset 6af6af3bc03a (bug 1682030)
Backed out changeset da94a91b35ae (bug 1682030)
Backed out changeset 9143da258d0e (bug 1682030)
Backed out changeset 5e20d06952ba (bug 1682030)
Backed out changeset 6253d7e1ce7d (bug 1682030)
Backed out changeset 0e06ddeea3e2 (bug 1682030)
Backed out changeset 9c58d57c9e44 (bug 1682030)
Backed out changeset e90edd89430e (bug 1682030)
Backed out changeset 5861b8166b10 (bug 1682030)
Backed out changeset b4b88cdc7993 (bug 1682030)
Backed out changeset b80054e9805c (bug 1682030)
Backed out changeset 580d857674c0 (bug 1682030)
Backed out changeset a9cdf93c2662 (bug 1682030)
Backed out changeset 9c9c8b4998e2 (bug 1682030)
2021-04-06 03:54:12 +03:00

452 lines
13 KiB
JavaScript

var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"PromiseUtils",
"resource://gre/modules/PromiseUtils.jsm"
);
XPCOMUtils.defineLazyServiceGetters(this, {
uuidGen: ["@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"],
});
// Various tests in this directory may define gTestBrowser, to use as the
// default browser under test in some of the functions below.
/* global gTestBrowser:true */
/**
* Waits a specified number of miliseconds.
*
* Usage:
* let wait = yield waitForMs(2000);
* ok(wait, "2 seconds should now have elapsed");
*
* @param aMs the number of miliseconds to wait for
* @returns a Promise that resolves to true after the time has elapsed
*/
function waitForMs(aMs) {
return new Promise(resolve => {
setTimeout(done, aMs);
function done() {
resolve(true);
}
});
}
/**
* Waits for a load (or custom) event to finish in a given tab. If provided
* load an uri into the tab.
*
* @param tab
* The tab to load into.
* @param [optional] url
* The url to load, or the current url.
* @return {Promise} resolved when the event is handled.
* @resolves to the received event
* @rejects if a valid load event is not received within a meaningful interval
*/
function promiseTabLoadEvent(tab, url) {
info("Wait tab event: load");
function handle(loadedUrl) {
if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
info(`Skipping spurious load event for ${loadedUrl}`);
return false;
}
info("Tab event received: load");
return true;
}
let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
if (url) {
BrowserTestUtils.loadURI(tab.linkedBrowser, url);
}
return loaded;
}
function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
let tries = 0;
let maxTries = aTries || 100; // 100 tries
let maxWait = aWait || 100; // 100 msec x 100 tries = ten seconds
let interval = setInterval(function() {
if (tries >= maxTries) {
ok(false, errorMsg);
moveOn();
}
let conditionPassed;
try {
conditionPassed = condition();
} catch (e) {
ok(false, e + "\n" + e.stack);
conditionPassed = false;
}
if (conditionPassed) {
moveOn();
}
tries++;
}, maxWait);
let moveOn = function() {
clearInterval(interval);
nextTest();
};
}
// Waits for a conditional function defined by the caller to return true.
function promiseForCondition(aConditionFn, aMessage, aTries, aWait) {
return new Promise(resolve => {
waitForCondition(
aConditionFn,
resolve,
aMessage || "Condition didn't pass.",
aTries,
aWait
);
});
}
// Returns the chrome side nsIPluginTag for this plugin
function getTestPlugin(aName) {
let pluginName = aName || "Test Plug-in";
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 == pluginName) {
return tags[i];
}
}
ok(false, "Unable to find plugin");
return null;
}
// Set the 'enabledState' on the nsIPluginTag stored in the main or chrome
// process.
function setTestPluginEnabledState(newEnabledState, pluginName) {
let name = pluginName || "Test Plug-in";
let plugin = getTestPlugin(name);
plugin.enabledState = newEnabledState;
}
// Get the 'enabledState' on the nsIPluginTag stored in the main or chrome
// process.
function getTestPluginEnabledState(pluginName) {
let name = pluginName || "Test Plug-in";
let plugin = getTestPlugin(name);
return plugin.enabledState;
}
// Returns a promise for nsIObjectLoadingContent props data.
function promiseForPluginInfo(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return SpecialPowers.spawn(browser, [aId], async function(contentId) {
let plugin = content.document.getElementById(contentId);
if (!(plugin instanceof Ci.nsIObjectLoadingContent)) {
throw new Error("no plugin found");
}
return {
pluginFallbackType: plugin.pluginFallbackType,
activated: plugin.activated,
hasRunningPlugin: plugin.hasRunningPlugin,
displayedType: plugin.displayedType,
};
});
}
// Return a promise and call the plugin's playPlugin() method.
function promisePlayObject(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return SpecialPowers.spawn(browser, [aId], async function(contentId) {
content.document.getElementById(contentId).playPlugin();
});
}
function promiseCrashObject(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return SpecialPowers.spawn(browser, [aId], async function(contentId) {
let plugin = content.document.getElementById(contentId);
Cu.waiveXrays(plugin).crash();
});
}
// Return a promise and call the plugin's getObjectValue() method.
function promiseObjectValueResult(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return SpecialPowers.spawn(browser, [aId], async function(contentId) {
let plugin = content.document.getElementById(contentId);
return Cu.waiveXrays(plugin).getObjectValue();
});
}
// Return a promise and reload the target plugin in the page
function promiseReloadPlugin(aId, aBrowser) {
let browser = aBrowser || gTestBrowser;
return SpecialPowers.spawn(browser, [aId], async function(contentId) {
let plugin = content.document.getElementById(contentId);
// eslint-disable-next-line no-self-assign
plugin.src = plugin.src;
});
}
// after a test is done using the plugin doorhanger, we should just clear
// any permissions that may have crept in
function clearAllPluginPermissions() {
for (let perm of Services.perms.all) {
if (perm.type.startsWith("plugin")) {
info(
"removing permission:" + perm.principal.origin + " " + perm.type + "\n"
);
Services.perms.removePermission(perm);
}
}
}
// Ported from AddonTestUtils.jsm
let JSONBlocklistWrapper = {
/**
* Load the data from the specified files into the *real* blocklist providers.
* Loads using loadBlocklistRawData, which will treat this as an update.
*
* @param {nsIFile} dir
* The directory in which the files live.
* @param {string} prefix
* a prefix for the files which ought to be loaded.
* This method will suffix -extensions.json and -plugins.json
* to the prefix it is given, and attempt to load both.
* Insofar as either exists, their data will be dumped into
* the respective store, and the respective update handlers
* will be called.
*/
async loadBlocklistData(url) {
const fullURL = `${url}-plugins.json`;
let jsonObj;
try {
jsonObj = await (await fetch(fullURL)).json();
} catch (ex) {
ok(false, ex);
}
info(`Loaded ${fullURL}`);
return this.loadBlocklistRawData({ plugins: jsonObj });
},
/**
* Load the following data into the *real* blocklist providers.
* While `overrideBlocklist` replaces the blocklist entirely with a mock
* that returns dummy data, this method instead loads data into the actual
* blocklist, fires update methods as would happen if this data came from
* an actual blocklist update, etc.
*
* @param {object} data
* An object that can optionally have `extensions` and/or `plugins`
* properties, each being an array of blocklist items.
* This code only uses plugin blocks, that can look something like:
*
* {
* "matchFilename": "libnptest\\.so|nptest\\.dll|Test\\.plugin",
* "versionRange": [
* {
* "severity": "0",
* "vulnerabilityStatus": "1"
* }
* ],
* "blockID": "p9999"
* }
*
*/
async loadBlocklistRawData(data) {
const bsPass = ChromeUtils.import(
"resource://gre/modules/Blocklist.jsm",
null
);
const blocklistMapping = {
extensions: bsPass.ExtensionBlocklistRS,
plugins: bsPass.PluginBlocklistRS,
};
for (const [dataProp, blocklistObj] of Object.entries(blocklistMapping)) {
let newData = data[dataProp];
if (!newData) {
continue;
}
if (!Array.isArray(newData)) {
throw new Error(
"Expected an array of new items to put in the " +
dataProp +
" blocklist!"
);
}
for (let item of newData) {
if (!item.id) {
item.id = uuidGen.generateUUID().number.slice(1, -1);
}
if (!item.last_modified) {
item.last_modified = Date.now();
}
}
await blocklistObj.ensureInitialized();
let db = await blocklistObj._client.db;
await db.importChanges({}, 42, newData, { clear: true });
// We manually call _onUpdate... which is evil, but at the moment kinto doesn't have
// a better abstraction unless you want to mock your own http server to do the update.
await blocklistObj._onUpdate();
}
},
};
// An async helper that insures a new blocklist is loaded (in both
// processes if applicable).
async function asyncSetAndUpdateBlocklist(aURL, aBrowser) {
let doTestRemote = aBrowser ? aBrowser.isRemoteBrowser : false;
let localPromise = TestUtils.topicObserved("plugin-blocklist-updated");
info("*** loading blocklist: " + aURL);
await JSONBlocklistWrapper.loadBlocklistData(aURL);
info("*** waiting on local load");
await localPromise;
if (doTestRemote) {
info("*** waiting on remote load");
// Ensure content has been updated with the blocklist
await SpecialPowers.spawn(aBrowser, [], () => {});
}
info("*** blocklist loaded.");
}
// Insure there's a popup notification present. This test does not indicate
// open state. aBrowser can be undefined.
function promisePopupNotification(aName, aBrowser) {
return new Promise(resolve => {
waitForCondition(
() => PopupNotifications.getNotification(aName, aBrowser),
() => {
ok(
!!PopupNotifications.getNotification(aName, aBrowser),
aName + " notification appeared"
);
resolve();
},
"timeout waiting for popup notification " + aName
);
});
}
/**
* Allows setting focus on a window, and waiting for that window to achieve
* focus.
*
* @param aWindow
* The window to focus and wait for.
*
* @return {Promise}
* @resolves When the window is focused.
* @rejects Never.
*/
function promiseWaitForFocus(aWindow) {
return new Promise(resolve => {
waitForFocus(resolve, aWindow);
});
}
/**
* Returns a Promise that resolves when a notification bar
* for a browser is shown. Alternatively, for old-style callers,
* can automatically call a callback before it resolves.
*
* @param notificationID
* The ID of the notification to look for.
* @param browser
* The browser to check for the notification bar.
* @param callback (optional)
* A function to be called just before the Promise resolves.
*
* @return Promise
*/
function waitForNotificationBar(notificationID, browser, callback) {
return new Promise((resolve, reject) => {
let notification;
let notificationBox = gBrowser.getNotificationBox(browser);
waitForCondition(
() =>
(notification = notificationBox.getNotificationWithValue(
notificationID
)),
() => {
ok(
notification,
`Successfully got the ${notificationID} notification bar`
);
if (callback) {
callback(notification);
}
resolve(notification);
},
`Waited too long for the ${notificationID} notification bar`
);
});
}
function promiseForNotificationBar(notificationID, browser) {
return new Promise(resolve => {
waitForNotificationBar(notificationID, browser, resolve);
});
}
/**
* Reshow a notification and call a callback when it is reshown.
* @param notification
* The notification to reshow
* @param callback
* A function to be called when the notification has been reshown
*/
function waitForNotificationShown(notification, callback) {
if (PopupNotifications.panel.state == "open") {
executeSoon(callback);
return;
}
PopupNotifications.panel.addEventListener(
"popupshown",
function(e) {
callback();
},
{ once: true }
);
notification.reshow();
}
function promiseForNotificationShown(notification) {
return new Promise(resolve => {
waitForNotificationShown(notification, resolve);
});
}
/**
* Due to layout being async, "PluginBindAttached" may trigger later. This
* returns a Promise that resolves once we've forced a layout flush, which
* triggers the PluginBindAttached event to fire. This trick only works if
* there is some sort of plugin in the page.
* @param browser
* The browser to force plugin bindings in.
* @return Promise
*/
function promiseUpdatePluginBindings(browser) {
return SpecialPowers.spawn(browser, [], async function() {
let doc = content.document;
let elems = doc.getElementsByTagName("embed");
if (!elems || elems.length < 1) {
elems = doc.getElementsByTagName("object");
}
if (elems && elems.length) {
elems[0].clientTop;
}
});
}