toolkit/devtools/server/tests/unit/test_protocol_children.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 /**
michael@0 5 * Test simple requests using the protocol helpers.
michael@0 6 */
michael@0 7 let protocol = devtools.require("devtools/server/protocol");
michael@0 8 let {method, preEvent, types, Arg, Option, RetVal} = protocol;
michael@0 9
michael@0 10 let events = devtools.require("sdk/event/core");
michael@0 11
michael@0 12 function simpleHello() {
michael@0 13 return {
michael@0 14 from: "root",
michael@0 15 applicationType: "xpcshell-tests",
michael@0 16 traits: [],
michael@0 17 }
michael@0 18 }
michael@0 19
michael@0 20 let testTypes = {};
michael@0 21
michael@0 22 // Predeclaring the actor type so that it can be used in the
michael@0 23 // implementation of the child actor.
michael@0 24 types.addActorType("childActor");
michael@0 25
michael@0 26 let ChildActor = protocol.ActorClass({
michael@0 27 typeName: "childActor",
michael@0 28
michael@0 29 // Actors returned by this actor should be owned by the root actor.
michael@0 30 marshallPool: function() { return this.parent() },
michael@0 31
michael@0 32 toString: function() "[ChildActor " + this.childID + "]",
michael@0 33
michael@0 34 initialize: function(conn, id) {
michael@0 35 protocol.Actor.prototype.initialize.call(this, conn);
michael@0 36 this.childID = id;
michael@0 37 },
michael@0 38
michael@0 39 destroy: function() {
michael@0 40 protocol.Actor.prototype.destroy.call(this);
michael@0 41 this.destroyed = true;
michael@0 42 },
michael@0 43
michael@0 44 form: function(detail) {
michael@0 45 if (detail === "actorid") {
michael@0 46 return this.actorID;
michael@0 47 }
michael@0 48 return {
michael@0 49 actor: this.actorID,
michael@0 50 childID: this.childID,
michael@0 51 detail: detail
michael@0 52 };
michael@0 53 },
michael@0 54
michael@0 55 echo: method(function(str) {
michael@0 56 return str;
michael@0 57 }, {
michael@0 58 request: { str: Arg(0) },
michael@0 59 response: { str: RetVal("string") },
michael@0 60 telemetry: "ECHO"
michael@0 61 }),
michael@0 62
michael@0 63 getDetail1: method(function() {
michael@0 64 return this;
michael@0 65 }, {
michael@0 66 // This also exercises return-value-as-packet.
michael@0 67 response: RetVal("childActor#detail1"),
michael@0 68 }),
michael@0 69
michael@0 70 getDetail2: method(function() {
michael@0 71 return this;
michael@0 72 }, {
michael@0 73 // This also exercises return-value-as-packet.
michael@0 74 response: RetVal("childActor#detail2"),
michael@0 75 }),
michael@0 76
michael@0 77 getIDDetail: method(function() {
michael@0 78 return this;
michael@0 79 }, {
michael@0 80 response: {
michael@0 81 idDetail: RetVal("childActor#actorid")
michael@0 82 }
michael@0 83 }),
michael@0 84
michael@0 85 getSibling: method(function(id) {
michael@0 86 return this.parent().getChild(id);
michael@0 87 }, {
michael@0 88 request: { id: Arg(0) },
michael@0 89 response: { sibling: RetVal("childActor") }
michael@0 90 }),
michael@0 91
michael@0 92 emitEvents: method(function() {
michael@0 93 events.emit(this, "event1", 1, 2, 3);
michael@0 94 events.emit(this, "named-event", 1, 2, 3);
michael@0 95 events.emit(this, "object-event", this);
michael@0 96 events.emit(this, "array-object-event", [this]);
michael@0 97 }, {
michael@0 98 response: { value: "correct response" },
michael@0 99 }),
michael@0 100
michael@0 101 release: method(function() { }, { release: true }),
michael@0 102
michael@0 103 events: {
michael@0 104 "event1" : {
michael@0 105 a: Arg(0),
michael@0 106 b: Arg(1),
michael@0 107 c: Arg(2)
michael@0 108 },
michael@0 109 "named-event": {
michael@0 110 type: "namedEvent",
michael@0 111 a: Arg(0),
michael@0 112 b: Arg(1),
michael@0 113 c: Arg(2)
michael@0 114 },
michael@0 115 "object-event": {
michael@0 116 type: "objectEvent",
michael@0 117 detail: Arg(0, "childActor#detail1"),
michael@0 118 },
michael@0 119 "array-object-event": {
michael@0 120 type: "arrayObjectEvent",
michael@0 121 detail: Arg(0, "array:childActor#detail2"),
michael@0 122 }
michael@0 123 }
michael@0 124 });
michael@0 125
michael@0 126 let ChildFront = protocol.FrontClass(ChildActor, {
michael@0 127 initialize: function(client, form) {
michael@0 128 protocol.Front.prototype.initialize.call(this, client, form);
michael@0 129 },
michael@0 130
michael@0 131 destroy: function() {
michael@0 132 this.destroyed = true;
michael@0 133 protocol.Front.prototype.destroy.call(this);
michael@0 134 },
michael@0 135
michael@0 136 marshallPool: function() { return this.parent() },
michael@0 137
michael@0 138 toString: function() "[child front " + this.childID + "]",
michael@0 139
michael@0 140 form: function(form, detail) {
michael@0 141 if (detail === "actorid") {
michael@0 142 return;
michael@0 143 }
michael@0 144 this.childID = form.childID;
michael@0 145 this.detail = form.detail;
michael@0 146 },
michael@0 147
michael@0 148 onEvent1: preEvent("event1", function(a, b, c) {
michael@0 149 this.event1arg3 = c;
michael@0 150 }),
michael@0 151 });
michael@0 152
michael@0 153 types.addDictType("manyChildrenDict", {
michael@0 154 child5: "childActor",
michael@0 155 more: "array:childActor",
michael@0 156 });
michael@0 157
michael@0 158 types.addLifetime("temp", "_temporaryHolder");
michael@0 159
michael@0 160 let rootActor = null;
michael@0 161 let RootActor = protocol.ActorClass({
michael@0 162 typeName: "root",
michael@0 163
michael@0 164 toString: function() "[root actor]",
michael@0 165
michael@0 166 initialize: function(conn) {
michael@0 167 rootActor = this;
michael@0 168 this.actorID = "root";
michael@0 169 this._children = {};
michael@0 170 protocol.Actor.prototype.initialize.call(this, conn);
michael@0 171 // Root actor owns itself.
michael@0 172 this.manage(this);
michael@0 173 },
michael@0 174
michael@0 175 sayHello: simpleHello,
michael@0 176
michael@0 177 getChild: method(function(id) {
michael@0 178 if (id in this._children) {
michael@0 179 return this._children[id];
michael@0 180 }
michael@0 181 let child = new ChildActor(this.conn, id);
michael@0 182 this._children[id] = child;
michael@0 183 return child;
michael@0 184 }, {
michael@0 185 request: { str: Arg(0) },
michael@0 186 response: { actor: RetVal("childActor") },
michael@0 187 }),
michael@0 188
michael@0 189 getChildren: method(function(ids) {
michael@0 190 return [this.getChild(id) for (id of ids)];
michael@0 191 }, {
michael@0 192 request: { ids: Arg(0, "array:string") },
michael@0 193 response: { children: RetVal("array:childActor") },
michael@0 194 }),
michael@0 195
michael@0 196 getManyChildren: method(function() {
michael@0 197 return {
michael@0 198 foo: "bar", // note that this isn't in the specialization array.
michael@0 199 child5: this.getChild("child5"),
michael@0 200 more: [ this.getChild("child6"), this.getChild("child7") ]
michael@0 201 }
michael@0 202 }, {
michael@0 203 response: RetVal("manyChildrenDict")
michael@0 204 }),
michael@0 205
michael@0 206 // This should remind you of a pause actor.
michael@0 207 getTemporaryChild: method(function(id) {
michael@0 208 if (!this._temporaryHolder) {
michael@0 209 this._temporaryHolder = this.manage(new protocol.Actor(this.conn));
michael@0 210 }
michael@0 211 return new ChildActor(this.conn, id);
michael@0 212 }, {
michael@0 213 request: { id: Arg(0) },
michael@0 214 response: { child: RetVal("temp:childActor") }
michael@0 215 }),
michael@0 216
michael@0 217 clearTemporaryChildren: method(function(id) {
michael@0 218 if (!this._temporaryHolder) {
michael@0 219 return;
michael@0 220 }
michael@0 221 this._temporaryHolder.destroy();
michael@0 222 delete this._temporaryHolder;
michael@0 223 })
michael@0 224 });
michael@0 225
michael@0 226 let RootFront = protocol.FrontClass(RootActor, {
michael@0 227 toString: function() "[root front]",
michael@0 228 initialize: function(client) {
michael@0 229 this.actorID = "root";
michael@0 230 protocol.Front.prototype.initialize.call(this, client);
michael@0 231 // Root actor owns itself.
michael@0 232 this.manage(this);
michael@0 233 },
michael@0 234
michael@0 235 getTemporaryChild: protocol.custom(function(id) {
michael@0 236 if (!this._temporaryHolder) {
michael@0 237 this._temporaryHolder = this.manage(new protocol.Front(this.conn, {actor: this.actorID + "_temp"}));
michael@0 238 }
michael@0 239 return this._getTemporaryChild(id);
michael@0 240 },{
michael@0 241 impl: "_getTemporaryChild"
michael@0 242 }),
michael@0 243
michael@0 244 clearTemporaryChildren: protocol.custom(function() {
michael@0 245 if (!this._temporaryHolder) {
michael@0 246 return promise.resolve(undefined);
michael@0 247 }
michael@0 248 this._temporaryHolder.destroy();
michael@0 249 delete this._temporaryHolder;
michael@0 250 return this._clearTemporaryChildren();
michael@0 251 }, {
michael@0 252 impl: "_clearTemporaryChildren"
michael@0 253 })
michael@0 254 });
michael@0 255
michael@0 256 function run_test()
michael@0 257 {
michael@0 258 DebuggerServer.createRootActor = (conn => {
michael@0 259 return RootActor(conn);
michael@0 260 });
michael@0 261 DebuggerServer.init(() => true);
michael@0 262
michael@0 263 let trace = connectPipeTracing();
michael@0 264 let client = new DebuggerClient(trace);
michael@0 265 client.connect((applicationType, traits) => {
michael@0 266 trace.expectReceive({"from":"<actorid>","applicationType":"xpcshell-tests","traits":[]})
michael@0 267 do_check_eq(applicationType, "xpcshell-tests");
michael@0 268
michael@0 269 let rootFront = RootFront(client);
michael@0 270 let childFront = null;
michael@0 271
michael@0 272 let expectRootChildren = size => {
michael@0 273 do_check_eq(rootActor._poolMap.size, size + 1);
michael@0 274 do_check_eq(rootFront._poolMap.size, size + 1);
michael@0 275 if (childFront) {
michael@0 276 do_check_eq(childFront._poolMap.size, 0);
michael@0 277 }
michael@0 278 };
michael@0 279
michael@0 280 rootFront.getChild("child1").then(ret => {
michael@0 281 trace.expectSend({"type":"getChild","str":"child1","to":"<actorid>"})
michael@0 282 trace.expectReceive({"actor":"<actorid>","from":"<actorid>"})
michael@0 283
michael@0 284 childFront = ret;
michael@0 285 do_check_true(childFront instanceof ChildFront);
michael@0 286 do_check_eq(childFront.childID, "child1");
michael@0 287 expectRootChildren(1);
michael@0 288 }).then(() => {
michael@0 289 // Request the child again, make sure the same is returned.
michael@0 290 return rootFront.getChild("child1");
michael@0 291 }).then(ret => {
michael@0 292 trace.expectSend({"type":"getChild","str":"child1","to":"<actorid>"})
michael@0 293 trace.expectReceive({"actor":"<actorid>","from":"<actorid>"})
michael@0 294
michael@0 295 expectRootChildren(1);
michael@0 296 do_check_true(ret === childFront);
michael@0 297 }).then(() => {
michael@0 298 return childFront.echo("hello");
michael@0 299 }).then(ret => {
michael@0 300 trace.expectSend({"type":"echo","str":"hello","to":"<actorid>"})
michael@0 301 trace.expectReceive({"str":"hello","from":"<actorid>"})
michael@0 302
michael@0 303 do_check_eq(ret, "hello");
michael@0 304 }).then(() => {
michael@0 305 return childFront.getDetail1();
michael@0 306 }).then(ret => {
michael@0 307 trace.expectSend({"type":"getDetail1","to":"<actorid>"});
michael@0 308 trace.expectReceive({"actor":"<actorid>","childID":"child1","detail":"detail1","from":"<actorid>"});
michael@0 309 do_check_true(ret === childFront);
michael@0 310 do_check_eq(childFront.detail, "detail1");
michael@0 311 }).then(() => {
michael@0 312 return childFront.getDetail2();
michael@0 313 }).then(ret => {
michael@0 314 trace.expectSend({"type":"getDetail2","to":"<actorid>"});
michael@0 315 trace.expectReceive({"actor":"<actorid>","childID":"child1","detail":"detail2","from":"<actorid>"});
michael@0 316 do_check_true(ret === childFront);
michael@0 317 do_check_eq(childFront.detail, "detail2");
michael@0 318 }).then(() => {
michael@0 319 return childFront.getIDDetail();
michael@0 320 }).then(ret => {
michael@0 321 trace.expectSend({"type":"getIDDetail","to":"<actorid>"});
michael@0 322 trace.expectReceive({"idDetail": childFront.actorID,"from":"<actorid>"});
michael@0 323 do_check_true(ret === childFront);
michael@0 324 }).then(() => {
michael@0 325 return childFront.getSibling("siblingID");
michael@0 326 }).then(ret => {
michael@0 327 trace.expectSend({"type":"getSibling","id":"siblingID","to":"<actorid>"});
michael@0 328 trace.expectReceive({"sibling":{"actor":"<actorid>","childID":"siblingID"},"from":"<actorid>"});
michael@0 329
michael@0 330 expectRootChildren(2);
michael@0 331 }).then(ret => {
michael@0 332 return rootFront.getTemporaryChild("temp1").then(temp1 => {
michael@0 333 trace.expectSend({"type":"getTemporaryChild","id":"temp1","to":"<actorid>"});
michael@0 334 trace.expectReceive({"child":{"actor":"<actorid>","childID":"temp1"},"from":"<actorid>"});
michael@0 335
michael@0 336 // At this point we expect two direct children, plus the temporary holder
michael@0 337 // which should hold 1 itself.
michael@0 338 do_check_eq(rootActor._temporaryHolder.__poolMap.size, 1);
michael@0 339 do_check_eq(rootFront._temporaryHolder.__poolMap.size, 1);
michael@0 340
michael@0 341 expectRootChildren(3);
michael@0 342 return rootFront.getTemporaryChild("temp2").then(temp2 => {
michael@0 343 trace.expectSend({"type":"getTemporaryChild","id":"temp2","to":"<actorid>"});
michael@0 344 trace.expectReceive({"child":{"actor":"<actorid>","childID":"temp2"},"from":"<actorid>"});
michael@0 345
michael@0 346 // Same amount of direct children, and an extra in the temporary holder.
michael@0 347 expectRootChildren(3);
michael@0 348 do_check_eq(rootActor._temporaryHolder.__poolMap.size, 2);
michael@0 349 do_check_eq(rootFront._temporaryHolder.__poolMap.size, 2);
michael@0 350
michael@0 351 // Get the children of the temporary holder...
michael@0 352 let checkActors = [entry[1] for (entry of rootActor._temporaryHolder.__poolMap)];
michael@0 353 let checkFronts = [entry[1] for (entry of rootFront._temporaryHolder.__poolMap)];
michael@0 354
michael@0 355 // Now release the temporary holders and expect them to drop again.
michael@0 356 return rootFront.clearTemporaryChildren().then(() => {
michael@0 357 trace.expectSend({"type":"clearTemporaryChildren","to":"<actorid>"});
michael@0 358 trace.expectReceive({"from":"<actorid>"});
michael@0 359
michael@0 360 expectRootChildren(2);
michael@0 361 do_check_false(!!rootActor._temporaryHolder);
michael@0 362 do_check_false(!!rootFront._temporaryHolder);
michael@0 363 for (let checkActor of checkActors) {
michael@0 364 do_check_true(checkActor.destroyed);
michael@0 365 do_check_true(checkActor.destroyed);
michael@0 366 }
michael@0 367 });
michael@0 368 });
michael@0 369 })
michael@0 370 }).then(ret => {
michael@0 371 return rootFront.getChildren(["child1", "child2"]);
michael@0 372 }).then(ret => {
michael@0 373 trace.expectSend({"type":"getChildren","ids":["child1","child2"],"to":"<actorid>"});
michael@0 374 trace.expectReceive({"children":[{"actor":"<actorid>","childID":"child1"},{"actor":"<actorid>","childID":"child2"}],"from":"<actorid>"});
michael@0 375
michael@0 376 expectRootChildren(3);
michael@0 377 do_check_true(ret[0] === childFront);
michael@0 378 do_check_true(ret[1] !== childFront);
michael@0 379 do_check_true(ret[1] instanceof ChildFront);
michael@0 380
michael@0 381 // On both children, listen to events. We're only
michael@0 382 // going to trigger events on the first child, so an event
michael@0 383 // triggered on the second should cause immediate failures.
michael@0 384
michael@0 385 let set = new Set(["event1", "named-event", "object-event", "array-object-event"]);
michael@0 386
michael@0 387 childFront.on("event1", (a, b, c) => {
michael@0 388 do_check_eq(a, 1);
michael@0 389 do_check_eq(b, 2);
michael@0 390 do_check_eq(c, 3);
michael@0 391 // Verify that the pre-event handler was called.
michael@0 392 do_check_eq(childFront.event1arg3, 3);
michael@0 393 set.delete("event1");
michael@0 394 });
michael@0 395 childFront.on("named-event", (a, b, c) => {
michael@0 396 do_check_eq(a, 1);
michael@0 397 do_check_eq(b, 2);
michael@0 398 do_check_eq(c, 3);
michael@0 399 set.delete("named-event");
michael@0 400 });
michael@0 401 childFront.on("object-event", (obj) => {
michael@0 402 do_check_true(obj === childFront);
michael@0 403 do_check_eq(childFront.detail, "detail1");
michael@0 404 set.delete("object-event");
michael@0 405 });
michael@0 406 childFront.on("array-object-event", (array) => {
michael@0 407 do_check_true(array[0] === childFront);
michael@0 408 do_check_eq(childFront.detail, "detail2");
michael@0 409 set.delete("array-object-event");
michael@0 410 });
michael@0 411
michael@0 412 let fail = function() {
michael@0 413 do_throw("Unexpected event");
michael@0 414 }
michael@0 415 ret[1].on("event1", fail);
michael@0 416 ret[1].on("named-event", fail);
michael@0 417 ret[1].on("object-event", fail);
michael@0 418 ret[1].on("array-object-event", fail);
michael@0 419
michael@0 420 return childFront.emitEvents().then(() => {
michael@0 421 trace.expectSend({"type":"emitEvents","to":"<actorid>"});
michael@0 422 trace.expectReceive({"type":"event1","a":1,"b":2,"c":3,"from":"<actorid>"});
michael@0 423 trace.expectReceive({"type":"namedEvent","a":1,"b":2,"c":3,"from":"<actorid>"});
michael@0 424 trace.expectReceive({"type":"objectEvent","detail":{"actor":"<actorid>","childID":"child1","detail":"detail1"},"from":"<actorid>"});
michael@0 425 trace.expectReceive({"type":"arrayObjectEvent","detail":[{"actor":"<actorid>","childID":"child1","detail":"detail2"}],"from":"<actorid>"});
michael@0 426 trace.expectReceive({"value":"correct response","from":"<actorid>"});
michael@0 427
michael@0 428
michael@0 429 do_check_eq(set.size, 0);
michael@0 430 });
michael@0 431 }).then(ret => {
michael@0 432 return rootFront.getManyChildren();
michael@0 433 }).then(ret => {
michael@0 434 trace.expectSend({"type":"getManyChildren","to":"<actorid>"});
michael@0 435 trace.expectReceive({"foo":"bar","child5":{"actor":"<actorid>","childID":"child5"},"more":[{"actor":"<actorid>","childID":"child6"},{"actor":"<actorid>","childID":"child7"}],"from":"<actorid>"});
michael@0 436
michael@0 437 // Check all the crazy stuff we did in getManyChildren
michael@0 438 do_check_eq(ret.foo, "bar");
michael@0 439 do_check_eq(ret.child5.childID, "child5");
michael@0 440 do_check_eq(ret.more[0].childID, "child6");
michael@0 441 do_check_eq(ret.more[1].childID, "child7");
michael@0 442 }).then(() => {
michael@0 443 client.close(() => {
michael@0 444 do_test_finished();
michael@0 445 });
michael@0 446 }).then(null, err => {
michael@0 447 do_report_unexpected_exception(err, "Failure executing test");
michael@0 448 });
michael@0 449 });
michael@0 450 do_test_pending();
michael@0 451 }

mercurial