mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 09:54:42 +00:00
Bug 1713443
- [remote] Support shared global session data that supports BiDi and CDP r=webdriver-reviewers,whimboo,ochameau
Differential Revision: https://phabricator.services.mozilla.com/D127698
This commit is contained in:
parent
7ae4b5ed14
commit
e788f6a08c
@ -30,6 +30,8 @@ remote.jar:
|
||||
content/shared/messagehandler/RootMessageHandler.jsm (shared/messagehandler/RootMessageHandler.jsm)
|
||||
content/shared/messagehandler/RootMessageHandlerRegistry.jsm (shared/messagehandler/RootMessageHandlerRegistry.jsm)
|
||||
content/shared/messagehandler/WindowGlobalMessageHandler.jsm (shared/messagehandler/WindowGlobalMessageHandler.jsm)
|
||||
content/shared/messagehandler/sessiondata/SessionData.jsm (shared/messagehandler/sessiondata/SessionData.jsm)
|
||||
content/shared/messagehandler/sessiondata/SessionDataReader.jsm (shared/messagehandler/sessiondata/SessionDataReader.jsm)
|
||||
content/shared/messagehandler/transports/js-window-actors/MessageHandlerFrameActor.jsm (shared/messagehandler/transports/js-window-actors/MessageHandlerFrameActor.jsm)
|
||||
content/shared/messagehandler/transports/js-window-actors/MessageHandlerFrameChild.jsm (shared/messagehandler/transports/js-window-actors/MessageHandlerFrameChild.jsm)
|
||||
content/shared/messagehandler/transports/js-window-actors/MessageHandlerFrameParent.jsm (shared/messagehandler/transports/js-window-actors/MessageHandlerFrameParent.jsm)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["MessageHandler"];
|
||||
const EXPORTED_SYMBOLS = ["CONTEXT_DESCRIPTOR_TYPES", "MessageHandler"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
@ -20,6 +20,34 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
|
||||
|
||||
/**
|
||||
* A ContextDescriptor object provides information to decide if a broadcast or
|
||||
* a session data item should be applied to a specific MessageHandler context.
|
||||
*
|
||||
* TODO: At the moment we only support one value: { type: "all", id: "all" },
|
||||
* but the format of the ContextDescriptor object is designed to fit more
|
||||
* complex values.
|
||||
* As soon as we start supporting broadcasts targeting only a part of the
|
||||
* context tree, we will add additional context types. This work will begin with
|
||||
* Bug 1725111, where we will support filtering on a single navigable. It will
|
||||
* be later expanded to filter on a worker, a webextension, a process etc...
|
||||
*
|
||||
* @typedef {Object} ContextDescriptor
|
||||
* @property {String} type
|
||||
* The type of context, one of CONTEXT_DESCRIPTOR_TYPES
|
||||
* @property {String=} id
|
||||
* Unique id of a given context for the provided type. Optional for
|
||||
* CONTEXT_DESCRIPTOR_TYPES.ALL, since there is only one context
|
||||
*/
|
||||
|
||||
// Enum of ContextDescriptor types.
|
||||
// TODO: At the moment we only support the type "all", but additional context
|
||||
// types will be added. See comment for the Context type definition.
|
||||
//
|
||||
const CONTEXT_DESCRIPTOR_TYPES = {
|
||||
ALL: "all",
|
||||
};
|
||||
|
||||
/**
|
||||
* MessageHandler instances are dedicated to handle both Commands and Events
|
||||
* to enable automation and introspection for remote control protocols.
|
||||
|
@ -15,6 +15,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
"chrome://remote/content/shared/messagehandler/transports/FrameTransport.jsm",
|
||||
MessageHandler:
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandler.jsm",
|
||||
SessionData:
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionData.jsm",
|
||||
WindowGlobalMessageHandler:
|
||||
"chrome://remote/content/shared/messagehandler/WindowGlobalMessageHandler.jsm",
|
||||
});
|
||||
@ -61,6 +63,16 @@ class RootMessageHandler extends MessageHandler {
|
||||
super(sessionId, null);
|
||||
|
||||
this._frameTransport = new FrameTransport(this);
|
||||
this._sessionData = new SessionData(this);
|
||||
}
|
||||
|
||||
get sessionData() {
|
||||
return this._sessionData;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._sessionData.destroy();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
|
251
remote/shared/messagehandler/sessiondata/SessionData.jsm
Normal file
251
remote/shared/messagehandler/sessiondata/SessionData.jsm
Normal file
@ -0,0 +1,251 @@
|
||||
/* 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 = ["SESSION_DATA_SHARED_DATA_KEY", "SessionData"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
|
||||
CONTEXT_DESCRIPTOR_TYPES:
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandler.jsm",
|
||||
Log: "chrome://remote/content/shared/Log.jsm",
|
||||
RootMessageHandler:
|
||||
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
|
||||
|
||||
const SESSION_DATA_SHARED_DATA_KEY = "MessageHandlerSessionData";
|
||||
|
||||
// This is a map from session id to session data, which will be persisted and
|
||||
// propagated to all processes using Services' sharedData.
|
||||
// We have to store this as a unique object under a unique shared data key
|
||||
// because new MessageHandlers in other processes will need to access this data
|
||||
// without any notion of a specific session.
|
||||
// This is a singleton.
|
||||
const sessionDataMap = new Map();
|
||||
|
||||
/**
|
||||
* @typedef {Object} SessionDataItem
|
||||
* @property {String} moduleName
|
||||
* The name of the module responsible for this data item.
|
||||
* @property {String} category
|
||||
* The category of data. The supported categories depend on the module.
|
||||
* @property {(string|number|boolean)} value
|
||||
* Value of the session data item.
|
||||
* @property {ContextDescriptor} contextDescriptor
|
||||
* ContextDescriptor to which this session data applies
|
||||
*/
|
||||
|
||||
/**
|
||||
* SessionData provides APIs to read and write the session data for a specific
|
||||
* ROOT message handler. It holds the session data as a property and acts as the
|
||||
* source of truth for this session data.
|
||||
*
|
||||
* The session data of a given message handler network should contain all the
|
||||
* information that might be needed to setup new contexts, for instance a list
|
||||
* of subscribed events, a list of breakpoints etc.
|
||||
*
|
||||
* The actual session data is an array of SessionDataItems. Example below:
|
||||
* ```
|
||||
* data: [
|
||||
* {
|
||||
* moduleName: "log",
|
||||
* category: "event",
|
||||
* value: "log.entryAdded",
|
||||
* contextDescriptor: { type: "all" }
|
||||
* },
|
||||
* {
|
||||
* moduleName: "browsingContext",
|
||||
* category: "event",
|
||||
* value: "browsingContext.contextCreated",
|
||||
* contextDescriptor: { type: "browser-element", id: "7"}
|
||||
* },
|
||||
* {
|
||||
* moduleName: "browsingContext",
|
||||
* category: "event",
|
||||
* value: "browsingContext.contextCreated",
|
||||
* contextDescriptor: { type: "browser-element", id: "12"}
|
||||
* },
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* The session data will be persisted using Services.ppmm.sharedData, so that
|
||||
* new contexts living in different processes can also access the information
|
||||
* during their startup.
|
||||
*
|
||||
* This class should only be used from a ROOT MessageHandler, or from modules
|
||||
* owned by a ROOT MessageHandler. Other MessageHandlers should rely on
|
||||
* SessionDataReader's readSessionData to get read-only access to session data.
|
||||
*
|
||||
*/
|
||||
class SessionData {
|
||||
constructor(messageHandler) {
|
||||
if (messageHandler.constructor.type != RootMessageHandler.type) {
|
||||
throw new Error(
|
||||
"SessionData should only be used from a ROOT MessageHandler"
|
||||
);
|
||||
}
|
||||
|
||||
this._messageHandler = messageHandler;
|
||||
|
||||
/*
|
||||
* The actual data for this session. This is an array of SessionDataItems.
|
||||
*/
|
||||
this._data = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new session data items of a given module, category and
|
||||
* contextDescriptor.
|
||||
*
|
||||
* A new SessionDataItem will be created for each value of the values array.
|
||||
*
|
||||
* If a SessionDataItem already exists for the provided value, moduleName,
|
||||
* category and contextDescriptor, it will be skipped to avoid duplicated
|
||||
* SessionDataItems.
|
||||
*
|
||||
* The data will be persisted across processes at the end of this method.
|
||||
*
|
||||
* @param {String} moduleName
|
||||
* The name of the module responsible for this data item.
|
||||
* @param {String} category
|
||||
* The session data category.
|
||||
* @param {ContextDescriptor} contextDescriptor
|
||||
* The contextDescriptor object defining the scope of the session data
|
||||
* values.
|
||||
* @param {Array<(string|number|boolean)>} values
|
||||
* Array of session data item values.
|
||||
*/
|
||||
addSessionData(moduleName, category, contextDescriptor, values) {
|
||||
for (const value of values) {
|
||||
const item = { moduleName, category, contextDescriptor, value };
|
||||
|
||||
const hasItem = this._data.some(_item => this._isSameItem(item, _item));
|
||||
if (!hasItem) {
|
||||
// This is a new data item, create it and add it to the data.
|
||||
this._data.push(item);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Duplicated session data item was not added: ${JSON.stringify(item)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Persist the sessionDataMap.
|
||||
this._persist();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// Update the sessionDataMap singleton.
|
||||
sessionDataMap.delete(this._messageHandler.sessionId);
|
||||
|
||||
// Update sharedData and flush to force consistency.
|
||||
Services.ppmm.sharedData.set(SESSION_DATA_SHARED_DATA_KEY, sessionDataMap);
|
||||
Services.ppmm.sharedData.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the SessionDataItems for a given module and type.
|
||||
*
|
||||
* @param {String} moduleName
|
||||
* The name of the module responsible for this data item.
|
||||
* @param {String} category
|
||||
* The session data category.
|
||||
* @param {ContextDescriptor=} contextDescriptor
|
||||
* Optional context descriptor, to retrieve only session data items added
|
||||
* for a specific context descriptor.
|
||||
* @return {Array<SessionDataItem>}
|
||||
* Array of SessionDataItems for the provided module and type.
|
||||
*/
|
||||
getSessionData(moduleName, category, contextDescriptor) {
|
||||
return this._data.filter(
|
||||
item =>
|
||||
item.moduleName === moduleName &&
|
||||
item.category === category &&
|
||||
(!contextDescriptor ||
|
||||
this._isSameContextDescriptor(
|
||||
item.contextDescriptor,
|
||||
contextDescriptor
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove values for the provided module, category and context.
|
||||
* Values which don't match any existing SessionDataItem will be ignored.
|
||||
*
|
||||
* The updated sessionDataMap will be persisted across processes at the end.
|
||||
*
|
||||
* @param {String} moduleName
|
||||
* The name of the module responsible for this data item.
|
||||
* @param {String} category
|
||||
* The session data category.
|
||||
* @param {ContextDescriptor} contextDescriptor
|
||||
* The contextDescriptor object defining the scope of the session data
|
||||
* values.
|
||||
* @param {Array<(string|number|boolean)>} values
|
||||
* Array of session data item values.
|
||||
*/
|
||||
removeSessionData(moduleName, category, contextDescriptor, values) {
|
||||
// Remove the provided context from the contexts Map of the provided items.
|
||||
for (const value of values) {
|
||||
const item = { moduleName, category, contextDescriptor, value };
|
||||
|
||||
const itemIndex = this._data.findIndex(_item =>
|
||||
this._isSameItem(item, _item)
|
||||
);
|
||||
if (itemIndex != -1) {
|
||||
// The item was found in the session data, remove it.
|
||||
this._data.splice(itemIndex, 1);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Missing session data item was not removed: ${JSON.stringify(item)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Persist the sessionDataMap.
|
||||
this._persist();
|
||||
}
|
||||
|
||||
_isSameItem(item1, item2) {
|
||||
const descriptor1 = item1.contextDescriptor;
|
||||
const descriptor2 = item2.contextDescriptor;
|
||||
|
||||
return (
|
||||
item1.moduleName === item2.moduleName &&
|
||||
item1.category === item2.category &&
|
||||
this._isSameContextDescriptor(descriptor1, descriptor2) &&
|
||||
item1.value === item2.value
|
||||
);
|
||||
}
|
||||
|
||||
_isSameContextDescriptor(contextDescriptor1, contextDescriptor2) {
|
||||
if (contextDescriptor1.type === CONTEXT_DESCRIPTOR_TYPES.ALL) {
|
||||
// Ignore the id for type ALL since we made the id optional for this type.
|
||||
return contextDescriptor1.type === contextDescriptor2.type;
|
||||
}
|
||||
|
||||
return (
|
||||
contextDescriptor1.type === contextDescriptor2.type &&
|
||||
contextDescriptor1.id === contextDescriptor2.id
|
||||
);
|
||||
}
|
||||
|
||||
_persist() {
|
||||
// Update the sessionDataMap singleton.
|
||||
sessionDataMap.set(this._messageHandler.sessionId, this._data);
|
||||
|
||||
// Update sharedData and flush to force consistency.
|
||||
Services.ppmm.sharedData.set(SESSION_DATA_SHARED_DATA_KEY, sessionDataMap);
|
||||
Services.ppmm.sharedData.flush();
|
||||
}
|
||||
}
|
@ -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 = ["readSessionData"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
|
||||
SESSION_DATA_SHARED_DATA_KEY:
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionData.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "sharedData", () => {
|
||||
const isInParent =
|
||||
Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
return isInParent ? Services.ppmm.sharedData : Services.cpmm.sharedData;
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the session data map, which is cloned from the
|
||||
* sessionDataMap singleton of SessionData.jsm.
|
||||
*
|
||||
* @return {Map.<string, Array<SessionDataItem>>}
|
||||
* Map of session id to arrays of SessionDataItems.
|
||||
*/
|
||||
const readSessionData = () =>
|
||||
sharedData.get(SESSION_DATA_SHARED_DATA_KEY) || new Map();
|
@ -11,3 +11,4 @@ prefs =
|
||||
[browser_handle_command_errors.js]
|
||||
[browser_handle_simple_command.js]
|
||||
[browser_registry.js]
|
||||
[browser_session_data.js]
|
||||
|
@ -0,0 +1,183 @@
|
||||
/* 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 { CONTEXT_DESCRIPTOR_TYPES } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandler.jsm"
|
||||
);
|
||||
const { RootMessageHandler } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
|
||||
);
|
||||
const { SessionData } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionData.jsm"
|
||||
);
|
||||
|
||||
const TEST_PAGE = "http://example.com/document-builder.sjs?html=tab";
|
||||
|
||||
add_task(async function test_sessionData() {
|
||||
info("Navigate the initial tab to the test URL");
|
||||
const tab1 = gBrowser.selectedTab;
|
||||
await loadURL(tab1.linkedBrowser, TEST_PAGE);
|
||||
|
||||
const sessionId = "sessionData-test";
|
||||
const contextDescriptorAll = { type: CONTEXT_DESCRIPTOR_TYPES.ALL };
|
||||
|
||||
const rootMessageHandlerRegistry = new MessageHandlerRegistry(
|
||||
RootMessageHandler.type
|
||||
);
|
||||
|
||||
const rootMessageHandler = rootMessageHandlerRegistry.getOrCreateMessageHandler(
|
||||
sessionId
|
||||
);
|
||||
ok(rootMessageHandler, "Valid ROOT MessageHandler created");
|
||||
|
||||
const sessionData = rootMessageHandler.sessionData;
|
||||
ok(
|
||||
sessionData instanceof SessionData,
|
||||
"ROOT MessageHandler has a valid sessionData"
|
||||
);
|
||||
|
||||
let sessionDataSnapshot = await getSessionDataFromContent();
|
||||
is(sessionDataSnapshot.size, 0, "session data is empty");
|
||||
|
||||
info("Store a string value in session data");
|
||||
sessionData.addSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
["value-1"]
|
||||
);
|
||||
|
||||
sessionDataSnapshot = await getSessionDataFromContent();
|
||||
is(sessionDataSnapshot.size, 1, "session data contains 1 session");
|
||||
ok(sessionDataSnapshot.has(sessionId));
|
||||
let snapshot = sessionDataSnapshot.get(sessionId);
|
||||
ok(Array.isArray(snapshot));
|
||||
is(snapshot.length, 1);
|
||||
|
||||
const stringDataItem = snapshot[0];
|
||||
checkSessionDataItem(
|
||||
stringDataItem,
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
"value-1"
|
||||
);
|
||||
|
||||
info("Store a number value in session data");
|
||||
sessionData.addSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
[12]
|
||||
);
|
||||
snapshot = (await getSessionDataFromContent()).get(sessionId);
|
||||
is(snapshot.length, 2);
|
||||
|
||||
const numberDataItem = snapshot[1];
|
||||
checkSessionDataItem(
|
||||
numberDataItem,
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
12
|
||||
);
|
||||
|
||||
info("Store a boolean value in session data");
|
||||
sessionData.addSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
[true]
|
||||
);
|
||||
snapshot = (await getSessionDataFromContent()).get(sessionId);
|
||||
is(snapshot.length, 3);
|
||||
|
||||
const boolDataItem = snapshot[2];
|
||||
checkSessionDataItem(
|
||||
boolDataItem,
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
true
|
||||
);
|
||||
|
||||
info("Remove one value");
|
||||
sessionData.removeSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
[12]
|
||||
);
|
||||
snapshot = (await getSessionDataFromContent()).get(sessionId);
|
||||
is(snapshot.length, 2);
|
||||
checkSessionDataItem(
|
||||
snapshot[0],
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
"value-1"
|
||||
);
|
||||
checkSessionDataItem(
|
||||
snapshot[1],
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
true
|
||||
);
|
||||
|
||||
info("Remove all values");
|
||||
sessionData.removeSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
["value-1", true]
|
||||
);
|
||||
snapshot = (await getSessionDataFromContent()).get(sessionId);
|
||||
is(snapshot.length, 0, "Session data is now empty");
|
||||
|
||||
info("Add another value before destroy");
|
||||
sessionData.addSessionData(
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
contextDescriptorAll,
|
||||
["value-2"]
|
||||
);
|
||||
snapshot = (await getSessionDataFromContent()).get(sessionId);
|
||||
is(snapshot.length, 1);
|
||||
checkSessionDataItem(
|
||||
snapshot[0],
|
||||
"fakemodule",
|
||||
"testCategory",
|
||||
CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
"value-2"
|
||||
);
|
||||
|
||||
sessionData.destroy();
|
||||
sessionDataSnapshot = await getSessionDataFromContent();
|
||||
is(sessionDataSnapshot.size, 0, "session data should be empty again");
|
||||
});
|
||||
|
||||
function checkSessionDataItem(item, moduleName, category, contextType, value) {
|
||||
is(item.moduleName, moduleName, "Data item has the expected module name");
|
||||
is(item.category, category, "Data item has the expected category");
|
||||
is(
|
||||
item.contextDescriptor.type,
|
||||
contextType,
|
||||
"Data item has the expected context type"
|
||||
);
|
||||
is(item.value, value, "Data item has the expected value");
|
||||
}
|
||||
|
||||
function getSessionDataFromContent() {
|
||||
return SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
||||
const { readSessionData } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionDataReader.jsm"
|
||||
);
|
||||
return readSessionData();
|
||||
});
|
||||
}
|
146
remote/shared/messagehandler/test/xpcshell/test_SessionData.js
Normal file
146
remote/shared/messagehandler/test/xpcshell/test_SessionData.js
Normal file
@ -0,0 +1,146 @@
|
||||
/* 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 { CONTEXT_DESCRIPTOR_TYPES } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/MessageHandler.jsm"
|
||||
);
|
||||
const { RootMessageHandler } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/RootMessageHandler.jsm"
|
||||
);
|
||||
const { SessionData } = ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionData.jsm"
|
||||
);
|
||||
|
||||
add_task(async function test_sessionData() {
|
||||
const sessionData = new SessionData(new RootMessageHandler("session-id-1"));
|
||||
equal(sessionData.getSessionData("mod", "event").length, 0);
|
||||
|
||||
const globalContext = {
|
||||
type: CONTEXT_DESCRIPTOR_TYPES.ALL,
|
||||
};
|
||||
const otherContext = { type: "other-type", id: "some-id" };
|
||||
|
||||
info("Add a first event for the global context");
|
||||
sessionData.addSessionData("mod", "event", globalContext, ["first.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Add the exact same data (same module, type, context, value)");
|
||||
sessionData.addSessionData("mod", "event", globalContext, ["first.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Add another context for the same event");
|
||||
sessionData.addSessionData("mod", "event", otherContext, ["first.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: otherContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Add a second event for the global context");
|
||||
sessionData.addSessionData("mod", "event", globalContext, ["second.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: otherContext,
|
||||
},
|
||||
{
|
||||
value: "second.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Add two events for the global context");
|
||||
sessionData.addSessionData("mod", "event", globalContext, [
|
||||
"third.event",
|
||||
"fourth.event",
|
||||
]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: otherContext,
|
||||
},
|
||||
{
|
||||
value: "second.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "third.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "fourth.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Remove the second, third and fourth events");
|
||||
sessionData.removeSessionData("mod", "event", globalContext, [
|
||||
"second.event",
|
||||
"third.event",
|
||||
"fourth.event",
|
||||
]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: globalContext,
|
||||
},
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: otherContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Remove the global context from the first event");
|
||||
sessionData.removeSessionData("mod", "event", globalContext, ["first.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), [
|
||||
{
|
||||
value: "first.event",
|
||||
contextDescriptor: otherContext,
|
||||
},
|
||||
]);
|
||||
|
||||
info("Remove the other context from the first event");
|
||||
sessionData.removeSessionData("mod", "event", otherContext, ["first.event"]);
|
||||
checkEvents(sessionData.getSessionData("mod", "event"), []);
|
||||
});
|
||||
|
||||
function checkEvents(events, expectedEvents) {
|
||||
// Check the arrays have the same size.
|
||||
equal(events.length, expectedEvents.length);
|
||||
|
||||
// Check all the expectedEvents can be found in the events array.
|
||||
for (const expected of expectedEvents) {
|
||||
ok(
|
||||
events.some(
|
||||
event =>
|
||||
expected.contextDescriptor.type === event.contextDescriptor.type &&
|
||||
expected.contextDescriptor.id === event.contextDescriptor.id &&
|
||||
expected.value == event.value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -3,3 +3,4 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[test_Errors.js]
|
||||
[test_SessionData.js]
|
||||
|
@ -10,6 +10,10 @@ const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.import(
|
||||
"chrome://remote/content/shared/messagehandler/sessiondata/SessionDataReader.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
error: "chrome://remote/content/shared/messagehandler/Errors.jsm",
|
||||
MessageHandlerRegistry:
|
||||
|
Loading…
Reference in New Issue
Block a user