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.

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

mercurial