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

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:21e0d3e2af9b
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
3
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;
9
10 let events = devtools.require("sdk/event/core");
11
12 function simpleHello() {
13 return {
14 from: "root",
15 applicationType: "xpcshell-tests",
16 traits: [],
17 }
18 }
19
20 let testTypes = {};
21
22 // Predeclaring the actor type so that it can be used in the
23 // implementation of the child actor.
24 types.addActorType("childActor");
25
26 let ChildActor = protocol.ActorClass({
27 typeName: "childActor",
28
29 // Actors returned by this actor should be owned by the root actor.
30 marshallPool: function() { return this.parent() },
31
32 toString: function() "[ChildActor " + this.childID + "]",
33
34 initialize: function(conn, id) {
35 protocol.Actor.prototype.initialize.call(this, conn);
36 this.childID = id;
37 },
38
39 destroy: function() {
40 protocol.Actor.prototype.destroy.call(this);
41 this.destroyed = true;
42 },
43
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 },
54
55 echo: method(function(str) {
56 return str;
57 }, {
58 request: { str: Arg(0) },
59 response: { str: RetVal("string") },
60 telemetry: "ECHO"
61 }),
62
63 getDetail1: method(function() {
64 return this;
65 }, {
66 // This also exercises return-value-as-packet.
67 response: RetVal("childActor#detail1"),
68 }),
69
70 getDetail2: method(function() {
71 return this;
72 }, {
73 // This also exercises return-value-as-packet.
74 response: RetVal("childActor#detail2"),
75 }),
76
77 getIDDetail: method(function() {
78 return this;
79 }, {
80 response: {
81 idDetail: RetVal("childActor#actorid")
82 }
83 }),
84
85 getSibling: method(function(id) {
86 return this.parent().getChild(id);
87 }, {
88 request: { id: Arg(0) },
89 response: { sibling: RetVal("childActor") }
90 }),
91
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 }),
100
101 release: method(function() { }, { release: true }),
102
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 });
125
126 let ChildFront = protocol.FrontClass(ChildActor, {
127 initialize: function(client, form) {
128 protocol.Front.prototype.initialize.call(this, client, form);
129 },
130
131 destroy: function() {
132 this.destroyed = true;
133 protocol.Front.prototype.destroy.call(this);
134 },
135
136 marshallPool: function() { return this.parent() },
137
138 toString: function() "[child front " + this.childID + "]",
139
140 form: function(form, detail) {
141 if (detail === "actorid") {
142 return;
143 }
144 this.childID = form.childID;
145 this.detail = form.detail;
146 },
147
148 onEvent1: preEvent("event1", function(a, b, c) {
149 this.event1arg3 = c;
150 }),
151 });
152
153 types.addDictType("manyChildrenDict", {
154 child5: "childActor",
155 more: "array:childActor",
156 });
157
158 types.addLifetime("temp", "_temporaryHolder");
159
160 let rootActor = null;
161 let RootActor = protocol.ActorClass({
162 typeName: "root",
163
164 toString: function() "[root actor]",
165
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 },
174
175 sayHello: simpleHello,
176
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 }),
188
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 }),
195
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 }),
205
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 }),
216
217 clearTemporaryChildren: method(function(id) {
218 if (!this._temporaryHolder) {
219 return;
220 }
221 this._temporaryHolder.destroy();
222 delete this._temporaryHolder;
223 })
224 });
225
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 },
234
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 }),
243
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 });
255
256 function run_test()
257 {
258 DebuggerServer.createRootActor = (conn => {
259 return RootActor(conn);
260 });
261 DebuggerServer.init(() => true);
262
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");
268
269 let rootFront = RootFront(client);
270 let childFront = null;
271
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 };
279
280 rootFront.getChild("child1").then(ret => {
281 trace.expectSend({"type":"getChild","str":"child1","to":"<actorid>"})
282 trace.expectReceive({"actor":"<actorid>","from":"<actorid>"})
283
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>"})
294
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>"})
302
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>"});
329
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>"});
335
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);
340
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>"});
345
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);
350
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)];
354
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>"});
359
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>"});
375
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);
380
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.
384
385 let set = new Set(["event1", "named-event", "object-event", "array-object-event"]);
386
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 });
411
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);
419
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>"});
427
428
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>"});
436
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