test_client_request.js (5543B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the DevToolsClient.request API. 7 8 var gClient, gActorId; 9 10 const { Actor } = require("resource://devtools/shared/protocol/Actor.js"); 11 12 class TestActor extends Actor { 13 constructor(conn) { 14 super(conn, { typeName: "test", methods: [] }); 15 16 this.requestTypes = { 17 hello: this.hello, 18 error: this.error, 19 }; 20 } 21 22 hello() { 23 return { hello: "world" }; 24 } 25 26 error() { 27 return { error: "code", message: "human message" }; 28 } 29 } 30 31 function run_test() { 32 ActorRegistry.addGlobalActor( 33 { 34 constructorName: "TestActor", 35 constructorFun: TestActor, 36 }, 37 "test" 38 ); 39 40 DevToolsServer.init(); 41 DevToolsServer.registerAllActors(); 42 43 add_test(init); 44 add_test(test_client_request_promise); 45 add_test(test_client_request_promise_error); 46 add_test(test_client_request_event_emitter); 47 add_test(test_close_client_while_sending_requests); 48 add_test(test_client_request_after_close); 49 run_next_test(); 50 } 51 52 function init() { 53 gClient = new DevToolsClient(DevToolsServer.connectPipe()); 54 gClient 55 .connect() 56 .then(() => gClient.mainRoot.rootForm) 57 .then(response => { 58 gActorId = response.test; 59 run_next_test(); 60 }); 61 } 62 63 function checkStack(expectedName) { 64 let stack = Components.stack; 65 while (stack) { 66 info(stack.name); 67 if (stack.name == expectedName) { 68 // Reached back to outer function before request 69 ok(true, "Complete stack"); 70 return; 71 } 72 stack = stack.asyncCaller || stack.caller; 73 } 74 ok(false, "Incomplete stack"); 75 } 76 77 function test_client_request_promise() { 78 // Test that DevToolsClient.request returns a promise that resolves on response 79 const request = gClient.request({ 80 to: gActorId, 81 type: "hello", 82 }); 83 84 request.then(response => { 85 Assert.equal(response.from, gActorId); 86 Assert.equal(response.hello, "world"); 87 checkStack("test_client_request_promise/<"); 88 run_next_test(); 89 }); 90 } 91 92 function test_client_request_promise_error() { 93 // Test that DevToolsClient.request returns a promise that reject when server 94 // returns an explicit error message 95 const request = gClient.request({ 96 to: gActorId, 97 type: "error", 98 }); 99 100 request.then( 101 () => { 102 do_throw("Promise shouldn't be resolved on error"); 103 }, 104 response => { 105 Assert.equal(response.from, gActorId); 106 Assert.equal(response.error, "code"); 107 Assert.equal(response.message, "human message"); 108 checkStack("test_client_request_promise_error/<"); 109 run_next_test(); 110 } 111 ); 112 } 113 114 function test_client_request_event_emitter() { 115 // Test that DevToolsClient.request returns also an EventEmitter object 116 const request = gClient.request({ 117 to: gActorId, 118 type: "hello", 119 }); 120 request.on("json-reply", reply => { 121 Assert.equal(reply.from, gActorId); 122 Assert.equal(reply.hello, "world"); 123 checkStack("test_client_request_event_emitter"); 124 run_next_test(); 125 }); 126 } 127 128 function test_close_client_while_sending_requests() { 129 // First send a first request that will be "active" 130 // while the connection is closed. 131 // i.e. will be sent but no response received yet. 132 const activeRequest = gClient.request({ 133 to: gActorId, 134 type: "hello", 135 }); 136 137 // Pile up a second one that will be "pending". 138 // i.e. won't event be sent. 139 const pendingRequest = gClient.request({ 140 to: gActorId, 141 type: "hello", 142 }); 143 144 const expectReply = new Promise(resolve => { 145 gClient.expectReply("root", function (response) { 146 Assert.equal(response.error, "connectionClosed"); 147 Assert.equal( 148 response.message, 149 "server side packet can't be received as the connection just closed." 150 ); 151 resolve(); 152 }); 153 }); 154 155 gClient.close().then(() => { 156 activeRequest 157 .then( 158 () => { 159 ok( 160 false, 161 "First request unexpectedly succeed while closing the connection" 162 ); 163 }, 164 response => { 165 Assert.equal(response.error, "connectionClosed"); 166 Assert.equal( 167 response.message, 168 "'hello' active request packet to '" + 169 gActorId + 170 "' can't be sent as the connection just closed." 171 ); 172 } 173 ) 174 .then(() => pendingRequest) 175 .then( 176 () => { 177 ok( 178 false, 179 "Second request unexpectedly succeed while closing the connection" 180 ); 181 }, 182 response => { 183 Assert.equal(response.error, "connectionClosed"); 184 Assert.equal( 185 response.message, 186 "'hello' pending request packet to '" + 187 gActorId + 188 "' can't be sent as the connection just closed." 189 ); 190 } 191 ) 192 .then(() => expectReply) 193 .then(run_next_test); 194 }); 195 } 196 197 function test_client_request_after_close() { 198 // Test that DevToolsClient.request fails after we called client.close() 199 // (with promise API) 200 const request = gClient.request({ 201 to: gActorId, 202 type: "hello", 203 }); 204 205 request.then( 206 () => { 207 ok(false, "Request succeed even after client.close"); 208 }, 209 response => { 210 ok(true, "Request failed after client.close"); 211 Assert.equal(response.error, "connectionClosed"); 212 ok( 213 response.message.match( 214 /'hello' request packet to '.*' can't be sent as the connection is closed./ 215 ) 216 ); 217 run_next_test(); 218 } 219 ); 220 }