Merge mozilla-inbound to mozilla-central. a=merge

This commit is contained in:
Daniel Varga 2019-08-21 12:52:49 +03:00
commit 597a69c70a
40 changed files with 3208 additions and 3449 deletions

View File

@ -20,9 +20,6 @@ const kDumpAllStacks = false;
const whitelist = {
modules: new Set([
"chrome://mochikit/content/ShutdownLeaksCollector.jsm",
"resource://specialpowers/SpecialPowersChild.jsm",
"resource://specialpowers/SpecialPowersAPI.jsm",
"resource://specialpowers/WrapPrivileged.jsm",
"resource://gre/modules/ContentProcessSingleton.jsm",
@ -95,6 +92,9 @@ const intermittently_loaded_whitelist = {
"resource://gre/modules/nsAsyncShutdown.jsm",
"resource://gre/modules/sessionstore/Utils.jsm",
"resource://specialpowers/SpecialPowersChild.jsm",
"resource://specialpowers/WrapPrivileged.jsm",
// Webcompat about:config front-end. This is presently nightly-only and
// part of a system add-on which may not load early enough for the test.
"resource://webcompat/AboutCompat.jsm",

View File

@ -33,7 +33,7 @@ add_task(async function setup() {
async function testPopup(hasPopup, buttonToClick) {
let numPageLoaded = gProtectionsHandler._socialTrackingSessionPageLoad;
let numPopupShown = SpecialPowers.getIntPref(
let numPopupShown = Services.prefs.getIntPref(
"privacy.socialtracking.notification.counter",
0
);
@ -89,7 +89,7 @@ async function testPopup(hasPopup, buttonToClick) {
// click on the button of the popup notification
if (typeof buttonToClick === "string") {
is(
SpecialPowers.getBoolPref(
Services.prefs.getBoolPref(
"privacy.socialtracking.notification.enabled",
false
),
@ -101,7 +101,7 @@ async function testPopup(hasPopup, buttonToClick) {
EventUtils.synthesizeMouseAtCenter(notification[buttonToClick], {});
is(
SpecialPowers.getBoolPref(
Services.prefs.getBoolPref(
"privacy.socialtracking.notification.enabled",
true
),
@ -110,13 +110,13 @@ async function testPopup(hasPopup, buttonToClick) {
);
}
let lastShown = SpecialPowers.getCharPref(
let lastShown = Services.prefs.getCharPref(
"privacy.socialtracking.notification.lastShown",
"0"
);
ok(lastShown !== "0", "last shown timestamp updated");
is(
SpecialPowers.getIntPref(
Services.prefs.getIntPref(
"privacy.socialtracking.notification.counter",
0
),
@ -221,12 +221,12 @@ add_task(async function testSocialTrackingPopups() {
for (let config of configs) {
ok(config.description, config.description);
SpecialPowers.pushPrefEnv({
await SpecialPowers.pushPrefEnv({
set: config.prefs,
});
for (let result of config.results) {
await testPopup(result, config.button);
}
SpecialPowers.popPrefEnv();
await SpecialPowers.popPrefEnv();
}
});

View File

@ -141,7 +141,7 @@ async function setDownloadDir() {
await SpecialPowers.pushPrefEnv({
set: [
["browser.download.folderList", 2],
["browser.download.dir", tmpDir, Ci.nsIFile],
["browser.download.dir", tmpDir.path],
],
});
}

View File

@ -6,6 +6,12 @@
# in this manifest to the sub-directory "test-oop-extensions", and then check
# whether we're running from that directory from head.js
install-to-subdir = test-oop-extensions
prefs =
extensions.webextensions.remote=true
# We don't want to reset this at the end of the test, so that we don't have
# to spawn a new extension child process for each test unit.
dom.ipc.keepProcessesAlive.extension=1
tags = webextensions remote-webextensions
skip-if = !e10s
support-files =

View File

@ -2,6 +2,8 @@
tags = webextensions in-process-webextensions
support-files =
head.js
prefs =
extensions.webextensions.remote=false
[browser_ext_autocompletepopup.js]
[browser_ext_windows_allowScriptsToClose.js]

View File

@ -546,6 +546,7 @@ add_task(async function testBadgeColorPersistence() {
add_task(async function testPropertyRemoval() {
await runTests({
manifest: {
name: "Generated extension",
browser_action: {
default_icon: "default.png",
default_popup: "default.html",

View File

@ -2,6 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
// Test that an error is thrown when providing invalid icon sizes
add_task(async function testInvalidIconSizes() {
let extension = ExtensionTestUtils.loadExtension({

View File

@ -2,6 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
const { GlobalManager } = ChromeUtils.import(
"resource://gre/modules/Extension.jsm",
null

View File

@ -2,6 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
function getExtension(page_action) {
return ExtensionTestUtils.loadExtension({
manifest: {

View File

@ -316,13 +316,13 @@ add_task(async function() {
const RESOLUTION_PREF = "layout.css.devPixelsPerPx";
registerCleanupFunction(() => {
SpecialPowers.clearUserPref(RESOLUTION_PREF);
Services.prefs.clearUserPref(RESOLUTION_PREF);
});
await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
for (let resolution of [2, 1]) {
SpecialPowers.setCharPref(RESOLUTION_PREF, String(resolution));
Services.prefs.setCharPref(RESOLUTION_PREF, String(resolution));
is(
window.devicePixelRatio,
resolution,
@ -342,7 +342,7 @@ add_task(async function() {
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab2);
BrowserTestUtils.removeTab(tab3);
SpecialPowers.clearUserPref(RESOLUTION_PREF);
Services.prefs.clearUserPref(RESOLUTION_PREF);
});
add_task(async function testQueryPermissions() {

View File

@ -1,5 +1,7 @@
"use strict";
PromiseTestUtils.whitelistRejectionsGlobally(/packaging errors/);
/**
* Helper function for testing a theme with invalid properties.
* @param {object} invalidProps The invalid properties to load the theme with.

View File

@ -68,20 +68,6 @@ function loadTestSubscript(filePath) {
Services.scriptloader.loadSubScript(new URL(filePath, gTestPath).href, this);
}
// We run tests under two different configurations, from browser.ini and
// browser-remote.ini. When running from browser-remote.ini, the tests are
// copied to the sub-directory "test-oop-extensions", which we detect here, and
// use to select our configuration.
let remote = gTestPath.includes("test-oop-extensions");
SpecialPowers.pushPrefEnv({
set: [["extensions.webextensions.remote", remote]],
});
if (remote) {
// We don't want to reset this at the end of the test, so that we don't have
// to spawn a new extension child process for each test unit.
SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
}
// Don't try to create screenshots of sites we load during tests.
Services.prefs
.getDefaultBranch("browser.newtabpage.activity-stream.")

View File

@ -43,7 +43,7 @@ add_task(async function copy_toolbar_shortcut() {
});
add_task(async function copy_mobile_shortcut() {
SpecialPowers.pushPrefEnv({
await SpecialPowers.pushPrefEnv({
set: [["browser.bookmarks.showMobileBookmarks", true]],
});
await promisePlacesInitComplete();

View File

@ -11,7 +11,6 @@
"workaround-issue38586.patch",
"unpoison-thread-stacks.patch",
"downgrade-mangling-error.patch",
"r355141-arm64-cfg.patch",
"r357725-asan-vs2019.patch",
"loosen-msvc-detection.patch",
"revert-r355311.patch"

View File

@ -1,112 +0,0 @@
[COFF] Add address-taken import thunks to the fid table
https://bugs.llvm.org/show_bug.cgi?id=39799
https://reviews.llvm.org/D58739
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1390,19 +1390,47 @@
// symbol in an executable section.
static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
Symbol *S) {
- auto *D = dyn_cast_or_null<DefinedCOFF>(S);
-
- // Ignore undefined symbols and references to non-functions (e.g. globals and
- // labels).
- if (!D ||
- D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ if (!S)
return;
- // Mark the symbol as address taken if it's in an executable section.
- Chunk *RefChunk = D->getChunk();
- OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
- if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
- addSymbolToRVASet(AddressTakenSyms, D);
+ switch (S->kind()) {
+ case Symbol::DefinedLocalImportKind:
+ case Symbol::DefinedImportDataKind:
+ // Defines an __imp_ pointer, so it is data, so it is ignored.
+ break;
+ case Symbol::DefinedCommonKind:
+ // Common is always data, so it is ignored.
+ break;
+ case Symbol::DefinedAbsoluteKind:
+ case Symbol::DefinedSyntheticKind:
+ // Absolute is never code, synthetic generally isn't and usually isn't
+ // determinable.
+ break;
+ case Symbol::LazyKind:
+ case Symbol::UndefinedKind:
+ // Undefined symbols resolve to zero, so they don't have an RVA. Lazy
+ // symbols shouldn't have relocations.
+ break;
+
+ case Symbol::DefinedImportThunkKind:
+ // Thunks are always code, include them.
+ addSymbolToRVASet(AddressTakenSyms, cast<Defined>(S));
+ break;
+
+ case Symbol::DefinedRegularKind: {
+ // This is a regular, defined, symbol from a COFF file. Mark the symbol as
+ // address taken if the symbol type is function and it's in an executable
+ // section.
+ auto *D = cast<DefinedRegular>(S);
+ if (D->getCOFFSymbol().getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) {
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(AddressTakenSyms, D);
+ }
+ break;
+ }
+ }
}
// Visit all relocations from all section contributions of this object file and
--- a/lld/test/COFF/guardcf-thunk.s
+++ b/lld/test/COFF/guardcf-thunk.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+
+# Make a DLL that exports exportfn1.
+# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj
+# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /implib:%t.lib
+
+# Make an obj that takes the address of that exported function.
+# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t2.obj
+# RUN: lld-link -entry:main -guard:cf %t2.obj %t.lib -nodefaultlib -out:%t.exe
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s
+
+# Check that the gfids table contains *exactly* two entries, one for exportfn1
+# and one for main.
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
+# CHECK-NEXT: 0x{{[0-9A-Fa-f]+0$}}
+# CHECK-NEXT: ]
+
+
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+@feat.00 = 0x001
+
+ .section .text,"rx"
+ .def main; .scl 2; .type 32; .endef
+ .global main
+main:
+ leaq exportfn1(%rip), %rax
+ retq
+
+ .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+ .long 256
+ .fill 124, 1, 0
+ .quad __guard_fids_table
+ .quad __guard_fids_count
+ .long __guard_flags
+ .fill 128, 1, 0
+

View File

@ -31,6 +31,7 @@ skip-if = true # original stepping is currently disabled
skip-if = os == "win" # Bug 1448523, Bug 1448450
[browser_dbg-breaking.js]
[browser_dbg-breaking-from-console.js]
skip-if = debug # Window leaks: bug 1575332
[browser_dbg-breakpoints.js]
[browser_dbg-breakpoints-actions.js]
[browser_dbg-breakpoints-columns.js]
@ -62,6 +63,7 @@ skip-if = (os == "win" && ccov) # Bug 1424154
[browser_dbg-editor-select.js]
[browser_dbg-editor-highlight.js]
[browser_dbg-ember-quickstart.js]
skip-if = debug # Window leaks: bug 1575332
[browser_dbg-expressions.js]
[browser_dbg-expressions-error.js]
[browser_dbg-expressions-focus.js]

View File

@ -53,6 +53,10 @@ support-files =
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/shared-redux-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
# This is far from ideal. https://bugzilla.mozilla.org/show_bug.cgi?id=1565279
# covers removing this pref flip.
prefs =
security.allow_unsafe_parent_loads=true
[browser_about-devtools-toolbox_load.js]
[browser_about-devtools-toolbox_reload.js]

View File

@ -12,12 +12,6 @@ Services.scriptloader.loadSubScript(
const EventEmitter = require("devtools/shared/event-emitter");
// This is far from ideal. https://bugzilla.mozilla.org/show_bug.cgi?id=1565279
// covers removing this pref flip.
SpecialPowers.pushPrefEnv({
set: [["security.allow_unsafe_parent_loads", true]],
});
function toggleAllTools(state) {
for (const [, tool] of gDevTools._tools) {
if (!tool.visibilityswitch) {

View File

@ -8,20 +8,20 @@ const TEST_JSON_URL = URL_ROOT + "valid_json.json";
add_task(async function() {
info("Test JSON theme started.");
const oldPref = SpecialPowers.getCharPref("devtools.theme");
SpecialPowers.setCharPref("devtools.theme", "light");
const oldPref = Services.prefs.getCharPref("devtools.theme");
Services.prefs.setCharPref("devtools.theme", "light");
await addJsonViewTab(TEST_JSON_URL);
is(await getTheme(), "theme-light", "The initial theme is light");
SpecialPowers.setCharPref("devtools.theme", "dark");
Services.prefs.setCharPref("devtools.theme", "dark");
is(await getTheme(), "theme-dark", "Theme changed to dark");
SpecialPowers.setCharPref("devtools.theme", "light");
Services.prefs.setCharPref("devtools.theme", "light");
is(await getTheme(), "theme-light", "Theme changed to light");
SpecialPowers.setCharPref("devtools.theme", oldPref);
Services.prefs.setCharPref("devtools.theme", oldPref);
});
function getTheme() {

View File

@ -8,7 +8,6 @@
onload="setTimeout(runTests, 0);"
title="bug 293235 test">
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>

View File

@ -8,7 +8,6 @@
onload="setTimeout(nextTest, 0);"
title="bug 396649 test">
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

View File

@ -9,7 +9,6 @@
title="bug 89419 test">
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src="docshell_helpers.js" />
<script src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>

View File

@ -73,11 +73,11 @@ callback interface MozObserverCallback {
};
/**
* WebIDL callback interface calling the `willDestroy` and `didDestroy`
* method on JSWindowActors.
* WebIDL callback interface calling the `willDestroy`, `didDestroy`, and
* `actorCreated` methods on JSWindowActors.
*/
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
callback MozActorDestroyCallback = void();
callback MozJSWindowActorCallback = void();
/**
* The willDestroy method, if present, will be called at the last opportunity
@ -85,13 +85,16 @@ callback MozActorDestroyCallback = void();
* up and send final messages.
* The didDestroy method, if present, will be called after the actor is no
* longer able to receive any more messages.
* The actorCreated method, if present, will be called immediately after the
* actor has been created and initialized.
*
* NOTE: Messages may be received between willDestroy and didDestroy, but they
* may not be sent.
*/
dictionary MozActorDestroyCallbacks {
[ChromeOnly] MozActorDestroyCallback willDestroy;
[ChromeOnly] MozActorDestroyCallback didDestroy;
dictionary MozJSWindowActorCallbacks {
[ChromeOnly] MozJSWindowActorCallback willDestroy;
[ChromeOnly] MozJSWindowActorCallback didDestroy;
[ChromeOnly] MozJSWindowActorCallback actorCreated;
};
/**

View File

@ -144,6 +144,11 @@ If you register your Actor to listen for ``nsIObserver`` notifications, implemen
If you register your Actor to listen for content events, implement a ``handleEvent`` method with the above signature to handle the event.
``actorCreated``
````````````````
This method is called immediately after a child actor is created and initialized. Unlike the actor's constructor, it is possible to do things like access the actor's content window and send messages from this callback.
``willDestroy``
```````````````

View File

@ -38,17 +38,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(JSWindowActor)
JSWindowActor::JSWindowActor() : mNextQueryId(0) {}
void JSWindowActor::StartDestroy() {
DestroyCallback(DestroyCallbackFunction::WillDestroy);
InvokeCallback(CallbackFunction::WillDestroy);
}
void JSWindowActor::AfterDestroy() {
DestroyCallback(DestroyCallbackFunction::DidDestroy);
InvokeCallback(CallbackFunction::DidDestroy);
}
void JSWindowActor::DestroyCallback(DestroyCallbackFunction callback) {
void JSWindowActor::InvokeCallback(CallbackFunction callback) {
AutoEntryScript aes(GetParentObject(), "JSWindowActor destroy callback");
JSContext* cx = aes.cx();
MozActorDestroyCallbacks callbacksHolder;
MozJSWindowActorCallbacks callbacksHolder;
NS_ENSURE_TRUE_VOID(GetWrapper());
JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*GetWrapper()));
if (NS_WARN_IF(!callbacksHolder.Init(cx, val))) {
@ -56,14 +56,18 @@ void JSWindowActor::DestroyCallback(DestroyCallbackFunction callback) {
}
// Destroy callback is optional.
if (callback == DestroyCallbackFunction::WillDestroy) {
if (callback == CallbackFunction::WillDestroy) {
if (callbacksHolder.mWillDestroy.WasPassed()) {
callbacksHolder.mWillDestroy.Value()->Call(this);
}
} else {
} else if (callback == CallbackFunction::DidDestroy) {
if (callbacksHolder.mDidDestroy.WasPassed()) {
callbacksHolder.mDidDestroy.Value()->Call(this);
}
} else {
if (callbacksHolder.mActorCreated.WasPassed()) {
callbacksHolder.mActorCreated.Value()->Call(this);
}
}
}

View File

@ -39,7 +39,7 @@ class JSWindowActor : public nsISupports, public nsWrapperCache {
JSWindowActor();
enum class Type { Parent, Child };
enum class DestroyCallbackFunction { WillDestroy, DidDestroy };
enum class CallbackFunction { WillDestroy, DidDestroy, ActorCreated };
const nsString& Name() const { return mName; }
@ -76,7 +76,7 @@ class JSWindowActor : public nsISupports, public nsWrapperCache {
void AfterDestroy();
void DestroyCallback(DestroyCallbackFunction willDestroy);
void InvokeCallback(CallbackFunction willDestroy);
private:
void ReceiveMessageOrQuery(JSContext* aCx,

View File

@ -35,6 +35,8 @@ void JSWindowActorChild::Init(const nsAString& aName,
MOZ_ASSERT(!mManager, "Cannot Init() a JSWindowActorChild twice!");
SetName(aName);
mManager = aManager;
InvokeCallback(CallbackFunction::ActorCreated);
}
namespace {

View File

@ -81,9 +81,9 @@ function startTests() {
async function mozBrowserTests(browser) {
info("Granting special powers for mozbrowser");
SpecialPowers.addPermission("browser", true, TEST_URI);
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
SpecialPowers.setBoolPref("network.disable.ipc.security", true);
await SpecialPowers.addPermission("browser", true, TEST_URI);
Services.prefs.setBoolPref("dom.mozBrowserFramesEnabled", true);
Services.prefs.setBoolPref("network.disable.ipc.security", true);
await ContentTask.spawn(browser, null, function() {
info("Checking mozbrowser iframe");
@ -103,7 +103,7 @@ async function mozBrowserTests(browser) {
});
info("Revoking special powers for mozbrowser");
SpecialPowers.clearUserPref("dom.mozBrowserFramesEnabled");
SpecialPowers.clearUserPref("network.disable.ipc.security");
SpecialPowers.removePermission("browser", TEST_URI);
Services.prefs.clearUserPref("dom.mozBrowserFramesEnabled");
Services.prefs.clearUserPref("network.disable.ipc.security");
await SpecialPowers.removePermission("browser", TEST_URI);
}

View File

@ -394,11 +394,11 @@ clang-7:
revision: d0d8eb2e5415b8be29343e3c17a18e49e67b5551
clang-8:
description: clang 8 source code
description: clang 8.0.1 source code
fetch:
type: git
repo: https://github.com/llvm/llvm-project
revision: d2298e74235598f15594fe2c99bbac870a507c59
revision: 19a71f6bdf2dddb10764939e7f0ec2b98dba76c9
ninja:
description: ninja 1.9.0

View File

@ -457,11 +457,12 @@ function Tester(aTests, structuredLogger, aCallback) {
this.cpowEventUtils
);
// Make sure our SpecialPowers actor is instantiated, in case it was
// registered after our DOMWindowCreated event was fired (which it
// most likely was).
window.getWindowGlobalChild().getActor("SpecialPowers");
var simpleTestScope = {};
this._scriptLoader.loadSubScript(
"chrome://mochikit/content/tests/SimpleTest/ChromePowers.js",
simpleTestScope
);
this._scriptLoader.loadSubScript(
"chrome://mochikit/content/tests/SimpleTest/SimpleTest.js",
simpleTestScope
@ -476,6 +477,9 @@ function Tester(aTests, structuredLogger, aCallback) {
);
this.SimpleTest = simpleTestScope.SimpleTest;
window.SpecialPowers.SimpleTest = this.SimpleTest;
window.SpecialPowers.setAsDefaultAssertHandler();
var extensionUtilsScope = {
registerCleanupFunction: fn => {
this.currentTest.scope.registerCleanupFunction(fn);

View File

@ -47,7 +47,6 @@ FINAL_TARGET_FILES.content.tests.SimpleTest += [
'../../docshell/test/chrome/docshell_helpers.js',
'../modules/StructuredLog.jsm',
'tests/SimpleTest/AsyncUtilsContent.js',
'tests/SimpleTest/ChromePowers.js',
'tests/SimpleTest/EventUtils.js',
'tests/SimpleTest/ExtensionTestUtils.js',
'tests/SimpleTest/iframe-between-tests.html',

View File

@ -37,8 +37,11 @@ async function interceptDiagnostics(func) {
}
add_task(async function() {
const frameSrc = "https://example.com/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
const subframeSrc = "https://example.org/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
let frame = document.getElementById("iframe");
frame.src = "https://example.com/tests/testing/mochitest/tests/Harness_sanity/file_spawn.html";
frame.src = frameSrc;
await new Promise(resolve => {
frame.addEventListener("load", resolve, {once: true});
@ -59,13 +62,31 @@ add_task(async function() {
// just need to make sure that the general functionality works as expected.
let tests = {
"SpecialPowers.spawn": () => {
return SpecialPowers.spawn(frame, [], () => {
return SpecialPowers.spawn(frame, [], async () => {
Assert.equal(1, 2, "Thing");
Assert.equal(1, 1, "Hmm");
Assert.ok(true, "Yay.");
Assert.ok(false, "Boo!.");
});
},
"SpecialPowers.spawn-subframe": () => {
return SpecialPowers.spawn(frame, [subframeSrc], async src => {
let frame = this.content.document.createElement("iframe");
frame.src = src;
this.content.document.body.appendChild(frame);
await new Promise(resolve => {
frame.addEventListener("load", resolve, { once: true });
});
await SpecialPowers.spawn(frame, [], () => {
Assert.equal(1, 2, "Thing");
Assert.equal(1, 1, "Hmm");
Assert.ok(true, "Yay.");
Assert.ok(false, "Boo!.");
});
});
},
"SpecialPowers.loadChromeScript": async () => {
let script = SpecialPowers.loadChromeScript(() => {
this.addMessageListener("ping", () => "pong");

View File

@ -1,120 +0,0 @@
/* 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/. */
const {SpecialPowersAPI, bindDOMWindowUtils} = ChromeUtils.import("resource://specialpowers/SpecialPowersAPI.jsm");
const {SpecialPowersAPIParent} = ChromeUtils.import("resource://specialpowers/SpecialPowersAPIParent.jsm");
class ChromePowers extends SpecialPowersAPI {
constructor(window) {
super();
this.window = Cu.getWeakReference(window);
this.chromeWindow = window;
this.DOMWindowUtils = bindDOMWindowUtils(window);
this.parentActor = new SpecialPowersAPIParent();
this.parentActor.sendAsyncMessage = this.sendReply.bind(this);
this.listeners = new Map();
}
toString() { return "[ChromePowers]"; }
sanityCheck() { return "foo"; }
get contentWindow() {
return window;
}
get document() {
return window.document;
}
get docShell() {
return window.docShell;
}
sendReply(aType, aMsg) {
var msg = {name: aType, json: aMsg, data: aMsg};
if (!this.listeners.has(aType)) {
throw new Error(`No listener for ${aType}`);
}
this.listeners.get(aType)(msg);
}
sendAsyncMessage(aType, aMsg) {
var msg = {name: aType, json: aMsg, data: aMsg};
this.receiveMessage(msg);
}
async sendQuery(aType, aMsg) {
var msg = {name: aType, json: aMsg, data: aMsg};
return this.receiveMessage(msg);
}
_addMessageListener(aType, aCallback) {
if (this.listeners.has(aType)) {
throw new Error(`unable to handle multiple listeners for ${aType}`);
}
this.listeners.set(aType, aCallback);
}
_removeMessageListener(aType, aCallback) {
this.listeners.delete(aType);
}
registerProcessCrashObservers() {
this._sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
}
unregisterProcessCrashObservers() {
this._sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
}
receiveMessage(aMessage) {
switch (aMessage.name) {
case "SpecialPowers.Quit":
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eForceQuit);
break;
case "SPProcessCrashService":
if (aMessage.json.op == "register-observer" || aMessage.json.op == "unregister-observer") {
// Hack out register/unregister specifically for browser-chrome leaks
break;
}
default:
// All calls go here, because we need to handle SPProcessCrashService calls as well
return this.parentActor.receiveMessage(aMessage);
}
return undefined;
}
quit() {
// We come in here as SpecialPowers.quit, but SpecialPowers is really ChromePowers.
// For some reason this.<func> resolves to TestRunner, so using SpecialPowers
// allows us to use the ChromePowers object which we defined below.
SpecialPowers._sendSyncMessage("SpecialPowers.Quit", {});
}
focus(aWindow) {
// We come in here as SpecialPowers.focus, but SpecialPowers is really ChromePowers.
// For some reason this.<func> resolves to TestRunner, so using SpecialPowers
// allows us to use the ChromePowers object which we defined below.
if (aWindow)
aWindow.focus();
}
executeAfterFlushingMessageQueue(aCallback) {
aCallback();
}
}
if (window.parent.SpecialPowers && !window.SpecialPowers) {
window.SpecialPowers = window.parent.SpecialPowers;
} else {
ChromeUtils.import("resource://specialpowers/SpecialPowersAPIParent.jsm", this);
window.SpecialPowers = new ChromePowers(window);
}

View File

@ -228,6 +228,8 @@ SimpleTest._inChaosMode = false;
SimpleTest.expected = 'pass';
SimpleTest.num_failed = 0;
SpecialPowers.setAsDefaultAssertHandler();
function usesFailurePatterns() {
return Array.isArray(SimpleTest.expected);
}

View File

@ -35,6 +35,7 @@ this.specialpowers = class extends ExtensionAPI {
ChromeUtils.registerWindowActor("SpecialPowers", {
allFrames: true,
includeChrome: true,
child: {
moduleURI: "resource://specialpowers/SpecialPowersChild.jsm",
events: {

File diff suppressed because it is too large Load Diff

View File

@ -1,926 +0,0 @@
/* 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/. */
"use strict";
var EXPORTED_SYMBOLS = ["SpecialPowersAPIParent", "SpecialPowersError"];
var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionData: "resource://gre/modules/Extension.jsm",
ExtensionTestCommon: "resource://testing-common/ExtensionTestCommon.jsm",
PerTestCoverageUtils: "resource://testing-common/PerTestCoverageUtils.jsm",
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
SpecialPowersSandbox: "resource://specialpowers/SpecialPowersSandbox.jsm",
HiddenFrame: "resource://gre/modules/HiddenFrame.jsm",
});
class SpecialPowersError extends Error {
get name() {
return "SpecialPowersError";
}
}
function parseKeyValuePairs(text) {
var lines = text.split("\n");
var data = {};
for (let i = 0; i < lines.length; i++) {
if (lines[i] == "") {
continue;
}
// can't just .split() because the value might contain = characters
let eq = lines[i].indexOf("=");
if (eq != -1) {
let [key, value] = [
lines[i].substring(0, eq),
lines[i].substring(eq + 1),
];
if (key && value) {
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
}
}
}
return data;
}
function parseKeyValuePairsFromFile(file) {
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
Ci.nsIFileInputStream
);
fstream.init(file, -1, 0, 0);
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(
Ci.nsIConverterInputStream
);
is.init(
fstream,
"UTF-8",
1024,
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER
);
var str = {};
var contents = "";
while (is.readString(4096, str) != 0) {
contents += str.value;
}
is.close();
fstream.close();
return parseKeyValuePairs(contents);
}
function getTestPlugin(pluginName) {
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var tags = ph.getPluginTags();
var name = pluginName || "Test Plug-in";
for (var tag of tags) {
if (tag.name == name) {
return tag;
}
}
return null;
}
const PREF_TYPES = {
[Ci.nsIPrefBranch.PREF_INVALID]: "INVALID",
[Ci.nsIPrefBranch.PREF_INT]: "INT",
[Ci.nsIPrefBranch.PREF_BOOL]: "BOOL",
[Ci.nsIPrefBranch.PREF_STRING]: "CHAR",
number: "INT",
boolean: "BOOL",
string: "CHAR",
};
// We share a single preference environment stack between all
// SpecialPowers instances, across all processes.
let prefUndoStack = [];
let inPrefEnvOp = false;
function doPrefEnvOp(fn) {
if (inPrefEnvOp) {
throw new Error(
"Reentrant preference environment operations not supported"
);
}
inPrefEnvOp = true;
try {
return fn();
} finally {
inPrefEnvOp = false;
}
}
// Supplies the unique IDs for tasks created by SpecialPowers.spawn(),
// used to bounce assertion messages back down to the correct child.
let nextTaskID = 1;
class SpecialPowersAPIParent extends JSWindowActorParent {
constructor() {
super();
this._crashDumpDir = null;
this._processCrashObserversRegistered = false;
this._chromeScriptListeners = [];
this._extensions = new Map();
this._taskActors = new Map();
}
_observe(aSubject, aTopic, aData) {
function addDumpIDToMessage(propertyName) {
try {
var id = aSubject.getPropertyAsAString(propertyName);
} catch (ex) {
id = null;
}
if (id) {
message.dumpIDs.push({ id, extension: "dmp" });
message.dumpIDs.push({ id, extension: "extra" });
}
}
switch (aTopic) {
case "plugin-crashed":
case "ipc:content-shutdown":
var message = { type: "crash-observed", dumpIDs: [] };
aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
if (aTopic == "plugin-crashed") {
addDumpIDToMessage("pluginDumpID");
addDumpIDToMessage("browserDumpID");
let pluginID = aSubject.getPropertyAsAString("pluginDumpID");
let extra = this._getExtraData(pluginID);
if (extra && "additional_minidumps" in extra) {
let dumpNames = extra.additional_minidumps.split(",");
for (let name of dumpNames) {
message.dumpIDs.push({
id: pluginID + "-" + name,
extension: "dmp",
});
}
}
} else {
// ipc:content-shutdown
if (!aSubject.hasKey("abnormal")) {
return; // This is a normal shutdown, ignore it
}
addDumpIDToMessage("dumpID");
}
this.sendAsyncMessage("SPProcessCrashService", message);
break;
}
}
_getCrashDumpDir() {
if (!this._crashDumpDir) {
this._crashDumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
this._crashDumpDir.append("minidumps");
}
return this._crashDumpDir;
}
_getPendingCrashDumpDir() {
if (!this._pendingCrashDumpDir) {
this._pendingCrashDumpDir = Services.dirsvc.get("UAppData", Ci.nsIFile);
this._pendingCrashDumpDir.append("Crash Reports");
this._pendingCrashDumpDir.append("pending");
}
return this._pendingCrashDumpDir;
}
_getExtraData(dumpId) {
let extraFile = this._getCrashDumpDir().clone();
extraFile.append(dumpId + ".extra");
if (!extraFile.exists()) {
return null;
}
return parseKeyValuePairsFromFile(extraFile);
}
_deleteCrashDumpFiles(aFilenames) {
var crashDumpDir = this._getCrashDumpDir();
if (!crashDumpDir.exists()) {
return false;
}
var success = aFilenames.length != 0;
aFilenames.forEach(function(crashFilename) {
var file = crashDumpDir.clone();
file.append(crashFilename);
if (file.exists()) {
file.remove(false);
} else {
success = false;
}
});
return success;
}
_findCrashDumpFiles(aToIgnore) {
var crashDumpDir = this._getCrashDumpDir();
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
if (!entries) {
return [];
}
var crashDumpFiles = [];
while (entries.hasMoreElements()) {
var file = entries.nextFile;
var path = String(file.path);
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
crashDumpFiles.push(path);
}
}
return crashDumpFiles.concat();
}
_deletePendingCrashDumpFiles() {
var crashDumpDir = this._getPendingCrashDumpDir();
var removed = false;
if (crashDumpDir.exists()) {
let entries = crashDumpDir.directoryEntries;
while (entries.hasMoreElements()) {
let file = entries.nextFile;
if (file.isFile()) {
file.remove(false);
removed = true;
}
}
}
return removed;
}
_getURI(url) {
return Services.io.newURI(url);
}
_notifyCategoryAndObservers(subject, topic, data) {
const serviceMarker = "service,";
// First create observers from the category manager.
let observers = [];
for (let { value: contractID } of Services.catMan.enumerateCategory(
topic
)) {
let factoryFunction;
if (contractID.substring(0, serviceMarker.length) == serviceMarker) {
contractID = contractID.substring(serviceMarker.length);
factoryFunction = "getService";
} else {
factoryFunction = "createInstance";
}
try {
let handler = Cc[contractID][factoryFunction]();
if (handler) {
let observer = handler.QueryInterface(Ci.nsIObserver);
observers.push(observer);
}
} catch (e) {}
}
// Next enumerate the registered observers.
for (let observer of Services.obs.enumerateObservers(topic)) {
if (observer instanceof Ci.nsIObserver && !observers.includes(observer)) {
observers.push(observer);
}
}
observers.forEach(function(observer) {
try {
observer.observe(subject, topic, data);
} catch (e) {}
});
}
/*
Iterate through one atomic set of pref actions and perform sets/clears as appropriate.
All actions performed must modify the relevant pref.
*/
_applyPrefs(actions) {
for (let pref of actions) {
if (pref.action == "set") {
this._setPref(pref.name, pref.type, pref.value, pref.iid);
} else if (pref.action == "clear") {
Services.prefs.clearUserPref(pref.name);
}
}
}
/**
* Take in a list of pref changes to make, pushes their current values
* onto the restore stack, and makes the changes. When the test
* finishes, these changes are reverted.
*
* |inPrefs| must be an object with up to two properties: "set" and "clear".
* pushPrefEnv will set prefs as indicated in |inPrefs.set| and will unset
* the prefs indicated in |inPrefs.clear|.
*
* For example, you might pass |inPrefs| as:
*
* inPrefs = {'set': [['foo.bar', 2], ['magic.pref', 'baz']],
* 'clear': [['clear.this'], ['also.this']] };
*
* Notice that |set| and |clear| are both an array of arrays. In |set|, each
* of the inner arrays must have the form [pref_name, value] or [pref_name,
* value, iid]. (The latter form is used for prefs with "complex" values.)
*
* In |clear|, each inner array should have the form [pref_name].
*
* If you set the same pref more than once (or both set and clear a pref),
* the behavior of this method is undefined.
*/
pushPrefEnv(inPrefs) {
return doPrefEnvOp(() => {
let pendingActions = [];
let cleanupActions = [];
for (let [action, prefs] of Object.entries(inPrefs)) {
for (let pref of prefs) {
let name = pref[0];
let value = null;
let iid = null;
let type = PREF_TYPES[Services.prefs.getPrefType(name)];
let originalValue = null;
if (pref.length == 3) {
value = pref[1];
iid = pref[2];
} else if (pref.length == 2) {
value = pref[1];
}
/* If pref is not found or invalid it doesn't exist. */
if (type !== "INVALID") {
if (
(Services.prefs.prefHasUserValue(name) && action == "clear") ||
action == "set"
) {
originalValue = this._getPref(name, type);
}
} else if (action == "set") {
/* name doesn't exist, so 'clear' is pointless */
if (iid) {
type = "COMPLEX";
}
}
if (type === "INVALID") {
type = PREF_TYPES[typeof value];
}
if (type === "INVALID") {
throw new Error("Unexpected preference type");
}
pendingActions.push({ action, type, name, value, iid });
/* Push original preference value or clear into cleanup array */
var cleanupTodo = { type, name, value: originalValue, iid };
if (originalValue == null) {
cleanupTodo.action = "clear";
} else {
cleanupTodo.action = "set";
}
cleanupActions.push(cleanupTodo);
}
}
prefUndoStack.push(cleanupActions);
this._applyPrefs(pendingActions);
});
}
async popPrefEnv() {
return doPrefEnvOp(() => {
let env = prefUndoStack.pop();
if (env) {
this._applyPrefs(env);
return true;
}
return false;
});
}
flushPrefEnv() {
while (prefUndoStack.length) {
this.popPrefEnv();
}
}
_setPref(name, type, value, iid) {
switch (type) {
case "BOOL":
return Services.prefs.setBoolPref(name, value);
case "INT":
return Services.prefs.setIntPref(name, value);
case "CHAR":
return Services.prefs.setCharPref(name, value);
case "COMPLEX":
return Services.prefs.setComplexValue(name, iid, value);
}
throw new Error(`Unexpected preference type: ${type}`);
}
_getPref(name, type, defaultValue, iid) {
switch (type) {
case "BOOL":
if (defaultValue !== undefined) {
return Services.prefs.getBoolPref(name, defaultValue);
}
return Services.prefs.getBoolPref(name);
case "INT":
if (defaultValue !== undefined) {
return Services.prefs.getIntPref(name, defaultValue);
}
return Services.prefs.getIntPref(name);
case "CHAR":
if (defaultValue !== undefined) {
return Services.prefs.getCharPref(name, defaultValue);
}
return Services.prefs.getCharPref(name);
case "COMPLEX":
return Services.prefs.getComplexValue(name, iid);
}
throw new Error(`Unexpected preference type: ${type}`);
}
_toggleMuteAudio(aMuted) {
let browser = this.browsingContext.top.embedderElement;
if (aMuted) {
browser.mute();
} else {
browser.unmute();
}
}
/**
* messageManager callback function
* This will get requests from our API in the window and process them in chrome for it
**/
// eslint-disable-next-line complexity
receiveMessage(aMessage) {
// We explicitly return values in the below code so that this function
// doesn't trigger a flurry of warnings about "does not always return
// a value".
switch (aMessage.name) {
case "SPToggleMuteAudio":
return this._toggleMuteAudio(aMessage.data.mute);
case "PushPrefEnv":
return this.pushPrefEnv(aMessage.data);
case "PopPrefEnv":
return this.popPrefEnv();
case "FlushPrefEnv":
return this.flushPrefEnv();
case "SPPrefService": {
let prefs = Services.prefs;
let prefType = aMessage.json.prefType.toUpperCase();
let { prefName, prefValue, iid, defaultValue } = aMessage.json;
if (aMessage.json.op == "get") {
if (!prefName || !prefType) {
throw new SpecialPowersError(
"Invalid parameters for get in SPPrefService"
);
}
// return null if the pref doesn't exist
if (
defaultValue === undefined &&
prefs.getPrefType(prefName) == prefs.PREF_INVALID
) {
return null;
}
return this._getPref(prefName, prefType, defaultValue, iid);
} else if (aMessage.json.op == "set") {
if (!prefName || !prefType || prefValue === undefined) {
throw new SpecialPowersError(
"Invalid parameters for set in SPPrefService"
);
}
return this._setPref(prefName, prefType, prefValue, iid);
} else if (aMessage.json.op == "clear") {
if (!prefName) {
throw new SpecialPowersError(
"Invalid parameters for clear in SPPrefService"
);
}
prefs.clearUserPref(prefName);
} else {
throw new SpecialPowersError("Invalid operation for SPPrefService");
}
return undefined; // See comment at the beginning of this function.
}
case "SPProcessCrashService": {
switch (aMessage.json.op) {
case "register-observer":
this._addProcessCrashObservers();
break;
case "unregister-observer":
this._removeProcessCrashObservers();
break;
case "delete-crash-dump-files":
return this._deleteCrashDumpFiles(aMessage.json.filenames);
case "find-crash-dump-files":
return this._findCrashDumpFiles(
aMessage.json.crashDumpFilesToIgnore
);
case "delete-pending-crash-dump-files":
return this._deletePendingCrashDumpFiles();
default:
throw new SpecialPowersError(
"Invalid operation for SPProcessCrashService"
);
}
return undefined; // See comment at the beginning of this function.
}
case "SPProcessCrashManagerWait": {
let promises = aMessage.json.crashIds.map(crashId => {
return Services.crashmanager.ensureCrashIsPresent(crashId);
});
return Promise.all(promises);
}
case "SPPermissionManager": {
let msg = aMessage.json;
let principal = msg.principal;
switch (msg.op) {
case "add":
Services.perms.addFromPrincipal(
principal,
msg.type,
msg.permission,
msg.expireType,
msg.expireTime
);
break;
case "remove":
Services.perms.removeFromPrincipal(principal, msg.type);
break;
case "has":
let hasPerm = Services.perms.testPermissionFromPrincipal(
principal,
msg.type
);
return hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
case "test":
let testPerm = Services.perms.testPermissionFromPrincipal(
principal,
msg.type
);
return testPerm == msg.value;
default:
throw new SpecialPowersError(
"Invalid operation for SPPermissionManager"
);
}
return undefined; // See comment at the beginning of this function.
}
case "SPSetTestPluginEnabledState": {
var plugin = getTestPlugin(aMessage.data.pluginName);
if (!plugin) {
return undefined;
}
var oldEnabledState = plugin.enabledState;
plugin.enabledState = aMessage.data.newEnabledState;
return oldEnabledState;
}
case "SPObserverService": {
let topic = aMessage.json.observerTopic;
switch (aMessage.json.op) {
case "notify":
let data = aMessage.json.observerData;
Services.obs.notifyObservers(null, topic, data);
break;
case "add":
this._registerObservers._add(topic);
break;
default:
throw new SpecialPowersError(
"Invalid operation for SPObserverervice"
);
}
return undefined; // See comment at the beginning of this function.
}
case "SPLoadChromeScript": {
let id = aMessage.json.id;
let scriptName;
let jsScript = aMessage.json.function.body;
if (aMessage.json.url) {
scriptName = aMessage.json.url;
} else if (aMessage.json.function) {
scriptName =
aMessage.json.function.name ||
"<loadChromeScript anonymous function>";
} else {
throw new SpecialPowersError("SPLoadChromeScript: Invalid script");
}
// Setup a chrome sandbox that has access to sendAsyncMessage
// and {add,remove}MessageListener in order to communicate with
// the mochitest.
let sb = new SpecialPowersSandbox(
scriptName,
data => {
this.sendAsyncMessage("Assert", data);
},
aMessage.data
);
Object.assign(sb.sandbox, {
sendAsyncMessage: (name, message) => {
this.sendAsyncMessage("SPChromeScriptMessage", {
id,
name,
message,
});
},
addMessageListener: (name, listener) => {
this._chromeScriptListeners.push({ id, name, listener });
},
removeMessageListener: (name, listener) => {
let index = this._chromeScriptListeners.findIndex(function(obj) {
return (
obj.id == id && obj.name == name && obj.listener == listener
);
});
if (index >= 0) {
this._chromeScriptListeners.splice(index, 1);
}
},
actorParent: this.manager,
});
// Evaluate the chrome script
try {
Cu.evalInSandbox(jsScript, sb.sandbox, "1.8", scriptName, 1);
} catch (e) {
throw new SpecialPowersError(
"Error while executing chrome script '" +
scriptName +
"':\n" +
e +
"\n" +
e.fileName +
":" +
e.lineNumber
);
}
return undefined; // See comment at the beginning of this function.
}
case "SPChromeScriptMessage": {
let id = aMessage.json.id;
let name = aMessage.json.name;
let message = aMessage.json.message;
let result;
for (let listener of this._chromeScriptListeners) {
if (listener.name == name && listener.id == id) {
result = listener.listener(message);
}
}
return result;
}
case "SPImportInMainProcess": {
var message = { hadError: false, errorMessage: null };
try {
ChromeUtils.import(aMessage.data);
} catch (e) {
message.hadError = true;
message.errorMessage = e.toString();
}
return message;
}
case "SPCleanUpSTSData": {
let origin = aMessage.data.origin;
let flags = aMessage.data.flags;
let uri = Services.io.newURI(origin);
let sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
sss.resetState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
return undefined;
}
case "SPRequestDumpCoverageCounters": {
return PerTestCoverageUtils.afterTest();
}
case "SPRequestResetCoverageCounters": {
return PerTestCoverageUtils.beforeTest();
}
case "SPCheckServiceWorkers": {
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
Ci.nsIServiceWorkerManager
);
let regs = swm.getAllRegistrations();
// XXX This code is shared with specialpowers.js.
let workers = new Array(regs.length);
for (let i = 0; i < regs.length; ++i) {
let { scope, scriptSpec } = regs.queryElementAt(
i,
Ci.nsIServiceWorkerRegistrationInfo
);
workers[i] = { scope, scriptSpec };
}
return { workers };
}
case "SPLoadExtension": {
let id = aMessage.data.id;
let ext = aMessage.data.ext;
let extension = ExtensionTestCommon.generate(ext);
let resultListener = (...args) => {
this.sendAsyncMessage("SPExtensionMessage", {
id,
type: "testResult",
args,
});
};
let messageListener = (...args) => {
args.shift();
this.sendAsyncMessage("SPExtensionMessage", {
id,
type: "testMessage",
args,
});
};
// Register pass/fail handlers.
extension.on("test-result", resultListener);
extension.on("test-eq", resultListener);
extension.on("test-log", resultListener);
extension.on("test-done", resultListener);
extension.on("test-message", messageListener);
this._extensions.set(id, extension);
return undefined;
}
case "SPStartupExtension": {
let id = aMessage.data.id;
// This is either an Extension, or (if useAddonManager is set) a MockExtension.
let extension = this._extensions.get(id);
extension.on("startup", (eventName, ext) => {
if (!ext) {
// ext is only set by the "startup" event from Extension.jsm.
// Unfortunately ext-backgroundPage.js emits an event with the same
// name, but without the extension object as parameter.
return;
}
// ext is always the "real" Extension object, even when "extension"
// is a MockExtension.
this.sendAsyncMessage("SPExtensionMessage", {
id,
type: "extensionSetId",
args: [ext.id, ext.uuid],
});
});
// Make sure the extension passes the packaging checks when
// they're run on a bare archive rather than a running instance,
// as the add-on manager runs them.
let extensionData = new ExtensionData(extension.rootURI);
return extensionData
.loadManifest()
.then(
() => {
return extensionData.initAllLocales().then(() => {
if (extensionData.errors.length) {
return Promise.reject("Extension contains packaging errors");
}
return undefined;
});
},
() => {
// loadManifest() will throw if we're loading an embedded
// extension, so don't worry about locale errors in that
// case.
}
)
.then(async () => {
// browser tests do not call startup in ExtensionXPCShellUtils or MockExtension,
// in that case we have an ID here and we need to set the override.
if (extension.id) {
await ExtensionTestCommon.setIncognitoOverride(extension);
}
return extension.startup().then(
() => {},
e => {
dump(`Extension startup failed: ${e}\n${e.stack}`);
throw e;
}
);
});
}
case "SPExtensionMessage": {
let id = aMessage.data.id;
let extension = this._extensions.get(id);
extension.testMessage(...aMessage.data.args);
return undefined;
}
case "SPUnloadExtension": {
let id = aMessage.data.id;
let extension = this._extensions.get(id);
this._extensions.delete(id);
return extension.shutdown().then(() => {
return extension._uninstallPromise;
});
}
case "Spawn": {
let { browsingContext, task, args, caller } = aMessage.data;
let spParent = browsingContext.currentWindowGlobal.getActor(
"SpecialPowers"
);
let taskId = nextTaskID++;
spParent._taskActors.set(taskId, this);
return spParent
.sendQuery("Spawn", { task, args, caller, taskId })
.finally(() => {
spParent._taskActors.delete(taskId);
});
}
case "Snapshot": {
let { browsingContext, rect, background } = aMessage.data;
return browsingContext.currentWindowGlobal
.drawSnapshot(rect, 1.0, background)
.then(async image => {
let hiddenFrame = new HiddenFrame();
let win = await hiddenFrame.get();
let canvas = win.document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
let data = ctx.getImageData(0, 0, image.width, image.height);
hiddenFrame.destroy();
return data;
});
}
case "ProxiedAssert": {
let { taskId, data } = aMessage.data;
let actor = this._taskActors.get(taskId);
actor.sendAsyncMessage("Assert", data);
return undefined;
}
case "SPRemoveAllServiceWorkers": {
return ServiceWorkerCleanUp.removeAll();
}
case "SPRemoveServiceWorkerDataForExampleDomain": {
return ServiceWorkerCleanUp.removeFromHost("example.com");
}
case "Wakeup":
return undefined;
default:
throw new SpecialPowersError(
`Unrecognized Special Powers API: ${aMessage.name}`
);
}
// We throw an exception before reaching this explicit return because
// we should never be arriving here anyway.
throw new SpecialPowersError("Unreached code"); // eslint-disable-line no-unreachable
return undefined;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,6 @@ FINAL_TARGET_FILES.content += [
'content/MockColorPicker.jsm',
'content/MockFilePicker.jsm',
'content/MockPermissionPrompt.jsm',
'content/SpecialPowersAPI.jsm',
'content/SpecialPowersAPIParent.jsm',
'content/SpecialPowersChild.jsm',
'content/SpecialPowersParent.jsm',
'content/SpecialPowersSandbox.jsm',