|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 /** |
|
5 * Make sure we get replies in the same order that we sent their |
|
6 * requests even when earlier requests take several event ticks to |
|
7 * complete. |
|
8 */ |
|
9 |
|
10 let protocol = devtools.require("devtools/server/protocol"); |
|
11 let {method, Arg, Option, RetVal} = protocol; |
|
12 let events = devtools.require("sdk/event/core"); |
|
13 |
|
14 function simpleHello() { |
|
15 return { |
|
16 from: "root", |
|
17 applicationType: "xpcshell-tests", |
|
18 traits: [], |
|
19 } |
|
20 } |
|
21 |
|
22 let RootActor = protocol.ActorClass({ |
|
23 typeName: "root", |
|
24 initialize: function(conn) { |
|
25 protocol.Actor.prototype.initialize.call(this, conn); |
|
26 // Root actor owns itself. |
|
27 this.manage(this); |
|
28 this.actorID = "root"; |
|
29 this.sequence = 0; |
|
30 }, |
|
31 |
|
32 sayHello: simpleHello, |
|
33 |
|
34 simpleReturn: method(function() { |
|
35 return this.sequence++; |
|
36 }, { |
|
37 response: { value: RetVal() }, |
|
38 }), |
|
39 |
|
40 promiseReturn: method(function(toWait) { |
|
41 // Guarantee that this resolves after simpleReturn returns. |
|
42 let deferred = promise.defer(); |
|
43 let sequence = this.sequence++; |
|
44 |
|
45 // Wait until the number of requests specified by toWait have |
|
46 // happened, to test queuing. |
|
47 let check = () => { |
|
48 if ((this.sequence - sequence) < toWait) { |
|
49 do_execute_soon(check); |
|
50 return; |
|
51 } |
|
52 deferred.resolve(sequence); |
|
53 } |
|
54 do_execute_soon(check); |
|
55 |
|
56 return deferred.promise; |
|
57 }, { |
|
58 request: { toWait: Arg(0, "number") }, |
|
59 response: { value: RetVal("number") }, |
|
60 }), |
|
61 |
|
62 simpleThrow: method(function() { |
|
63 throw new Error(this.sequence++); |
|
64 }, { |
|
65 response: { value: RetVal("number") } |
|
66 }), |
|
67 |
|
68 promiseThrow: method(function() { |
|
69 // Guarantee that this resolves after simpleReturn returns. |
|
70 let deferred = promise.defer(); |
|
71 let sequence = this.sequence++; |
|
72 // This should be enough to force a failure if the code is broken. |
|
73 do_timeout(150, () => { |
|
74 deferred.reject(sequence++); |
|
75 }); |
|
76 return deferred.promise; |
|
77 }, { |
|
78 response: { value: RetVal("number") }, |
|
79 }) |
|
80 }); |
|
81 |
|
82 let RootFront = protocol.FrontClass(RootActor, { |
|
83 initialize: function(client) { |
|
84 this.actorID = "root"; |
|
85 protocol.Front.prototype.initialize.call(this, client); |
|
86 // Root owns itself. |
|
87 this.manage(this); |
|
88 } |
|
89 }); |
|
90 |
|
91 function run_test() |
|
92 { |
|
93 DebuggerServer.createRootActor = RootActor; |
|
94 DebuggerServer.init(() => true); |
|
95 |
|
96 let trace = connectPipeTracing(); |
|
97 let client = new DebuggerClient(trace); |
|
98 let rootClient; |
|
99 |
|
100 client.connect((applicationType, traits) => { |
|
101 rootClient = RootFront(client); |
|
102 |
|
103 let calls = []; |
|
104 let sequence = 0; |
|
105 |
|
106 // Execute a call that won't finish processing until 2 |
|
107 // more calls have happened |
|
108 calls.push(rootClient.promiseReturn(2).then(ret => { |
|
109 do_check_eq(sequence, 0); // Check right return order |
|
110 do_check_eq(ret, sequence++); // Check request handling order |
|
111 })); |
|
112 |
|
113 // Put a few requests into the backlog |
|
114 |
|
115 calls.push(rootClient.simpleReturn().then(ret => { |
|
116 do_check_eq(sequence, 1); // Check right return order |
|
117 do_check_eq(ret, sequence++); // Check request handling order |
|
118 })); |
|
119 |
|
120 calls.push(rootClient.simpleReturn().then(ret => { |
|
121 do_check_eq(sequence, 2); // Check right return order |
|
122 do_check_eq(ret, sequence++); // Check request handling order |
|
123 })); |
|
124 |
|
125 calls.push(rootClient.simpleThrow().then(() => { |
|
126 do_check_true(false, "simpleThrow shouldn't succeed!"); |
|
127 }, error => { |
|
128 do_check_eq(sequence++, 3); // Check right return order |
|
129 })); |
|
130 |
|
131 // While packets are sent in the correct order, rejection handlers |
|
132 // registered in "Promise.jsm" may be invoked later than fulfillment |
|
133 // handlers, meaning that we can't check the actual order with certainty. |
|
134 let deferAfterRejection = promise.defer(); |
|
135 |
|
136 calls.push(rootClient.promiseThrow().then(() => { |
|
137 do_check_true(false, "promiseThrow shouldn't succeed!"); |
|
138 }, error => { |
|
139 do_check_eq(sequence++, 4); // Check right return order |
|
140 do_check_true(true, "simple throw should throw"); |
|
141 deferAfterRejection.resolve(); |
|
142 })); |
|
143 |
|
144 calls.push(rootClient.simpleReturn().then(ret => { |
|
145 return deferAfterRejection.promise.then(function () { |
|
146 do_check_eq(sequence, 5); // Check right return order |
|
147 do_check_eq(ret, sequence++); // Check request handling order |
|
148 }); |
|
149 })); |
|
150 |
|
151 // Break up the backlog with a long request that waits |
|
152 // for another simpleReturn before completing |
|
153 calls.push(rootClient.promiseReturn(1).then(ret => { |
|
154 return deferAfterRejection.promise.then(function () { |
|
155 do_check_eq(sequence, 6); // Check right return order |
|
156 do_check_eq(ret, sequence++); // Check request handling order |
|
157 }); |
|
158 })); |
|
159 |
|
160 calls.push(rootClient.simpleReturn().then(ret => { |
|
161 return deferAfterRejection.promise.then(function () { |
|
162 do_check_eq(sequence, 7); // Check right return order |
|
163 do_check_eq(ret, sequence++); // Check request handling order |
|
164 }); |
|
165 })); |
|
166 |
|
167 promise.all(calls).then(() => { |
|
168 client.close(() => { |
|
169 do_test_finished(); |
|
170 }); |
|
171 }) |
|
172 }); |
|
173 do_test_pending(); |
|
174 } |