Bug 1713439 - [remote] Add mochitests to exercize message-handler API r=webdriver-reviewers,whimboo

Depends on 120083

Differential Revision: https://phabricator.services.mozilla.com/D120084
This commit is contained in:
Julian Descottes 2021-07-30 08:17:49 +00:00
Родитель 24d060cac5
Коммит ee4b6dd666
10 изменённых файлов: 415 добавлений и 1 удалений

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

@ -11,6 +11,8 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
Log: "chrome://remote/content/shared/Log.jsm",
getMessageHandlerClass:
"chrome://remote/content/shared/messagehandler/MessageHandlerRegistry.jsm",
@ -23,6 +25,9 @@ XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
// the protocol owning the MessageHandler. See Bug 1722464.
const MODULES_FOLDER = "chrome://remote/content/webdriver-bidi/modules";
const TEST_MODULES_FOLDER =
"chrome://mochitests/content/browser/remote/shared/messagehandler/test/browser/resources/modules";
/**
* ModuleCache instances are dedicated to lazily create and cache the instances
* of all the modules related to a specific MessageHandler instance.
@ -63,6 +68,19 @@ class ModuleCache {
this.messageHandler = messageHandler;
this._messageHandlerPath = messageHandler.constructor.modulePath;
this._modulesRootFolder = MODULES_FOLDER;
// TODO: Temporary workaround to use a different folder for tests.
// After Bug 1722464 lands, we should be able to set custom root folders
// per session and we can remove this workaround.
if (
Services.prefs.getBoolPref(
"remote.messagehandler.modulecache.useBrowserTestRoot",
false
)
) {
this._modulesRootFolder = TEST_MODULES_FOLDER;
}
// Map of absolute module paths to module instances.
this._modules = new Map();
}
@ -127,6 +145,6 @@ class ModuleCache {
moduleFolder = `${destinationPath}-in-${this._messageHandlerPath}`;
}
return `${MODULES_FOLDER}/${moduleFolder}/${moduleName}.jsm`;
return `${this._modulesRootFolder}/${moduleFolder}/${moduleName}.jsm`;
}
}

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

@ -0,0 +1,11 @@
[DEFAULT]
tags = remote
subsuite = remote
support-files =
head.js
resources/*
prefs =
remote.messagehandler.modulecache.useBrowserTestRoot=true
[browser_handle_simple_command.js]
[browser_registry.js]

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

@ -0,0 +1,205 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { RootMessageHandler } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
);
const { WindowGlobalMessageHandler } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/WindowGlobalMessageHandler.jsm"
);
// Test calling methods only implemented in the root version of a module.
add_task(async function test_rootModule_command() {
const rootMessageHandler = createRootMessageHandler("session-id-rootModule");
const rootValue = await rootMessageHandler.handleCommand({
moduleName: "TestModule",
commandName: "testRootModule",
destination: {
type: RootMessageHandler.type,
},
});
is(
rootValue,
"root-value",
"Retrieved the expected value from testRootModule"
);
rootMessageHandler.destroy();
});
// Test calling methods only implemented in the windowglobal-in-root version of
// a module.
add_task(async function test_windowglobalInRootModule_command() {
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
const rootMessageHandler = createRootMessageHandler(
"session-id-windowglobalInRootModule"
);
const interceptedValue = await rootMessageHandler.handleCommand({
moduleName: "TestModule",
commandName: "testInterceptModule",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
interceptedValue,
"intercepted-value",
"Retrieved the expected value from testInterceptModule"
);
rootMessageHandler.destroy();
});
// Test calling methods only implemented in the windowglobal version of a
// module.
add_task(async function test_windowglobalModule_command() {
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
const rootMessageHandler = createRootMessageHandler(
"session-id-windowglobalModule"
);
const windowGlobalValue = await rootMessageHandler.handleCommand({
moduleName: "TestModule",
commandName: "testWindowGlobalModule",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
windowGlobalValue,
"windowglobal-value",
"Retrieved the expected value from testWindowGlobalModule"
);
rootMessageHandler.destroy();
});
// Test calling a method on a module which is only available in the "windowglobal"
// folder. This will check that the MessageHandler/ModuleCache correctly moves
// on to the next layer when no implementation can be found in the root layer.
add_task(async function test_windowglobalOnlyModule_command() {
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
const rootMessageHandler = createRootMessageHandler(
"session-id-windowglobalOnlyModule"
);
const windowGlobalOnlyValue = await rootMessageHandler.handleCommand({
moduleName: "TestOnlyInWindowGlobalModule",
commandName: "testOnlyInWindowGlobal",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
windowGlobalOnlyValue,
"only-in-windowglobal",
"Retrieved the expected value from testOnlyInWindowGlobal"
);
rootMessageHandler.destroy();
});
// Try to create 2 sessions which will both set values in individual modules
// via a command `testSetValue`, and then retrieve the values via another
// command `testGetValue`.
// This will ensure that different sessions use different module instances.
add_task(async function test_multisession() {
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
const rootMessageHandler1 = createRootMessageHandler(
"session-id-multisession-1"
);
const rootMessageHandler2 = createRootMessageHandler(
"session-id-multisession-2"
);
info("Set value for session 1");
await rootMessageHandler1.handleCommand({
moduleName: "TestModule",
commandName: "testSetValue",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
params: "session1-value",
});
info("Set value for session 2");
await rootMessageHandler2.handleCommand({
moduleName: "TestModule",
commandName: "testSetValue",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
params: "session2-value",
});
const session1Value = await rootMessageHandler1.handleCommand({
moduleName: "TestModule",
commandName: "testGetValue",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
session1Value,
"session1-value",
"Retrieved the expected value for session 1"
);
const session2Value = await rootMessageHandler2.handleCommand({
moduleName: "TestModule",
commandName: "testGetValue",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
session2Value,
"session2-value",
"Retrieved the expected value for session 2"
);
rootMessageHandler1.destroy();
rootMessageHandler2.destroy();
});
// Test calling a method from the windowglobal-in-root module which will
// internally forward to the windowglobal module and will return a composite
// result built both in parent and content process.
add_task(async function test_forwarding_command() {
const browsingContextId = gBrowser.selectedBrowser.browsingContext.id;
const rootMessageHandler = createRootMessageHandler("session-id-forwarding");
const interceptAndForwardValue = await rootMessageHandler.handleCommand({
moduleName: "TestModule",
commandName: "testInterceptAndForwardModule",
destination: {
type: WindowGlobalMessageHandler.type,
id: browsingContextId,
},
});
is(
interceptAndForwardValue,
"intercepted-and-forward+forward-to-windowglobal-value",
"Retrieved the expected value from testInterceptAndForwardModule"
);
rootMessageHandler.destroy();
});

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

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { MessageHandlerRegistry } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/MessageHandlerRegistry.jsm"
);
const { RootMessageHandler } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
);
add_task(async function test_messageHandlerRegistry_API() {
const sessionId = 1;
const type = RootMessageHandler.type;
const rootMessageHandler = MessageHandlerRegistry.getOrCreateMessageHandler(
sessionId,
type
);
ok(rootMessageHandler, "Valid ROOT MessageHandler created");
const contextId = rootMessageHandler.contextId;
ok(contextId, "ROOT MessageHandler has a valid contextId");
is(
rootMessageHandler,
MessageHandlerRegistry.getExistingMessageHandler(
sessionId,
type,
contextId
),
"ROOT MessageHandler can be retrieved from the registry"
);
rootMessageHandler.destroy();
ok(
!MessageHandlerRegistry.getExistingMessageHandler(
sessionId,
type,
contextId
),
"Destroyed ROOT MessageHandler is no longer returned by the Registry"
);
});

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

@ -0,0 +1,18 @@
/* 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";
function createRootMessageHandler(sessionId) {
const { MessageHandlerRegistry } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/MessageHandlerRegistry.jsm"
);
const { RootMessageHandler } = ChromeUtils.import(
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
);
return MessageHandlerRegistry.getOrCreateMessageHandler(
sessionId,
RootMessageHandler.type
);
}

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

@ -0,0 +1,23 @@
/* 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";
const EXPORTED_SYMBOLS = ["TestModule"];
class TestModule {
constructor(messageHandler) {
this.messageHandler = messageHandler;
}
destroy() {}
/**
* Commands
*/
testRootModule() {
return "root-value";
}
}

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

