зеркало из 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)]
|
[scriptable, builtinclass, uuid(7404c8e8-4d47-4449-8ed1-47d1261d4e33)]
|
||||||
interface nsIServiceWorkerManager : nsISupports
|
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`.
|
* Unregister an existing ServiceWorker registration for `aScope`.
|
||||||
* It keeps aCallback alive until the operation is concluded.
|
* It keeps aCallback alive until the operation is concluded.
|
||||||
|
|
|
@ -939,6 +939,85 @@ class ResolvePromiseRunnable final : public CancelableRunnable {
|
||||||
|
|
||||||
} // namespace
|
} // 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(
|
RefPtr<ServiceWorkerRegistrationPromise> ServiceWorkerManager::Register(
|
||||||
const ClientInfo& aClientInfo, const nsACString& aScopeURL,
|
const ClientInfo& aClientInfo, const nsACString& aScopeURL,
|
||||||
const nsACString& aScriptURL, ServiceWorkerUpdateViaCache aUpdateViaCache) {
|
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_workers.js]
|
||||||
[test_fileReader.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
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче