diff options
Diffstat (limited to 'devtools/server/tests/xpcshell/test_client_request.js')
-rw-r--r-- | devtools/server/tests/xpcshell/test_client_request.js | 262 |
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")); +} |