зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1642676 - Add test case to ensure we have test coverage for RemoteWorkerManager LaunchNewContentProcess and RegisterActor methods. r=dom-workers-and-storage-reviewers,asuth
Depends on D61708 Differential Revision: https://phabricator.services.mozilla.com/D63697
This commit is contained in:
Родитель
634a0f15cf
Коммит
a3c0ff4871
|
@ -122,6 +122,18 @@ interface nsIServiceWorkerManagerListener : nsISupports
|
|||
[scriptable, builtinclass, uuid(7404c8e8-4d47-4449-8ed1-47d1261d4e33)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* A testing helper that registers a service worker for testing purpose (e.g. used to test
|
||||
* a remote worker that has to spawn a new process to be launched).
|
||||
* This method can only be used when "dom.serviceWorkers.testing.enabled" is true and
|
||||
* it doesn't support all the registration options (e.g. updateViaCache is set automatically
|
||||
* to "imports").
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
Promise registerForTest(in nsIPrincipal aPrincipal,
|
||||
in AString aScope,
|
||||
in AString aScriptURL);
|
||||
|
||||
/**
|
||||
* Unregister an existing ServiceWorker registration for `aScope`.
|
||||
* It keeps aCallback alive until the operation is concluded.
|
||||
|
|
|
@ -939,6 +939,85 @@ class ResolvePromiseRunnable final : public CancelableRunnable {
|
|||
|
||||
} // namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::RegisterForTest(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aScopeURL,
|
||||
const nsAString& aScriptURL,
|
||||
JSContext* aCx,
|
||||
mozilla::dom::Promise** aPromise) {
|
||||
nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
|
||||
if (NS_WARN_IF(!global)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult erv;
|
||||
RefPtr<Promise> outer = Promise::Create(global, erv);
|
||||
if (NS_WARN_IF(erv.Failed())) {
|
||||
return erv.StealNSResult();
|
||||
}
|
||||
|
||||
if (!StaticPrefs::dom_serviceWorkers_testing_enabled()) {
|
||||
outer->MaybeRejectWithAbortError(
|
||||
"registerForTest only allowed when dom.serviceWorkers.testing.enabled "
|
||||
"is true");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aPrincipal == nullptr) {
|
||||
outer->MaybeRejectWithAbortError("Missing principal");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aScriptURL.IsEmpty()) {
|
||||
outer->MaybeRejectWithAbortError("Missing script url");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aScopeURL.IsEmpty()) {
|
||||
outer->MaybeRejectWithAbortError("Missing scope url");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The ClientType isn't really used here, but ClientType::Window
|
||||
// is the least bad choice since this is happening on the main thread.
|
||||
Maybe<ClientInfo> clientInfo =
|
||||
dom::ClientManager::CreateInfo(ClientType::Window, aPrincipal);
|
||||
|
||||
if (!clientInfo.isSome()) {
|
||||
outer->MaybeRejectWithUnknownError("Error creating clientInfo");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto scope = NS_ConvertUTF16toUTF8(aScopeURL);
|
||||
auto scriptURL = NS_ConvertUTF16toUTF8(aScriptURL);
|
||||
|
||||
auto regPromise = Register(clientInfo.ref(), scope, scriptURL,
|
||||
dom::ServiceWorkerUpdateViaCache::Imports);
|
||||
const RefPtr<ServiceWorkerManager> self(this);
|
||||
const nsCOMPtr<nsIPrincipal> principal(aPrincipal);
|
||||
regPromise->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self, outer, principal,
|
||||
scope](const ServiceWorkerRegistrationDescriptor& regDesc) {
|
||||
RefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
self->GetRegistration(principal, NS_ConvertUTF16toUTF8(scope));
|
||||
if (registration) {
|
||||
outer->MaybeResolve(registration);
|
||||
} else {
|
||||
outer->MaybeRejectWithUnknownError(
|
||||
"Failed to retrieve ServiceWorkerRegistrationInfo");
|
||||
}
|
||||
},
|
||||
[outer](const mozilla::CopyableErrorResult& err) {
|
||||
CopyableErrorResult result(err);
|
||||
outer->MaybeReject(std::move(result));
|
||||
});
|
||||
|
||||
outer.forget(aPromise);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerRegistrationPromise> ServiceWorkerManager::Register(
|
||||
const ClientInfo& aClientInfo, const nsACString& aScopeURL,
|
||||
const nsACString& aScriptURL, ServiceWorkerUpdateViaCache aUpdateViaCache) {
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
const { AddonTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/AddonTestUtils.jsm"
|
||||
);
|
||||
const { createHttpServer } = AddonTestUtils;
|
||||
|
||||
// Force ServiceWorkerRegistrar to init by calling do_get_profile.
|
||||
// (This has to be called before AddonTestUtils.init, because it does
|
||||
// also call do_get_profile internally but it doesn't notify
|
||||
// profile-after-change).
|
||||
do_get_profile(true);
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
|
||||
const server = createHttpServer({
|
||||
hosts: ["localhost", "example.org"],
|
||||
});
|
||||
|
||||
server.registerPathHandler("/sw.js", (request, response) => {
|
||||
info(`/sw.js is being requested: ${JSON.stringify(request)}`);
|
||||
response.setHeader("Content-Type", "application/javascript");
|
||||
response.write("");
|
||||
});
|
||||
|
||||
add_task(async function setup_prefs() {
|
||||
equal(
|
||||
Services.prefs.getBoolPref("browser.tabs.remote.autostart"),
|
||||
true,
|
||||
"e10s is expected to be enabled"
|
||||
);
|
||||
|
||||
// Enable nsIServiceWorkerManager.registerForTest.
|
||||
Services.prefs.setBoolPref("dom.serviceWorkers.testing.enabled", true);
|
||||
|
||||
// Configure prefs to configure example.org as a domain to load
|
||||
// in a privilegedmozilla content child process.
|
||||
Services.prefs.setBoolPref(
|
||||
"browser.tabs.remote.separatePrivilegedMozillaWebContentProcess",
|
||||
true
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"browser.tabs.remote.separatedMozillaDomains",
|
||||
"example.org"
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("dom.serviceWorkers.testing.enabled");
|
||||
Services.prefs.clearUserPref(
|
||||
"browser.tabs.remote.separatePrivilegedMozillaWebContentProcess"
|
||||
);
|
||||
Services.prefs.clearUserPref("browser.tabs.remote.separatedMozillaDomains");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This test installs a ServiceWorker via test API and verify that the install
|
||||
* process spawns a new process. (Normally ServiceWorker installation won't
|
||||
* cause a new content process to be spawned because the call to register must
|
||||
* be coming from within an existing content process, but the registerForTest
|
||||
* API allows us to bypass this restriction.)
|
||||
*
|
||||
* This models the real-world situation of a push notification being received
|
||||
* from the network which results in a ServiceWorker being spawned without their
|
||||
* necessarily being an existing content process to host it (especially under Fission).
|
||||
*/
|
||||
add_task(async function launch_remoteworkers_in_new_processes() {
|
||||
const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
|
||||
const ssm = Services.scriptSecurityManager;
|
||||
|
||||
const initialChildCount = Services.ppmm.childCount;
|
||||
|
||||
// A test service worker that should spawn a regular web content child process.
|
||||
const swRegInfoWeb = await swm.registerForTest(
|
||||
ssm.createContentPrincipal(Services.io.newURI("http://localhost"), {}),
|
||||
"http://localhost/scope",
|
||||
"http://localhost/sw.js"
|
||||
);
|
||||
swRegInfoWeb.QueryInterface(Ci.nsIServiceWorkerRegistrationInfo);
|
||||
|
||||
info(
|
||||
`web content service worker registered: ${JSON.stringify({
|
||||
principal: swRegInfoWeb.principal.URI.spec,
|
||||
scope: swRegInfoWeb.scope,
|
||||
})}`
|
||||
);
|
||||
|
||||
// A test service worker that should spawn a privilegedmozilla child process.
|
||||
const swRegInfoPriv = await swm.registerForTest(
|
||||
ssm.createContentPrincipal(Services.io.newURI("http://example.org"), {}),
|
||||
"http://example.org/scope",
|
||||
"http://example.org/sw.js"
|
||||
);
|
||||
swRegInfoPriv.QueryInterface(Ci.nsIServiceWorkerRegistrationInfo);
|
||||
|
||||
info(
|
||||
`privilegedmozilla service worker registered: ${JSON.stringify({
|
||||
principal: swRegInfoPriv.principal.URI.spec,
|
||||
scope: swRegInfoPriv.scope,
|
||||
})}`
|
||||
);
|
||||
|
||||
info("Wait new process to be launched");
|
||||
await TestUtils.waitForCondition(() => {
|
||||
return Services.ppmm.childCount - initialChildCount >= 2;
|
||||
}, "wait for a new child processes to be started");
|
||||
|
||||
// Wait both workers to become active to be sure that. besides spawning
|
||||
// the new child processes as expected, the two remote worker have been
|
||||
// able to run successfully (in other word their remote worker data did
|
||||
// pass successfull the IsRemoteTypeAllowed check in RemoteworkerChild).
|
||||
info("Wait for webcontent worker to become active");
|
||||
await TestUtils.waitForCondition(
|
||||
() => swRegInfoPriv.activeWorker,
|
||||
`wait workers for scope ${swRegInfoPriv.scope} to be active`
|
||||
);
|
||||
|
||||
info("Wait for privilegedmozille worker to become active");
|
||||
await TestUtils.waitForCondition(
|
||||
() => swRegInfoPriv.activeWorker,
|
||||
`wait workers for scope ${swRegInfoPriv.scope} to be active`
|
||||
);
|
||||
});
|
|
@ -8,3 +8,12 @@ support-files =
|
|||
|
||||
[test_workers.js]
|
||||
[test_fileReader.js]
|
||||
[test_remoteworker_launch_new_process.js]
|
||||
# The following firefox-appdir make sure that this xpcshell test will run
|
||||
# with e10s enabled (which is needed to make sure that the test case is
|
||||
# going to launch the expected new processes)
|
||||
firefox-appdir = browser
|
||||
# Disable plugin loading to make it rr able to record and replay this test.
|
||||
prefs =
|
||||
plugin.disable=true
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче