content/base/test/test_XHR_timeout.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial