--- a/testing/marionette/message.js
+++ b/testing/marionette/message.js
@@ -3,81 +3,92 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {utils: Cu} = Components;
Cu.import("chrome://marionette/content/assert.js");
Cu.import("chrome://marionette/content/error.js");
+const {truncate} = Cu.import("chrome://marionette/content/format.js", {});
this.EXPORTED_SYMBOLS = [
"Command",
"Message",
"MessageOrigin",
"Response",
];
+/** Representation of the packets transproted over the wire. */
+class Message {
+ /**
+ * @param {number} messageID
+ * Message ID unique identifying this message.
+ */
+ constructor(messageID) {
+ this.id = assert.integer(messageID);
+ }
+
+ toString() {
+ return truncate`${this.toPacket()}`;
+ }
+
+ /**
+ * Converts a data packet into a {@link Command} or {@link Response}.
+ *
+ * @param {Array.<number, number, ?, ?>} data
+ * A four element array where the elements, in sequence, signifies
+ * message type, message ID, method name or error, and parameters
+ * or result.
+ *
+ * @return {Message}
+ * Based on the message type, a {@link Command} or {@link Response}
+ * instance.
+ *
+ * @throws {TypeError}
+ * If the message type is not recognised.
+ */
+ static fromPacket(data) {
+ const [type] = data;
+
+ switch (type) {
+ case Command.TYPE:
+ return Command.fromPacket(data);
+
+ case Response.TYPE:
+ return Response.fromPacket(data);
+
+ default:
+ throw new TypeError(
+ "Unrecognised message type in packet: " + JSON.stringify(data));
+ }
+ }
+}
+
/**
* Messages may originate from either the server or the client.
* Because the remote protocol is full duplex, both endpoints may be the
* origin of both commands and responses.
*
* @enum
* @see {@link Message}
*/
const MessageOrigin = {
/** Indicates that the message originates from the client. */
Client: 0,
/** Indicates that the message originates from the server. */
Server: 1,
};
/**
- * Representation of the packets transproted over the wire.
- *
- * @class
- */
-this.Message = {};
-
-/**
- * Converts a data packet into a Command or Response type.
- *
- * @param {Array.<number, number, ?, ?>} data
- * A four element array where the elements, in sequence, signifies
- * message type, message ID, method name or error, and parameters
- * or result.
- *
- * @return {Message}
- * Based on the message type, a {@link Command} or {@link Response}
- * instance.
- *
- * @throws {TypeError}
- * If the message type is not recognised.
- */
-Message.fromMsg = function(data) {
- switch (data[0]) {
- case Command.TYPE:
- return Command.fromMsg(data);
-
- case Response.TYPE:
- return Response.fromMsg(data);
-
- default:
- throw new TypeError(
- "Unrecognised message type in packet: " + JSON.stringify(data));
- }
-};
-
-/**
* A command is a request from the client to run a series of remote end
* steps and return a fitting response.
*
* The command can be synthesised from the message passed over the
- * Marionette socket using the {@code fromMsg} function. The format of
+ * Marionette socket using the {@link fromPacket} function. The format of
* a message is:
*
* [type, id, name, params]
*
* where
*
* type (integer)
* Must be zero (integer). Zero means that this message is a command.
@@ -97,26 +108,27 @@ Message.fromMsg = function(data) {
* A command has an associated message {@code id} that prevents the
* dispatcher from sending responses in the wrong order.
*
* The command may also have optional error- and result handlers that
* are called when the client returns with a response. These are
* {@code function onerror({Object})}, {@code function onresult({Object})},
* and {@code function onresult({Response})}.
*
- * @param {number} msgId
+ * @param {number} messageID
* Message ID unique identifying this message.
* @param {string} name
* Command name.
* @param {Object.<string, ?>} params
* Command parameters.
*/
-class Command {
- constructor(msgID, name, params = {}) {
- this.id = assert.integer(msgID);
+class Command extends Message {
+ constructor(messageID, name, params = {}) {
+ super(messageID);
+
this.name = assert.string(name);
this.parameters = assert.object(params);
this.onerror = null;
this.onresult = null;
this.origin = MessageOrigin.Client;
this.sent = false;
@@ -133,39 +145,56 @@ class Command {
onresponse(resp) {
if (this.onerror && resp.error) {
this.onerror(resp.error);
} else if (this.onresult && resp.body) {
this.onresult(resp.body);
}
}
- toMsg() {
- return [Command.TYPE, this.id, this.name, this.parameters];
+ /**
+ * Encodes the command to a packet.
+ *
+ * @return {Array}
+ * Packet.
+ */
+ toPacket() {
+ return [
+ Command.TYPE,
+ this.id,
+ this.name,
+ this.parameters,
+ ];
}
- toString() {
- return "Command {id: " + this.id + ", " +
- "name: " + JSON.stringify(this.name) + ", " +
- "parameters: " + JSON.stringify(this.parameters) + "}";
- }
-
- static fromMsg(msg) {
- let [type, msgID, name, params] = msg;
+ /**
+ * Converts a data packet into {@link Command}.
+ *
+ * @param {Array.<number, number, ?, ?>} data
+ * A four element array where the elements, in sequence, signifies
+ * message type, message ID, command name, and parameters.
+ *
+ * @return {Command}
+ * Representation of packet.
+ *
+ * @throws {TypeError}
+ * If the message type is not recognised.
+ */
+ static fromPacket(payload) {
+ let [type, msgID, name, params] = payload;
assert.that(n => n === Command.TYPE)(type);
// if parameters are given but null, treat them as undefined
if (params === null) {
params = undefined;
}
return new Command(msgID, name, params);
}
}
-
Command.TYPE = 0;
const validator = {
exclusionary: {
"capabilities": ["error", "value"],
"error": ["value", "sessionId", "capabilities"],
"sessionId": ["error", "value"],
"value": ["error", "sessionId", "capabilities"],
@@ -215,25 +244,26 @@ const ResponseBody = () => new Proxy({},
* modification through the available setters. To send data in a response,
* you modify the body property on the response. The body property can
* also be replaced completely.
*
* The response is sent implicitly by CommandProcessor when a command
* has finished executing, and any modifications made subsequent to that
* will have no effect.
*
- * @param {number} msgID
- * Message ID tied to the corresponding command request this is a
- * response for.
+ * @param {number} messageID
+ * Message ID tied to the corresponding command request this is
+ * a response for.
* @param {ResponseHandler} respHandler
* Function callback called on sending the response.
*/
-class Response {
- constructor(msgID, respHandler = () => {}) {
- this.id = assert.integer(msgID);
+class Response extends Message {
+ constructor(messageID, respHandler = () => {}) {
+ super(messageID);
+
this.respHandler_ = assert.callable(respHandler);
this.error = null;
this.body = ResponseBody();
this.origin = MessageOrigin.Server;
this.sent = false;
}
@@ -284,31 +314,52 @@ class Response {
this.send();
// propagate errors which are implementation problems
if (!error.isWebDriverError(err)) {
throw err;
}
}
- toMsg() {
- return [Response.TYPE, this.id, this.error, this.body];
+ /**
+ * Encodes the response to a packet.
+ *
+ * @return {Array}
+ * Packet.
+ */
+ toPacket() {
+ return [
+ Response.TYPE,
+ this.id,
+ this.error,
+ this.body,
+ ];
}
- toString() {
- return "Response {id: " + this.id + ", " +
- "error: " + JSON.stringify(this.error) + ", " +
- "body: " + JSON.stringify(this.body) + "}";
- }
-
- static fromMsg(msg) {
- let [type, msgID, err, body] = msg;
+ /**
+ * Converts a data packet into {@link Response}.
+ *
+ * @param {Array.<number, number, ?, ?>} data
+ * A four element array where the elements, in sequence, signifies
+ * message type, message ID, error, and result.
+ *
+ * @return {Response}
+ * Representation of packet.
+ *
+ * @throws {TypeError}
+ * If the message type is not recognised.
+ */
+ static fromPacket(payload) {
+ let [type, msgID, err, body] = payload;
assert.that(n => n === Response.TYPE)(type);
let resp = new Response(msgID);
resp.error = assert.string(err);
resp.body = body;
return resp;
}
}
+Response.TYPE = 1;
-Response.TYPE = 1;
+this.Message = Message;
+this.Command = Command;
+this.Response = Response;
--- a/testing/marionette/server.js
+++ b/testing/marionette/server.js
@@ -484,17 +484,17 @@ server.TCPConnection = class {
"Unable to unmarshal packet data: " + JSON.stringify(data));
error.report(e);
return;
}
// return immediately with any error trying to unmarshal message
let msg;
try {
- msg = Message.fromMsg(data);
+ msg = Message.fromPacket(data);
msg.origin = MessageOrigin.Client;
this.log_(msg);
} catch (e) {
let resp = this.createResponse(data[1]);
resp.sendError(e);
return;
}
@@ -644,17 +644,17 @@ server.TCPConnection = class {
/**
* Marshal message to the Marionette message format and send it.
*
* @param {Message} msg
* The message to send.
*/
sendMessage(msg) {
this.log_(msg);
- let payload = msg.toMsg();
+ let payload = msg.toPacket();
this.sendRaw(payload);
}
/**
* Send the given payload over the debugger transport socket to the
* connected client.
*
* @param {Object.<string, ?>} payload
--- a/testing/marionette/test_message.js
+++ b/testing/marionette/test_message.js
@@ -9,24 +9,24 @@ Cu.import("chrome://marionette/content/m
add_test(function test_MessageOrigin() {
equal(0, MessageOrigin.Client);
equal(1, MessageOrigin.Server);
run_next_test();
});
-add_test(function test_Message_fromMsg() {
+add_test(function test_Message_fromPacket() {
let cmd = new Command(4, "foo");
let resp = new Response(5, () => {});
resp.error = "foo";
- ok(Message.fromMsg(cmd.toMsg()) instanceof Command);
- ok(Message.fromMsg(resp.toMsg()) instanceof Response);
- Assert.throws(() => Message.fromMsg([3, 4, 5, 6]),
+ ok(Message.fromPacket(cmd.toPacket()) instanceof Command);
+ ok(Message.fromPacket(resp.toPacket()) instanceof Response);
+ Assert.throws(() => Message.fromPacket([3, 4, 5, 6]),
/Unrecognised message type in packet/);
run_next_test();
});
add_test(function test_Command() {
let cmd = new Command(42, "foo", {bar: "baz"});
equal(42, cmd.id);
@@ -61,53 +61,50 @@ add_test(function test_Command_onrespons
cmd.onresponse(bodyResp);
equal(true, onresultOk);
run_next_test();
});
add_test(function test_Command_ctor() {
let cmd = new Command(42, "bar", {bar: "baz"});
- let msg = cmd.toMsg();
+ let msg = cmd.toPacket();
equal(Command.TYPE, msg[0]);
equal(cmd.id, msg[1]);
equal(cmd.name, msg[2]);
equal(cmd.parameters, msg[3]);
run_next_test();
});
add_test(function test_Command_toString() {
let cmd = new Command(42, "foo", {bar: "baz"});
- equal(`Command {id: ${cmd.id}, ` +
- `name: ${JSON.stringify(cmd.name)}, ` +
- `parameters: ${JSON.stringify(cmd.parameters)}}`,
- cmd.toString());
+ equal(JSON.stringify(cmd.toPacket()), cmd.toString());
run_next_test();
});
-add_test(function test_Command_fromMsg() {
+add_test(function test_Command_fromPacket() {
let c1 = new Command(42, "foo", {bar: "baz"});
- let msg = c1.toMsg();
- let c2 = Command.fromMsg(msg);
+ let msg = c1.toPacket();
+ let c2 = Command.fromPacket(msg);
equal(c1.id, c2.id);
equal(c1.name, c2.name);
equal(c1.parameters, c2.parameters);
- Assert.throws(() => Command.fromMsg([null, 2, "foo", {}]));
- Assert.throws(() => Command.fromMsg([1, 2, "foo", {}]));
- Assert.throws(() => Command.fromMsg([0, null, "foo", {}]));
- Assert.throws(() => Command.fromMsg([0, 2, null, {}]));
- Assert.throws(() => Command.fromMsg([0, 2, "foo", false]));
+ Assert.throws(() => Command.fromPacket([null, 2, "foo", {}]));
+ Assert.throws(() => Command.fromPacket([1, 2, "foo", {}]));
+ Assert.throws(() => Command.fromPacket([0, null, "foo", {}]));
+ Assert.throws(() => Command.fromPacket([0, 2, null, {}]));
+ Assert.throws(() => Command.fromPacket([0, 2, "foo", false]));
- let nullParams = Command.fromMsg([0, 2, "foo", null]);
+ let nullParams = Command.fromPacket([0, 2, "foo", null]);
equal("[object Object]", Object.prototype.toString.call(nullParams.parameters));
run_next_test();
});
add_test(function test_Command_TYPE() {
equal(0, Command.TYPE);
run_next_test();
@@ -194,58 +191,55 @@ add_test(function test_Response_sendErro
// they should also throw after being sent
Assert.throws(() => resp.sendError(err), /foo/);
equal(true, resp.sent);
run_next_test();
});
-add_test(function test_Response_toMsg() {
+add_test(function test_Response_toPacket() {
let resp = new Response(42, () => {});
- let msg = resp.toMsg();
+ let msg = resp.toPacket();
equal(Response.TYPE, msg[0]);
equal(resp.id, msg[1]);
equal(resp.error, msg[2]);
equal(resp.body, msg[3]);
run_next_test();
});
add_test(function test_Response_toString() {
let resp = new Response(42, () => {});
resp.error = "foo";
resp.body = "bar";
- equal(`Response {id: ${resp.id}, ` +
- `error: ${JSON.stringify(resp.error)}, ` +
- `body: ${JSON.stringify(resp.body)}}`,
- resp.toString());
+ equal(JSON.stringify(resp.toPacket()), resp.toString());
run_next_test();
});
-add_test(function test_Response_fromMsg() {
+add_test(function test_Response_fromPacket() {
let r1 = new Response(42, () => {});
r1.error = "foo";
r1.body = "bar";
- let msg = r1.toMsg();
- let r2 = Response.fromMsg(msg);
+ let msg = r1.toPacket();
+ let r2 = Response.fromPacket(msg);
equal(r1.id, r2.id);
equal(r1.error, r2.error);
equal(r1.body, r2.body);
- Assert.throws(() => Response.fromMsg([null, 2, "foo", {}]));
- Assert.throws(() => Response.fromMsg([0, 2, "foo", {}]));
- Assert.throws(() => Response.fromMsg([1, null, "foo", {}]));
- Assert.throws(() => Response.fromMsg([1, 2, null, {}]));
- Response.fromMsg([1, 2, "foo", null]);
+ Assert.throws(() => Response.fromPacket([null, 2, "foo", {}]));
+ Assert.throws(() => Response.fromPacket([0, 2, "foo", {}]));
+ Assert.throws(() => Response.fromPacket([1, null, "foo", {}]));
+ Assert.throws(() => Response.fromPacket([1, 2, null, {}]));
+ Response.fromPacket([1, 2, "foo", null]);
run_next_test();
});
add_test(function test_Response_TYPE() {
equal(1, Response.TYPE);
run_next_test();
});