content/base/test/test_XHR_timeout.js

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

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 });

mercurial