summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/xpcshell/test_client_request.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/tests/xpcshell/test_client_request.js')
-rw-r--r--devtools/server/tests/xpcshell/test_client_request.js262
1 files changed, 262 insertions, 0 deletions
diff --git a/devtools/server/tests/xpcshell/test_client_request.js b/devtools/server/tests/xpcshell/test_client_request.js
new file mode 100644
index 0000000000..43f4377798
--- /dev/null
+++ b/devtools/server/tests/xpcshell/test_client_request.js
@@ -0,0 +1,262 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the DevToolsClient.request API.
+
+var gClient, gActorId;
+
+const { Actor } = require("devtools/shared/protocol/Actor");
+
+class TestActor extends Actor {
+ constructor(conn) {
+ super(conn);
+
+ this.typeName = "test";
+ this.requestTypes = {
+ hello: this.hello,
+ error: this.error,
+ };
+ }
+
+ hello() {
+ return { hello: "world" };
+ }
+
+ error() {
+ return { error: "code", message: "human message" };
+ }
+}
+
+function run_test() {
+ ActorRegistry.addGlobalActor(
+ {
+ constructorName: "TestActor",
+ constructorFun: TestActor,
+ },
+ "test"
+ );
+
+ DevToolsServer.init();
+ DevToolsServer.registerAllActors();
+
+ add_test(init);
+ add_test(test_client_request_callback);
+ add_test(test_client_request_promise);
+ add_test(test_client_request_promise_error);
+ add_test(test_client_request_event_emitter);
+ add_test(test_close_client_while_sending_requests);
+ add_test(test_client_request_after_close);
+ add_test(test_client_request_after_close_callback);
+ run_next_test();
+}
+
+function init() {
+ gClient = new DevToolsClient(DevToolsServer.connectPipe());
+ gClient
+ .connect()
+ .then(() => gClient.mainRoot.rootForm)
+ .then(response => {
+ gActorId = response.test;
+ run_next_test();
+ });
+}
+
+function checkStack(expectedName) {
+ let stack = Components.stack;
+ while (stack) {
+ info(stack.name);
+ if (stack.name == expectedName) {
+ // Reached back to outer function before request
+ ok(true, "Complete stack");
+ return;
+ }
+ stack = stack.asyncCaller || stack.caller;
+ }
+ ok(false, "Incomplete stack");
+}
+
+function test_client_request_callback() {
+ // Test that DevToolsClient.request accepts a `onResponse` callback as 2nd argument
+ gClient.request(
+ {
+ to: gActorId,
+ type: "hello",
+ },
+ response => {
+ Assert.equal(response.from, gActorId);
+ Assert.equal(response.hello, "world");
+ checkStack("test_client_request_callback");
+ run_next_test();
+ }
+ );
+}
+
+function test_client_request_promise() {
+ // Test that DevToolsClient.request returns a promise that resolves on response
+ const request = gClient.request({
+ to: gActorId,
+ type: "hello",
+ });
+
+ request.then(response => {
+ Assert.equal(response.from, gActorId);
+ Assert.equal(response.hello, "world");
+ checkStack("test_client_request_promise/<");
+ run_next_test();
+ });
+}
+
+function test_client_request_promise_error() {
+ // Test that DevToolsClient.request returns a promise that reject when server
+ // returns an explicit error message
+ const request = gClient.request({
+ to: gActorId,
+ type: "error",
+ });
+
+ request.then(
+ () => {
+ do_throw("Promise shouldn't be resolved on error");
+ },
+ response => {
+ Assert.equal(response.from, gActorId);
+ Assert.equal(response.error, "code");
+ Assert.equal(response.message, "human message");
+ checkStack("test_client_request_promise_error/<");
+ run_next_test();
+ }
+ );
+}
+
+function test_client_request_event_emitter() {
+ // Test that DevToolsClient.request returns also an EventEmitter object
+ const request = gClient.request({
+ to: gActorId,
+ type: "hello",
+ });
+ request.on("json-reply", reply => {
+ Assert.equal(reply.from, gActorId);
+ Assert.equal(reply.hello, "world");
+ checkStack("test_client_request_event_emitter");
+ run_next_test();
+ });
+}
+
+function test_close_client_while_sending_requests() {
+ // First send a first request that will be "active"
+ // while the connection is closed.
+ // i.e. will be sent but no response received yet.
+ const activeRequest = gClient.request({
+ to: gActorId,
+ type: "hello",
+ });
+
+ // Pile up a second one that will be "pending".
+ // i.e. won't event be sent.
+ const pendingRequest = gClient.request({
+ to: gActorId,
+ type: "hello",
+ });
+
+ const expectReply = new Promise(resolve => {
+ gClient.expectReply("root", function(response) {
+ Assert.equal(response.error, "connectionClosed");
+ Assert.equal(
+ response.message,
+ "server side packet can't be received as the connection just closed."
+ );
+ resolve();
+ });
+ });
+
+ gClient.close().then(() => {
+ activeRequest
+ .then(
+ () => {
+ ok(
+ false,
+ "First request unexpectedly succeed while closing the connection"
+ );
+ },
+ response => {
+ Assert.equal(response.error, "connectionClosed");
+ Assert.equal(
+ response.message,
+ "'hello' active request packet to '" +
+ gActorId +
+ "' can't be sent as the connection just closed."
+ );
+ }
+ )
+ .then(() => pendingRequest)
+ .then(
+ () => {
+ ok(
+ false,
+ "Second request unexpectedly succeed while closing the connection"
+ );
+ },
+ response => {
+ Assert.equal(response.error, "connectionClosed");
+ Assert.equal(
+ response.message,
+ "'hello' pending request packet to '" +
+ gActorId +
+ "' can't be sent as the connection just closed."
+ );
+ }
+ )
+ .then(() => expectReply)
+ .then(run_next_test);
+ });
+}
+
+function test_client_request_after_close() {
+ // Test that DevToolsClient.request fails after we called client.close()
+ // (with promise API)
+ const request = gClient.request({
+ to: gActorId,
+ type: "hello",
+ });
+
+ request.then(
+ response => {
+ ok(false, "Request succeed even after client.close");
+ },
+ response => {
+ ok(true, "Request failed after client.close");
+ Assert.equal(response.error, "connectionClosed");
+ ok(
+ response.message.match(
+ /'hello' request packet to '.*' can't be sent as the connection is closed./
+ )
+ );
+ run_next_test();
+ }
+ );
+}
+
+function test_client_request_after_close_callback() {
+ // Test that DevToolsClient.request fails after we called client.close()
+ // (with callback API)
+ gClient
+ .request(
+ {
+ to: gActorId,
+ type: "hello",
+ },
+ response => {
+ ok(true, "Request failed after client.close");
+ Assert.equal(response.error, "connectionClosed");
+ ok(
+ response.message.match(
+ /'hello' request packet to '.*' can't be sent as the connection is closed./
+ )
+ );
+ run_next_test();
+ }
+ )
+ .catch(() => info("Caught rejected promise as expected"));
+}