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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/devtools/server/tests/unit/test_protocol_children.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,451 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +/**
     1.8 + * Test simple requests using the protocol helpers.
     1.9 + */
    1.10 +let protocol = devtools.require("devtools/server/protocol");
    1.11 +let {method, preEvent, types, Arg, Option, RetVal} = protocol;
    1.12 +
    1.13 +let events = devtools.require("sdk/event/core");
    1.14 +
    1.15 +function simpleHello() {
    1.16 +  return {
    1.17 +    from: "root",
    1.18 +    applicationType: "xpcshell-tests",
    1.19 +    traits: [],
    1.20 +  }
    1.21 +}
    1.22 +
    1.23 +let testTypes = {};
    1.24 +
    1.25 +// Predeclaring the actor type so that it can be used in the
    1.26 +// implementation of the child actor.
    1.27 +types.addActorType("childActor");
    1.28 +
    1.29 +let ChildActor = protocol.ActorClass({
    1.30 +  typeName: "childActor",
    1.31 +
    1.32 +  // Actors returned by this actor should be owned by the root actor.
    1.33 +  marshallPool: function() { return this.parent() },
    1.34 +
    1.35 +  toString: function() "[ChildActor " + this.childID + "]",
    1.36 +
    1.37 +  initialize: function(conn, id) {
    1.38 +    protocol.Actor.prototype.initialize.call(this, conn);
    1.39 +    this.childID = id;
    1.40 +  },
    1.41 +
    1.42 +  destroy: function() {
    1.43 +    protocol.Actor.prototype.destroy.call(this);
    1.44 +    this.destroyed = true;
    1.45 +  },
    1.46 +
    1.47 +  form: function(detail) {
    1.48 +    if (detail === "actorid") {
    1.49 +      return this.actorID;
    1.50 +    }
    1.51 +    return {
    1.52 +      actor: this.actorID,
    1.53 +      childID: this.childID,
    1.54 +      detail: detail
    1.55 +    };
    1.56 +  },
    1.57 +
    1.58 +  echo: method(function(str) {
    1.59 +    return str;
    1.60 +  }, {
    1.61 +    request: { str: Arg(0) },
    1.62 +    response: { str: RetVal("string") },
    1.63 +    telemetry: "ECHO"
    1.64 +  }),
    1.65 +
    1.66 +  getDetail1: method(function() {
    1.67 +    return this;
    1.68 +  }, {
    1.69 +    // This also exercises return-value-as-packet.
    1.70 +    response: RetVal("childActor#detail1"),
    1.71 +  }),
    1.72 +
    1.73 +  getDetail2: method(function() {
    1.74 +    return this;
    1.75 +  }, {
    1.76 +    // This also exercises return-value-as-packet.
    1.77 +    response: RetVal("childActor#detail2"),
    1.78 +  }),
    1.79 +
    1.80 +  getIDDetail: method(function() {
    1.81 +    return this;
    1.82 +  }, {
    1.83 +    response: {
    1.84 +      idDetail: RetVal("childActor#actorid")
    1.85 +    }
    1.86 +  }),
    1.87 +
    1.88 +  getSibling: method(function(id) {
    1.89 +    return this.parent().getChild(id);
    1.90 +  }, {
    1.91 +    request: { id: Arg(0) },
    1.92 +    response: { sibling: RetVal("childActor") }
    1.93 +  }),
    1.94 +
    1.95 +  emitEvents: method(function() {
    1.96 +    events.emit(this, "event1", 1, 2, 3);
    1.97 +    events.emit(this, "named-event", 1, 2, 3);
    1.98 +    events.emit(this, "object-event", this);
    1.99 +    events.emit(this, "array-object-event", [this]);
   1.100 +  }, {
   1.101 +    response: { value: "correct response" },
   1.102 +  }),
   1.103 +
   1.104 +  release: method(function() { }, { release: true }),
   1.105 +
   1.106 +  events: {
   1.107 +    "event1" : {
   1.108 +      a: Arg(0),
   1.109 +      b: Arg(1),
   1.110 +      c: Arg(2)
   1.111 +    },
   1.112 +    "named-event": {
   1.113 +      type: "namedEvent",
   1.114 +      a: Arg(0),
   1.115 +      b: Arg(1),
   1.116 +      c: Arg(2)
   1.117 +    },
   1.118 +    "object-event": {
   1.119 +      type: "objectEvent",
   1.120 +      detail: Arg(0, "childActor#detail1"),
   1.121 +    },
   1.122 +    "array-object-event": {
   1.123 +      type: "arrayObjectEvent",
   1.124 +      detail: Arg(0, "array:childActor#detail2"),
   1.125 +    }
   1.126 +  }
   1.127 +});
   1.128 +
   1.129 +let ChildFront = protocol.FrontClass(ChildActor, {
   1.130 +  initialize: function(client, form) {
   1.131 +    protocol.Front.prototype.initialize.call(this, client, form);
   1.132 +  },
   1.133 +
   1.134 +  destroy: function() {
   1.135 +    this.destroyed = true;
   1.136 +    protocol.Front.prototype.destroy.call(this);
   1.137 +  },
   1.138 +
   1.139 +  marshallPool: function() { return this.parent() },
   1.140 +
   1.141 +  toString: function() "[child front " + this.childID + "]",
   1.142 +
   1.143 +  form: function(form, detail) {
   1.144 +    if (detail === "actorid") {
   1.145 +      return;
   1.146 +    }
   1.147 +    this.childID = form.childID;
   1.148 +    this.detail = form.detail;
   1.149 +  },
   1.150 +
   1.151 +  onEvent1: preEvent("event1", function(a, b, c) {
   1.152 +    this.event1arg3 = c;
   1.153 +  }),
   1.154 +});
   1.155 +
   1.156 +types.addDictType("manyChildrenDict", {
   1.157 +  child5: "childActor",
   1.158 +  more: "array:childActor",
   1.159 +});
   1.160 +
   1.161 +types.addLifetime("temp", "_temporaryHolder");
   1.162 +
   1.163 +let rootActor = null;
   1.164 +let RootActor = protocol.ActorClass({
   1.165 +  typeName: "root",
   1.166 +
   1.167 +  toString: function() "[root actor]",
   1.168 +
   1.169 +  initialize: function(conn) {
   1.170 +    rootActor = this;
   1.171 +    this.actorID = "root";
   1.172 +    this._children = {};
   1.173 +    protocol.Actor.prototype.initialize.call(this, conn);
   1.174 +    // Root actor owns itself.
   1.175 +    this.manage(this);
   1.176 +  },
   1.177 +
   1.178 +  sayHello: simpleHello,
   1.179 +
   1.180 +  getChild: method(function(id) {
   1.181 +    if (id in this._children) {
   1.182 +      return this._children[id];
   1.183 +    }
   1.184 +    let child = new ChildActor(this.conn, id);
   1.185 +    this._children[id] = child;
   1.186 +    return child;
   1.187 +  }, {
   1.188 +    request: { str: Arg(0) },
   1.189 +    response: { actor: RetVal("childActor") },
   1.190 +  }),
   1.191 +
   1.192 +  getChildren: method(function(ids) {
   1.193 +    return [this.getChild(id) for (id of ids)];
   1.194 +  }, {
   1.195 +    request: { ids: Arg(0, "array:string") },
   1.196 +    response: { children: RetVal("array:childActor") },
   1.197 +  }),
   1.198 +
   1.199 +  getManyChildren: method(function() {
   1.200 +    return {
   1.201 +      foo: "bar", // note that this isn't in the specialization array.
   1.202 +      child5: this.getChild("child5"),
   1.203 +      more: [ this.getChild("child6"), this.getChild("child7") ]
   1.204 +    }
   1.205 +  }, {
   1.206 +    response: RetVal("manyChildrenDict")
   1.207 +  }),
   1.208 +
   1.209 +  // This should remind you of a pause actor.
   1.210 +  getTemporaryChild: method(function(id) {
   1.211 +    if (!this._temporaryHolder) {
   1.212 +      this._temporaryHolder = this.manage(new protocol.Actor(this.conn));
   1.213 +    }
   1.214 +    return new ChildActor(this.conn, id);
   1.215 +  }, {
   1.216 +    request: { id: Arg(0) },
   1.217 +    response: { child: RetVal("temp:childActor") }
   1.218 +  }),
   1.219 +
   1.220 +  clearTemporaryChildren: method(function(id) {
   1.221 +    if (!this._temporaryHolder) {
   1.222 +      return;
   1.223 +    }
   1.224 +    this._temporaryHolder.destroy();
   1.225 +    delete this._temporaryHolder;
   1.226 +  })
   1.227 +});
   1.228 +
   1.229 +let RootFront = protocol.FrontClass(RootActor, {
   1.230 +  toString: function() "[root front]",
   1.231 +  initialize: function(client) {
   1.232 +    this.actorID = "root";
   1.233 +    protocol.Front.prototype.initialize.call(this, client);
   1.234 +    // Root actor owns itself.
   1.235 +    this.manage(this);
   1.236 +  },
   1.237 +
   1.238 +  getTemporaryChild: protocol.custom(function(id) {
   1.239 +    if (!this._temporaryHolder) {
   1.240 +      this._temporaryHolder = this.manage(new protocol.Front(this.conn, {actor: this.actorID + "_temp"}));
   1.241 +    }
   1.242 +    return this._getTemporaryChild(id);
   1.243 +  },{
   1.244 +   impl: "_getTemporaryChild"
   1.245 +  }),
   1.246 +
   1.247 +  clearTemporaryChildren: protocol.custom(function() {
   1.248 +    if (!this._temporaryHolder) {
   1.249 +      return promise.resolve(undefined);
   1.250 +    }
   1.251 +    this._temporaryHolder.destroy();
   1.252 +    delete this._temporaryHolder;
   1.253 +    return this._clearTemporaryChildren();
   1.254 +  }, {
   1.255 +    impl: "_clearTemporaryChildren"
   1.256 +  })
   1.257 +});
   1.258 +
   1.259 +function run_test()
   1.260 +{
   1.261 +  DebuggerServer.createRootActor = (conn => {
   1.262 +    return RootActor(conn);
   1.263 +  });
   1.264 +  DebuggerServer.init(() => true);
   1.265 +
   1.266 +  let trace = connectPipeTracing();
   1.267 +  let client = new DebuggerClient(trace);
   1.268 +  client.connect((applicationType, traits) => {
   1.269 +    trace.expectReceive({"from":"<actorid>","applicationType":"xpcshell-tests","traits":[]})
   1.270 +    do_check_eq(applicationType, "xpcshell-tests");
   1.271 +
   1.272 +    let rootFront = RootFront(client);
   1.273 +    let childFront = null;
   1.274 +
   1.275 +    let expectRootChildren = size => {
   1.276 +      do_check_eq(rootActor._poolMap.size, size + 1);
   1.277 +      do_check_eq(rootFront._poolMap.size, size + 1);
   1.278 +      if (childFront) {
   1.279 +        do_check_eq(childFront._poolMap.size, 0);
   1.280 +      }
   1.281 +    };
   1.282 +
   1.283 +    rootFront.getChild("child1").then(ret => {
   1.284 +      trace.expectSend({"type":"getChild","str":"child1","to":"<actorid>"})
   1.285 +      trace.expectReceive({"actor":"<actorid>","from":"<actorid>"})
   1.286 +
   1.287 +      childFront = ret;
   1.288 +      do_check_true(childFront instanceof ChildFront);
   1.289 +      do_check_eq(childFront.childID, "child1");
   1.290 +      expectRootChildren(1);
   1.291 +    }).then(() => {
   1.292 +      // Request the child again, make sure the same is returned.
   1.293 +      return rootFront.getChild("child1");
   1.294 +    }).then(ret => {
   1.295 +      trace.expectSend({"type":"getChild","str":"child1","to":"<actorid>"})
   1.296 +      trace.expectReceive({"actor":"<actorid>","from":"<actorid>"})
   1.297 +
   1.298 +      expectRootChildren(1);
   1.299 +      do_check_true(ret === childFront);
   1.300 +    }).then(() => {
   1.301 +      return childFront.echo("hello");
   1.302 +    }).then(ret => {
   1.303 +      trace.expectSend({"type":"echo","str":"hello","to":"<actorid>"})
   1.304 +      trace.expectReceive({"str":"hello","from":"<actorid>"})
   1.305 +
   1.306 +      do_check_eq(ret, "hello");
   1.307 +    }).then(() => {
   1.308 +      return childFront.getDetail1();
   1.309 +    }).then(ret => {
   1.310 +      trace.expectSend({"type":"getDetail1","to":"<actorid>"});
   1.311 +      trace.expectReceive({"actor":"<actorid>","childID":"child1","detail":"detail1","from":"<actorid>"});
   1.312 +      do_check_true(ret === childFront);
   1.313 +      do_check_eq(childFront.detail, "detail1");
   1.314 +    }).then(() => {
   1.315 +      return childFront.getDetail2();
   1.316 +    }).then(ret => {
   1.317 +      trace.expectSend({"type":"getDetail2","to":"<actorid>"});
   1.318 +      trace.expectReceive({"actor":"<actorid>","childID":"child1","detail":"detail2","from":"<actorid>"});
   1.319 +      do_check_true(ret === childFront);
   1.320 +      do_check_eq(childFront.detail, "detail2");
   1.321 +    }).then(() => {
   1.322 +      return childFront.getIDDetail();
   1.323 +    }).then(ret => {
   1.324 +      trace.expectSend({"type":"getIDDetail","to":"<actorid>"});
   1.325 +      trace.expectReceive({"idDetail": childFront.actorID,"from":"<actorid>"});
   1.326 +      do_check_true(ret === childFront);
   1.327 +    }).then(() => {
   1.328 +      return childFront.getSibling("siblingID");
   1.329 +    }).then(ret => {
   1.330 +      trace.expectSend({"type":"getSibling","id":"siblingID","to":"<actorid>"});
   1.331 +      trace.expectReceive({"sibling":{"actor":"<actorid>","childID":"siblingID"},"from":"<actorid>"});
   1.332 +
   1.333 +      expectRootChildren(2);
   1.334 +    }).then(ret => {
   1.335 +      return rootFront.getTemporaryChild("temp1").then(temp1 => {
   1.336 +        trace.expectSend({"type":"getTemporaryChild","id":"temp1","to":"<actorid>"});
   1.337 +        trace.expectReceive({"child":{"actor":"<actorid>","childID":"temp1"},"from":"<actorid>"});
   1.338 +
   1.339 +        // At this point we expect two direct children, plus the temporary holder
   1.340 +        // which should hold 1 itself.
   1.341 +        do_check_eq(rootActor._temporaryHolder.__poolMap.size, 1);
   1.342 +        do_check_eq(rootFront._temporaryHolder.__poolMap.size, 1);
   1.343 +
   1.344 +        expectRootChildren(3);
   1.345 +        return rootFront.getTemporaryChild("temp2").then(temp2 => {
   1.346 +          trace.expectSend({"type":"getTemporaryChild","id":"temp2","to":"<actorid>"});
   1.347 +          trace.expectReceive({"child":{"actor":"<actorid>","childID":"temp2"},"from":"<actorid>"});
   1.348 +
   1.349 +          // Same amount of direct children, and an extra in the temporary holder.
   1.350 +          expectRootChildren(3);
   1.351 +          do_check_eq(rootActor._temporaryHolder.__poolMap.size, 2);
   1.352 +          do_check_eq(rootFront._temporaryHolder.__poolMap.size, 2);
   1.353 +
   1.354 +          // Get the children of the temporary holder...
   1.355 +          let checkActors = [entry[1] for (entry of rootActor._temporaryHolder.__poolMap)];
   1.356 +          let checkFronts = [entry[1] for (entry of rootFront._temporaryHolder.__poolMap)];
   1.357 +
   1.358 +          // Now release the temporary holders and expect them to drop again.
   1.359 +          return rootFront.clearTemporaryChildren().then(() => {
   1.360 +            trace.expectSend({"type":"clearTemporaryChildren","to":"<actorid>"});
   1.361 +            trace.expectReceive({"from":"<actorid>"});
   1.362 +
   1.363 +            expectRootChildren(2);
   1.364 +            do_check_false(!!rootActor._temporaryHolder);
   1.365 +            do_check_false(!!rootFront._temporaryHolder);
   1.366 +            for (let checkActor of checkActors) {
   1.367 +              do_check_true(checkActor.destroyed);
   1.368 +              do_check_true(checkActor.destroyed);
   1.369 +            }
   1.370 +          });
   1.371 +        });
   1.372 +      })
   1.373 +    }).then(ret => {
   1.374 +      return rootFront.getChildren(["child1", "child2"]);
   1.375 +    }).then(ret => {
   1.376 +      trace.expectSend({"type":"getChildren","ids":["child1","child2"],"to":"<actorid>"});
   1.377 +      trace.expectReceive({"children":[{"actor":"<actorid>","childID":"child1"},{"actor":"<actorid>","childID":"child2"}],"from":"<actorid>"});
   1.378 +
   1.379 +      expectRootChildren(3);
   1.380 +      do_check_true(ret[0] === childFront);
   1.381 +      do_check_true(ret[1] !== childFront);
   1.382 +      do_check_true(ret[1] instanceof ChildFront);
   1.383 +
   1.384 +      // On both children, listen to events.  We're only
   1.385 +      // going to trigger events on the first child, so an event
   1.386 +      // triggered on the second should cause immediate failures.
   1.387 +
   1.388 +      let set = new Set(["event1", "named-event", "object-event", "array-object-event"]);
   1.389 +
   1.390 +      childFront.on("event1", (a, b, c) => {
   1.391 +        do_check_eq(a, 1);
   1.392 +        do_check_eq(b, 2);
   1.393 +        do_check_eq(c, 3);
   1.394 +        // Verify that the pre-event handler was called.
   1.395 +        do_check_eq(childFront.event1arg3, 3);
   1.396 +        set.delete("event1");
   1.397 +      });
   1.398 +      childFront.on("named-event", (a, b, c) => {
   1.399 +        do_check_eq(a, 1);
   1.400 +        do_check_eq(b, 2);
   1.401 +        do_check_eq(c, 3);
   1.402 +        set.delete("named-event");
   1.403 +      });
   1.404 +      childFront.on("object-event", (obj) => {
   1.405 +        do_check_true(obj === childFront);
   1.406 +        do_check_eq(childFront.detail, "detail1");
   1.407 +        set.delete("object-event");
   1.408 +      });
   1.409 +      childFront.on("array-object-event", (array) => {
   1.410 +        do_check_true(array[0] === childFront);
   1.411 +        do_check_eq(childFront.detail, "detail2");
   1.412 +        set.delete("array-object-event");
   1.413 +      });
   1.414 +
   1.415 +      let fail = function() {
   1.416 +        do_throw("Unexpected event");
   1.417 +      }
   1.418 +      ret[1].on("event1", fail);
   1.419 +      ret[1].on("named-event", fail);
   1.420 +      ret[1].on("object-event", fail);
   1.421 +      ret[1].on("array-object-event", fail);
   1.422 +
   1.423 +      return childFront.emitEvents().then(() => {
   1.424 +        trace.expectSend({"type":"emitEvents","to":"<actorid>"});
   1.425 +        trace.expectReceive({"type":"event1","a":1,"b":2,"c":3,"from":"<actorid>"});
   1.426 +        trace.expectReceive({"type":"namedEvent","a":1,"b":2,"c":3,"from":"<actorid>"});
   1.427 +        trace.expectReceive({"type":"objectEvent","detail":{"actor":"<actorid>","childID":"child1","detail":"detail1"},"from":"<actorid>"});
   1.428 +        trace.expectReceive({"type":"arrayObjectEvent","detail":[{"actor":"<actorid>","childID":"child1","detail":"detail2"}],"from":"<actorid>"});
   1.429 +        trace.expectReceive({"value":"correct response","from":"<actorid>"});
   1.430 +
   1.431 +
   1.432 +        do_check_eq(set.size, 0);
   1.433 +      });
   1.434 +    }).then(ret => {
   1.435 +      return rootFront.getManyChildren();
   1.436 +    }).then(ret => {
   1.437 +      trace.expectSend({"type":"getManyChildren","to":"<actorid>"});
   1.438 +      trace.expectReceive({"foo":"bar","child5":{"actor":"<actorid>","childID":"child5"},"more":[{"actor":"<actorid>","childID":"child6"},{"actor":"<actorid>","childID":"child7"}],"from":"<actorid>"});
   1.439 +
   1.440 +      // Check all the crazy stuff we did in getManyChildren
   1.441 +      do_check_eq(ret.foo, "bar");
   1.442 +      do_check_eq(ret.child5.childID, "child5");
   1.443 +      do_check_eq(ret.more[0].childID, "child6");
   1.444 +      do_check_eq(ret.more[1].childID, "child7");
   1.445 +    }).then(() => {
   1.446 +      client.close(() => {
   1.447 +        do_test_finished();
   1.448 +      });
   1.449 +    }).then(null, err => {
   1.450 +      do_report_unexpected_exception(err, "Failure executing test");
   1.451 +    });
   1.452 +  });
   1.453 +  do_test_pending();
   1.454 +}

mercurial