diff options
Diffstat (limited to '')
8 files changed, 698 insertions, 0 deletions
diff --git a/browser/base/content/test/plugins/browser.toml b/browser/base/content/test/plugins/browser.toml new file mode 100644 index 0000000000..b941e7278d --- /dev/null +++ b/browser/base/content/test/plugins/browser.toml @@ -0,0 +1,15 @@ +[DEFAULT] +support-files = [ + "empty_file.html", + "head.js", + "plugin_bug797677.html", +] + +["browser_bug797677.js"] + +["browser_enable_DRM_prompt.js"] + +["browser_globalplugin_crashinfobar.js"] +run-if = ["crashreporter"] + +["browser_private_browsing_eme_persistent_state.js"] diff --git a/browser/base/content/test/plugins/browser_bug797677.js b/browser/base/content/test/plugins/browser_bug797677.js new file mode 100644 index 0000000000..60a59ea98b --- /dev/null +++ b/browser/base/content/test/plugins/browser_bug797677.js @@ -0,0 +1,45 @@ +var gTestRoot = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://127.0.0.1:8888/" +); +var gTestBrowser = null; +var gConsoleErrors = 0; + +add_task(async function () { + registerCleanupFunction(function () { + Services.console.unregisterListener(errorListener); + gBrowser.removeCurrentTab(); + window.focus(); + gTestBrowser = null; + }); + + gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser); + gTestBrowser = gBrowser.selectedBrowser; + + let errorListener = { + observe(aMessage) { + if (aMessage.message.includes("NS_ERROR_FAILURE")) { + gConsoleErrors++; + } + }, + }; + Services.console.registerListener(errorListener); + + await promiseTabLoadEvent( + gBrowser.selectedTab, + gTestRoot + "plugin_bug797677.html" + ); + + let pluginInfo = await promiseForPluginInfo("plugin"); + is( + pluginInfo.displayedType, + Ci.nsIObjectLoadingContent.TYPE_FALLBACK, + "plugin should not have been found." + ); + + await SpecialPowers.spawn(gTestBrowser, [], function () { + let plugin = content.document.getElementById("plugin"); + ok(plugin, "plugin should be in the page"); + }); + is(gConsoleErrors, 0, "should have no console errors"); +}); diff --git a/browser/base/content/test/plugins/browser_enable_DRM_prompt.js b/browser/base/content/test/plugins/browser_enable_DRM_prompt.js new file mode 100644 index 0000000000..3dfa26f021 --- /dev/null +++ b/browser/base/content/test/plugins/browser_enable_DRM_prompt.js @@ -0,0 +1,298 @@ +const TEST_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" + ) + "empty_file.html"; + +/* + * Register cleanup function to reset prefs after other tasks have run. + */ + +add_task(async function () { + // Note: SpecialPowers.pushPrefEnv has problems with the "Enable DRM" + // button on the notification box toggling the prefs. So manually + // set/unset the prefs the UI we're testing toggles. + let emeWasEnabled = Services.prefs.getBoolPref("media.eme.enabled", false); + let cdmWasEnabled = Services.prefs.getBoolPref( + "media.gmp-widevinecdm.enabled", + false + ); + + // Restore the preferences to their pre-test state on test finish. + registerCleanupFunction(function () { + // Unlock incase lock test threw and didn't unlock. + Services.prefs.unlockPref("media.eme.enabled"); + Services.prefs.setBoolPref("media.eme.enabled", emeWasEnabled); + Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", cdmWasEnabled); + }); +}); + +/* + * Bug 1366167 - Tests that the "Enable DRM" prompt shows if EME is requested while EME is disabled. + */ + +add_task(async function test_drm_prompt_shows_for_toplevel() { + await BrowserTestUtils.withNewTab(TEST_URL, async function (browser) { + // Turn off EME and Widevine CDM. + Services.prefs.setBoolPref("media.eme.enabled", false); + Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false); + let notificationShownPromise = BrowserTestUtils.waitForNotificationBar( + gBrowser, + browser, + "drmContentDisabled" + ); + + // Have content request access to Widevine, UI should drop down to + // prompt user to enable DRM. + let result = await SpecialPowers.spawn(browser, [], async function () { + try { + let config = [ + { + initDataTypes: ["webm"], + videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }], + }, + ]; + await content.navigator.requestMediaKeySystemAccess( + "com.widevine.alpha", + config + ); + } catch (ex) { + return { rejected: true }; + } + return { rejected: false }; + }); + is( + result.rejected, + true, + "EME request should be denied because EME disabled." + ); + + // Verify the UI prompt showed. + let box = gBrowser.getNotificationBox(browser); + await notificationShownPromise; + let notification = box.currentNotification; + await notification.updateComplete; + + ok(notification, "Notification should be visible"); + is( + notification.getAttribute("value"), + "drmContentDisabled", + "Should be showing the right notification" + ); + + // Verify the "Enable DRM" button is there. + let buttons = notification.buttonContainer.querySelectorAll( + ".notification-button" + ); + is(buttons.length, 1, "Should have one button."); + + // Prepare a Promise that should resolve when the "Enable DRM" button's + // page reload completes. + let refreshPromise = BrowserTestUtils.browserLoaded(browser); + buttons[0].click(); + + // Wait for the reload to complete. + await refreshPromise; + + // Verify clicking the "Enable DRM" button enabled DRM. + let enabled = Services.prefs.getBoolPref("media.eme.enabled", true); + is( + enabled, + true, + "EME should be enabled after click on 'Enable DRM' button" + ); + }); +}); + +add_task(async function test_eme_locked() { + await BrowserTestUtils.withNewTab(TEST_URL, async function (browser) { + // Turn off EME and Widevine CDM. + Services.prefs.setBoolPref("media.eme.enabled", false); + Services.prefs.lockPref("media.eme.enabled"); + + // Have content request access to Widevine, UI should drop down to + // prompt user to enable DRM. + let result = await SpecialPowers.spawn(browser, [], async function () { + try { + let config = [ + { + initDataTypes: ["webm"], + videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }], + }, + ]; + await content.navigator.requestMediaKeySystemAccess( + "com.widevine.alpha", + config + ); + } catch (ex) { + return { rejected: true }; + } + return { rejected: false }; + }); + is( + result.rejected, + true, + "EME request should be denied because EME disabled." + ); + + // Verify the UI prompt did not show. + let box = gBrowser.getNotificationBox(browser); + let notification = box.currentNotification; + + is( + notification, + null, + "Notification should not be displayed since pref is locked" + ); + + // Unlock the pref for any tests that follow. + Services.prefs.unlockPref("media.eme.enabled"); + }); +}); + +/* + * Bug 1642465 - Ensure cross origin frames requesting access prompt in the same way as same origin. + */ + +add_task(async function test_drm_prompt_shows_for_cross_origin_iframe() { + await BrowserTestUtils.withNewTab(TEST_URL, async function (browser) { + // Turn off EME and Widevine CDM. + Services.prefs.setBoolPref("media.eme.enabled", false); + Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false); + let notificationShownPromise = BrowserTestUtils.waitForNotificationBar( + gBrowser, + browser, + "drmContentDisabled" + ); + + // Have content request access to Widevine, UI should drop down to + // prompt user to enable DRM. + const CROSS_ORIGIN_URL = TEST_URL.replace("example.com", "example.org"); + let result = await SpecialPowers.spawn( + browser, + [CROSS_ORIGIN_URL], + async function (crossOriginUrl) { + let frame = content.document.createElement("iframe"); + frame.src = crossOriginUrl; + await new Promise(resolve => { + frame.addEventListener("load", () => { + resolve(); + }); + content.document.body.appendChild(frame); + }); + + return content.SpecialPowers.spawn(frame, [], async function () { + try { + let config = [ + { + initDataTypes: ["webm"], + videoCapabilities: [ + { contentType: 'video/webm; codecs="vp9"' }, + ], + }, + ]; + await content.navigator.requestMediaKeySystemAccess( + "com.widevine.alpha", + config + ); + } catch (ex) { + return { rejected: true }; + } + return { rejected: false }; + }); + } + ); + is( + result.rejected, + true, + "EME request should be denied because EME disabled." + ); + + // Verify the UI prompt showed. + let box = gBrowser.getNotificationBox(browser); + await notificationShownPromise; + let notification = box.currentNotification; + await notification.updateComplete; + + ok(notification, "Notification should be visible"); + is( + notification.getAttribute("value"), + "drmContentDisabled", + "Should be showing the right notification" + ); + + // Verify the "Enable DRM" button is there. + let buttons = notification.buttonContainer.querySelectorAll( + ".notification-button" + ); + is(buttons.length, 1, "Should have one button."); + + // Prepare a Promise that should resolve when the "Enable DRM" button's + // page reload completes. + let refreshPromise = BrowserTestUtils.browserLoaded(browser); + buttons[0].click(); + + // Wait for the reload to complete. + await refreshPromise; + + // Verify clicking the "Enable DRM" button enabled DRM. + let enabled = Services.prefs.getBoolPref("media.eme.enabled", true); + is( + enabled, + true, + "EME should be enabled after click on 'Enable DRM' button" + ); + }); +}); + +add_task(async function test_drm_prompt_only_shows_one_notification() { + await BrowserTestUtils.withNewTab(TEST_URL, async function (browser) { + // Turn off EME and Widevine CDM. + Services.prefs.setBoolPref("media.eme.enabled", false); + Services.prefs.setBoolPref("media.gmp-widevinecdm.enabled", false); + let notificationShownPromise = BrowserTestUtils.waitForNotificationBar( + gBrowser, + browser, + "drmContentDisabled" + ); + + // Send three EME requests to ensure only one instance of the + // "Enable DRM" notification appears in the chrome + for (let i = 0; i < 3; i++) { + await SpecialPowers.spawn(browser, [], async function () { + try { + let config = [ + { + initDataTypes: ["webm"], + videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }], + }, + ]; + await content.navigator.requestMediaKeySystemAccess( + "com.widevine.alpha", + config + ); + } catch (ex) { + return { rejected: true }; + } + return { rejected: false }; + }); + } + + // Verify the UI prompt showed. + let box = gBrowser.getNotificationBox(browser); + await notificationShownPromise; + let notification = box.currentNotification; + + ok(notification, "Notification should be visible"); + is( + notification.getAttribute("value"), + "drmContentDisabled", + "Should be showing the right notification" + ); + is( + box.allNotifications.length, + 1, + "There should only be one notification shown" + ); + }); +}); diff --git a/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js b/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js new file mode 100644 index 0000000000..38ac3864c0 --- /dev/null +++ b/browser/base/content/test/plugins/browser_globalplugin_crashinfobar.js @@ -0,0 +1,63 @@ +"use strict"; + +let { PluginManager } = ChromeUtils.importESModule( + "resource:///actors/PluginParent.sys.mjs" +); + +/** + * Test that the notification bar for crashed GMPs works. + */ +add_task(async function () { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "about:blank", + }, + async function (browser) { + // Ensure the parent has heard before the client. + // In practice, this is always true for GMP crashes (but not for NPAPI ones!) + let props = Cc["@mozilla.org/hash-property-bag;1"].createInstance( + Ci.nsIWritablePropertyBag2 + ); + props.setPropertyAsUint32("pluginID", 1); + props.setPropertyAsACString("pluginName", "GlobalTestPlugin"); + props.setPropertyAsACString("pluginDumpID", "1234"); + Services.obs.notifyObservers(props, "gmp-plugin-crash"); + + await SpecialPowers.spawn(browser, [], async function () { + const GMP_CRASH_EVENT = { + pluginID: 1, + pluginName: "GlobalTestPlugin", + submittedCrashReport: false, + bubbles: true, + cancelable: true, + gmpPlugin: true, + }; + + let crashEvent = new content.PluginCrashedEvent( + "PluginCrashed", + GMP_CRASH_EVENT + ); + content.dispatchEvent(crashEvent); + }); + + let notification = await waitForNotificationBar( + "plugin-crashed", + browser + ); + + let notificationBox = gBrowser.getNotificationBox(browser); + ok(notification, "Infobar was shown."); + is( + notification.priority, + notificationBox.PRIORITY_WARNING_MEDIUM, + "Correct priority." + ); + is( + notification.messageText.textContent.trim(), + "The GlobalTestPlugin plugin has crashed.", + "Correct message." + ); + } + ); +}); diff --git a/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js b/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js new file mode 100644 index 0000000000..fba4bb552c --- /dev/null +++ b/browser/base/content/test/plugins/browser_private_browsing_eme_persistent_state.js @@ -0,0 +1,59 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This test ensures that navigator.requestMediaKeySystemAccess() requests + * to run EME with persistent state are rejected in private browsing windows. + * Bug 1334111. + */ + +const TEST_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" + ) + "empty_file.html"; + +async function isEmePersistentStateSupported(mode) { + let win = await BrowserTestUtils.openNewBrowserWindow(mode); + let tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, TEST_URL); + let persistentStateSupported = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + async function () { + try { + let config = [ + { + initDataTypes: ["webm"], + videoCapabilities: [{ contentType: 'video/webm; codecs="vp9"' }], + persistentState: "required", + }, + ]; + await content.navigator.requestMediaKeySystemAccess( + "org.w3.clearkey", + config + ); + } catch (ex) { + return false; + } + return true; + } + ); + + await BrowserTestUtils.closeWindow(win); + + return persistentStateSupported; +} + +add_task(async function test() { + is( + await isEmePersistentStateSupported({ private: true }), + false, + "EME persistentState should *NOT* be supported in private browsing window." + ); + is( + await isEmePersistentStateSupported({ private: false }), + true, + "EME persistentState *SHOULD* be supported in non private browsing window." + ); +}); diff --git a/browser/base/content/test/plugins/empty_file.html b/browser/base/content/test/plugins/empty_file.html new file mode 100644 index 0000000000..af8440ac16 --- /dev/null +++ b/browser/base/content/test/plugins/empty_file.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + </head> + <body> + This page is intentionally left blank. + </body> +</html> diff --git a/browser/base/content/test/plugins/head.js b/browser/base/content/test/plugins/head.js new file mode 100644 index 0000000000..4f6c25b92a --- /dev/null +++ b/browser/base/content/test/plugins/head.js @@ -0,0 +1,204 @@ +ChromeUtils.defineESModuleGetters(this, { + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", +}); + +// 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.startLoadingURIString(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 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 { + activated: plugin.activated, + hasRunningPlugin: plugin.hasRunningPlugin, + displayedType: plugin.displayedType, + }; + }); +} + +/** + * 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); + }); +} diff --git a/browser/base/content/test/plugins/plugin_bug797677.html b/browser/base/content/test/plugins/plugin_bug797677.html new file mode 100644 index 0000000000..1545f36475 --- /dev/null +++ b/browser/base/content/test/plugins/plugin_bug797677.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<html> +<head><meta charset="utf-8"/></head> +<body><embed id="plugin" type="9000"></embed></body> +</html> |