@ -0,0 +1,32 @@
/* 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";
const EXPORTED_SYMBOLS = ["TestModule"];
class TestModule {
constructor(messageHandler) {
this.messageHandler = messageHandler;
}
destroy() {}
/**
* Commands
*/
testInterceptModule() {
return "intercepted-value";
}
async testInterceptAndForwardModule(destination) {
const windowGlobalValue = await this.messageHandler.handleCommand({
moduleName: "TestModule",
commandName: "testForwardToWindowGlobal",
destination,
});
return "intercepted-and-forward+" + windowGlobalValue;
}
}

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

@ -0,0 +1,35 @@
/* 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";
const EXPORTED_SYMBOLS = ["TestModule"];
class TestModule {
constructor(messageHandler) {
this.messageHandler = messageHandler;
}
destroy() {}
/**
* Commands
*/
testWindowGlobalModule() {
return "windowglobal-value";
}
testSetValue(destination, value) {
this._testValue = value;
}
testGetValue() {
return this._testValue;
}
testForwardToWindowGlobal() {
return "forward-to-windowglobal-value";
}
}

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

@ -0,0 +1,23 @@
/* 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";
const EXPORTED_SYMBOLS = ["TestOnlyInWindowGlobalModule"];
class TestOnlyInWindowGlobalModule {
constructor(messageHandler) {
this.messageHandler = messageHandler;
}
destroy() {}
/**
* Commands
*/
testOnlyInWindowGlobal() {
return "only-in-windowglobal";
}
}

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

@ -2,6 +2,10 @@
# 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/.
BROWSER_CHROME_MANIFESTS += [
"messagehandler/test/browser/browser.ini",
]
XPCSHELL_TESTS_MANIFESTS += [
"test/xpcshell/xpcshell.ini",
"webdriver/test/xpcshell/xpcshell.ini",