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:
Luca Greco 2020-06-26 16:05:53 +00:00
Родитель 634a0f15cf
Коммит a3c0ff4871
4 изменённых файлов: 234 добавлений и 0 удалений

Просмотреть файл

@ -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