Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* Notes:
2 - All times are expressed in milliseconds in this test suite.
3 - Test harness code is at the end of this file.
4 - We generate only one request at a time, to avoid overloading the HTTP
5 request handlers.
6 */
8 var inWorker = false;
9 try {
10 inWorker = !(self instanceof Window);
11 } catch (e) {
12 inWorker = true;
13 }
15 function message(data) {
16 if (inWorker)
17 self.postMessage(data);
18 else
19 self.postMessage(data, "*");
20 }
22 function is(got, expected, msg) {
23 var obj = {};
24 obj.type = "is";
25 obj.got = got;
26 obj.expected = expected;
27 obj.msg = msg;
29 message(obj);
30 }
32 function ok(bool, msg) {
33 var obj = {};
34 obj.type = "ok";
35 obj.bool = bool;
36 obj.msg = msg;
38 message(obj);
39 }
41 /**
42 * Generate and track results from a XMLHttpRequest with regards to timeouts.
43 *
44 * @param {String} id The test description.
45 * @param {Number} timeLimit The initial setting for the request timeout.
46 * @param {Number} resetAfter (Optional) The time after sending the request, to
47 * reset the timeout.
48 * @param {Number} resetTo (Optional) The delay to reset the timeout to.
49 *
50 * @note The actual testing takes place in handleEvent(event).
51 * The requests are generated in startXHR().
52 *
53 * @note If resetAfter and resetTo are omitted, only the initial timeout setting
54 * applies.
55 *
56 * @constructor
57 * @implements DOMEventListener
58 */
59 function RequestTracker(async, id, timeLimit /*[, resetAfter, resetTo]*/) {
60 this.async = async;
61 this.id = id;
62 this.timeLimit = timeLimit;
64 if (arguments.length > 3) {
65 this.mustReset = true;
66 this.resetAfter = arguments[3];
67 this.resetTo = arguments[4];
68 }
70 this.hasFired = false;
71 }
72 RequestTracker.prototype = {
73 /**
74 * Start the XMLHttpRequest!
75 */
76 startXHR: function() {
77 var req = new XMLHttpRequest();
78 this.request = req;
79 req.open("GET", "file_XHR_timeout.sjs", this.async);
80 var me = this;
81 function handleEvent(e) { return me.handleEvent(e); };
82 req.onerror = handleEvent;
83 req.onload = handleEvent;
84 req.onabort = handleEvent;
85 req.ontimeout = handleEvent;
87 req.timeout = this.timeLimit;
89 if (this.mustReset) {
90 var resetTo = this.resetTo;
91 self.setTimeout(function() {
92 req.timeout = resetTo;
93 }, this.resetAfter);
94 }
96 req.send(null);
97 },
99 /**
100 * Get a message describing this test.
101 *
102 * @returns {String} The test description.
103 */
104 getMessage: function() {
105 var rv = this.id + ", ";
106 if (this.mustReset) {
107 rv += "original timeout at " + this.timeLimit + ", ";
108 rv += "reset at " + this.resetAfter + " to " + this.resetTo;
109 }
110 else {
111 rv += "timeout scheduled at " + this.timeLimit;
112 }
113 return rv;
114 },
116 /**
117 * Check the event received, and if it's the right (and only) one we get.
118 *
119 * @param {DOMProgressEvent} evt An event of type "load" or "timeout".
120 */
121 handleEvent: function(evt) {
122 if (this.hasFired) {
123 ok(false, "Only one event should fire: " + this.getMessage());
124 return;
125 }
126 this.hasFired = true;
128 var type = evt.type, expectedType;
129 // The XHR responds after 3000 milliseconds with a load event.
130 var timeLimit = this.mustReset && (this.resetAfter < Math.min(3000, this.timeLimit)) ?
131 this.resetTo :
132 this.timeLimit;
133 if ((timeLimit == 0) || (timeLimit >= 3000)) {
134 expectedType = "load";
135 }
136 else {
137 expectedType = "timeout";
138 }
139 is(type, expectedType, this.getMessage());
140 TestCounter.testComplete();
141 }
142 };
144 /**
145 * Generate and track XMLHttpRequests which will have abort() called on.
146 *
147 * @param shouldAbort {Boolean} True if we should call abort at all.
148 * @param abortDelay {Number} The time in ms to wait before calling abort().
149 */
150 function AbortedRequest(shouldAbort, abortDelay) {
151 this.shouldAbort = shouldAbort;
152 this.abortDelay = abortDelay;
153 this.hasFired = false;
154 }
155 AbortedRequest.prototype = {
156 /**
157 * Start the XMLHttpRequest!
158 */
159 startXHR: function() {
160 var req = new XMLHttpRequest();
161 this.request = req;
162 req.open("GET", "file_XHR_timeout.sjs");
163 var me = this;
164 function handleEvent(e) { return me.handleEvent(e); };
165 req.onerror = handleEvent;
166 req.onload = handleEvent;
167 req.onabort = handleEvent;
168 req.ontimeout = handleEvent;
170 req.timeout = 2000;
171 var _this = this;
173 function abortReq() {
174 req.abort();
175 }
177 if (!this.shouldAbort) {
178 self.setTimeout(function() {
179 try {
180 _this.noEventsFired();
181 }
182 catch (e) {
183 ok(false, "Unexpected error: " + e);
184 TestCounter.testComplete();
185 }
186 }, 5000);
187 }
188 else {
189 // Abort events can only be triggered on sent requests.
190 req.send();
191 if (this.abortDelay == -1) {
192 abortReq();
193 }
194 else {
195 self.setTimeout(abortReq, this.abortDelay);
196 }
197 }
198 },
200 /**
201 * Ensure that no events fired at all, especially not our timeout event.
202 */
203 noEventsFired: function() {
204 ok(!this.hasFired, "No events should fire for an unsent, unaborted request");
205 // We're done; if timeout hasn't fired by now, it never will.
206 TestCounter.testComplete();
207 },
209 /**
210 * Get a message describing this test.
211 *
212 * @returns {String} The test description.
213 */
214 getMessage: function() {
215 return "time to abort is " + this.abortDelay + ", timeout set at 2000";
216 },
218 /**
219 * Check the event received, and if it's the right (and only) one we get.
220 *
221 * @param {DOMProgressEvent} evt An event of type "load" or "timeout".
222 */
223 handleEvent: function(evt) {
224 if (this.hasFired) {
225 ok(false, "Only abort event should fire: " + this.getMessage());
226 return;
227 }
228 this.hasFired = true;
230 var expectedEvent = (this.abortDelay >= 2000) ? "timeout" : "abort";
231 is(evt.type, expectedEvent, this.getMessage());
232 TestCounter.testComplete();
233 }
234 };
236 var SyncRequestSettingTimeoutAfterOpen = {
237 startXHR: function() {
238 var pass = false;
239 var req = new XMLHttpRequest();
240 req.open("GET", "file_XHR_timeout.sjs", false);
241 try {
242 req.timeout = 1000;
243 }
244 catch (e) {
245 pass = true;
246 }
247 ok(pass, "Synchronous XHR must not allow a timeout to be set");
248 TestCounter.testComplete();
249 }
250 };
252 var SyncRequestSettingTimeoutBeforeOpen = {
253 startXHR: function() {
254 var pass = false;
255 var req = new XMLHttpRequest();
256 req.timeout = 1000;
257 try {
258 req.open("GET", "file_XHR_timeout.sjs", false);
259 }
260 catch (e) {
261 pass = true;
262 }
263 ok(pass, "Synchronous XHR must not allow a timeout to be set");
264 TestCounter.testComplete();
265 }
266 };
268 var TestRequests = [
269 // Simple timeouts.
270 new RequestTracker(true, "no time out scheduled, load fires normally", 0),
271 new RequestTracker(true, "load fires normally", 5000),
272 new RequestTracker(true, "timeout hit before load", 2000),
274 // Timeouts reset after a certain delay.
275 new RequestTracker(true, "load fires normally with no timeout set, twice", 0, 2000, 0),
276 new RequestTracker(true, "load fires normally with same timeout set twice", 5000, 2000, 5000),
277 new RequestTracker(true, "timeout fires normally with same timeout set twice", 2000, 1000, 2000),
279 new RequestTracker(true, "timeout disabled after initially set", 5000, 2000, 0),
280 new RequestTracker(true, "timeout overrides load after a delay", 5000, 1000, 2000),
281 new RequestTracker(true, "timeout enabled after initially disabled", 0, 2000, 5000),
283 new RequestTracker(true, "timeout set to expiring value after load fires", 5000, 4000, 1000),
284 new RequestTracker(true, "timeout set to expired value before load fires", 5000, 2000, 1000),
285 new RequestTracker(true, "timeout set to non-expiring value after timeout fires", 1000, 2000, 5000),
287 // Aborted requests.
288 new AbortedRequest(false),
289 new AbortedRequest(true, -1),
290 new AbortedRequest(true, 5000),
291 ];
293 var MainThreadTestRequests = [
294 new AbortedRequest(true, 0),
295 new AbortedRequest(true, 1000),
297 // Synchronous requests.
298 SyncRequestSettingTimeoutAfterOpen,
299 SyncRequestSettingTimeoutBeforeOpen
300 ];
302 var WorkerThreadTestRequests = [
303 // Simple timeouts.
304 new RequestTracker(false, "no time out scheduled, load fires normally", 0),
305 new RequestTracker(false, "load fires normally", 5000),
306 new RequestTracker(false, "timeout hit before load", 2000),
308 // Reset timeouts don't make much sense with a sync request ...
309 ];
311 if (inWorker) {
312 TestRequests = TestRequests.concat(WorkerThreadTestRequests);
313 } else {
314 TestRequests = TestRequests.concat(MainThreadTestRequests);
315 }
317 // This code controls moving from one test to another.
318 var TestCounter = {
319 testComplete: function() {
320 // Allow for the possibility there are other events coming.
321 self.setTimeout(function() {
322 TestCounter.next();
323 }, 5000);
324 },
326 next: function() {
327 var test = TestRequests.shift();
329 if (test) {
330 test.startXHR();
331 }
332 else {
333 message("done");
334 }
335 }
336 };
338 self.addEventListener("message", function (event) {
339 if (event.data == "start") {
340 TestCounter.next();
341 }
342 });