Bug 1358715 - Queue NetworkEventUpdate in netmonitor controller r=Honza
authorRicky Chien <ricky060709@gmail.com>
Tue, 25 Apr 2017 14:13:05 +0800
changeset 567688 dd7f584c9dcb06b684c066e6fb4538b5fb13e8af
parent 567687 a01a94c69531fb976977c3a3f66fe0e9d29ba907
child 567689 415180322f1a76ec5417108d433d68fe226604e5
push id55664
push userbmo:standard8@mozilla.com
push dateTue, 25 Apr 2017 11:49:25 +0000
reviewersHonza
bugs1358715
milestone55.0a1
Bug 1358715 - Queue NetworkEventUpdate in netmonitor controller r=Honza MozReview-Commit-ID: JyOV95mb7ci
devtools/client/netmonitor/src/netmonitor-controller.js
devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
devtools/client/netmonitor/test/browser_net_simple-request-data.js
--- a/devtools/client/netmonitor/src/netmonitor-controller.js
+++ b/devtools/client/netmonitor/src/netmonitor-controller.js
@@ -289,16 +289,17 @@ var NetMonitorController = {
     }
   },
 };
 
 /**
  * Functions handling target network events.
  */
 function NetworkEventsHandler() {
+  this.payloadQueue = [];
   this.addRequest = this.addRequest.bind(this);
   this.updateRequest = this.updateRequest.bind(this);
   this._onNetworkEvent = this._onNetworkEvent.bind(this);
   this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
   this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this);
   this._onRequestHeaders = this._onRequestHeaders.bind(this);
   this._onRequestCookies = this._onRequestCookies.bind(this);
   this._onRequestPostData = this._onRequestPostData.bind(this);
@@ -522,16 +523,37 @@ NetworkEventsHandler.prototype = {
         if (reqCookies.length) {
           payload.requestCookies = reqCookies;
         }
       }
     }
     return payload;
   },
 
+  getPayloadFromQueue(id) {
+    return this.payloadQueue.find((item) => item.id === id);
+  },
+
+  // Packet order of "networkUpdateEvent" is predictable, as a result we can wait for
+  // the last one "eventTimings" packet arrives to check payload is ready
+  isQueuePayloadReady(id) {
+    let queuedPayload = this.getPayloadFromQueue(id);
+    return queuedPayload && queuedPayload.payload.eventTimings;
+  },
+
+  pushPayloadToQueue(id, payload) {
+    let queuedPayload = this.getPayloadFromQueue(id);
+    if (!queuedPayload) {
+      this.payloadQueue.push({ id, payload });
+    } else {
+      // Merge upcoming networkEventUpdate payload into existing one
+      queuedPayload.payload = Object.assign({}, queuedPayload.payload, payload);
+    }
+  },
+
   async updateRequest(id, data) {
     let {
       mimeType,
       responseContent,
       responseCookies,
       responseHeaders,
       requestCookies,
       requestHeaders,
@@ -553,17 +575,22 @@ NetworkEventsHandler.prototype = {
       this.fetchPostData(requestPostData),
       this.fetchRequestCookies(requestCookies),
       this.fetchResponseCookies(responseCookies),
     ]);
 
     let payload = Object.assign({}, data,
                                     imageObj, requestHeadersObj, responseHeadersObj,
                                     postDataObj, requestCookiesObj, responseCookiesObj);
-    await this.actions.updateRequest(id, payload, true);
+
+    this.pushPayloadToQueue(id, payload);
+
+    if (this.isQueuePayloadReady(id)) {
+      await this.actions.updateRequest(id, this.getPayloadFromQueue(id).payload, true);
+    }
   },
 
   /**
    * The "networkEventUpdate" message type handler.
    *
    * @param string type
    *        Message type.
    * @param object packet
--- a/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
+++ b/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
@@ -63,16 +63,17 @@ add_task(function* () {
        "Security state has not yet arrived.");
     is(!!document.querySelector("#security-tab"), testcase.visibleOnNewEvent,
       "Security tab is " + (testcase.visibleOnNewEvent ? "visible" : "hidden") +
       " after new request was added to the menu.");
 
     info("Waiting for security information to arrive.");
     yield onSecurityInfo;
 
+    yield waitUntil(() => !!getSelectedRequest(gStore.getState()).securityState);
     ok(getSelectedRequest(gStore.getState()).securityState,
        "Security state arrived.");
     is(!!document.querySelector("#security-tab"), testcase.visibleOnSecurityInfo,
        "Security tab is " + (testcase.visibleOnSecurityInfo ? "visible" : "hidden") +
        " after security information arrived.");
 
     info("Waiting for request to complete.");
     yield onComplete;
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js
@@ -86,18 +86,24 @@ function test() {
         document,
         getDisplayedRequests(gStore.getState()),
         requestItem,
         "GET",
         SIMPLE_SJS
       );
     });
 
-    monitor.panelWin.once(EVENTS.RECEIVED_REQUEST_HEADERS, () => {
+    monitor.panelWin.once(EVENTS.RECEIVED_REQUEST_HEADERS, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.requestHeaders;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
+
       ok(requestItem.requestHeaders,
         "There should be a requestHeaders data available.");
       is(requestItem.requestHeaders.headers.length, 10,
         "The requestHeaders data has an incorrect |headers| property.");
       isnot(requestItem.requestHeaders.headersSize, 0,
         "The requestHeaders data has an incorrect |headersSize| property.");
       // Can't test for the exact request headers size because the value may
       // vary across platforms ("User-Agent" header differs).
@@ -106,17 +112,22 @@ function test() {
         document,
         getDisplayedRequests(gStore.getState()),
         requestItem,
         "GET",
         SIMPLE_SJS
       );
     });
 
-    monitor.panelWin.once(EVENTS.RECEIVED_REQUEST_COOKIES, () => {
+    monitor.panelWin.once(EVENTS.RECEIVED_REQUEST_COOKIES, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.requestCookies;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       ok(requestItem.requestCookies,
         "There should be a requestCookies data available.");
       is(requestItem.requestCookies.cookies.length, 2,
         "The requestCookies data has an incorrect |cookies| property.");
 
       verifyRequestItemTarget(
@@ -127,17 +138,22 @@ function test() {
         SIMPLE_SJS
       );
     });
 
     monitor.panelWin.once(EVENTS.RECEIVED_REQUEST_POST_DATA, () => {
       ok(false, "Trap listener: this request doesn't have any post data.");
     });
 
-    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_HEADERS, () => {
+    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_HEADERS, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.responseHeaders;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       ok(requestItem.responseHeaders,
         "There should be a responseHeaders data available.");
       is(requestItem.responseHeaders.headers.length, 10,
         "The responseHeaders data has an incorrect |headers| property.");
       is(requestItem.responseHeaders.headersSize, 330,
         "The responseHeaders data has an incorrect |headersSize| property.");
@@ -146,34 +162,47 @@ function test() {
         document,
         getDisplayedRequests(gStore.getState()),
         requestItem,
         "GET",
         SIMPLE_SJS
       );
     });
 
-    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_COOKIES, () => {
+    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_COOKIES, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.responseCookies;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       ok(requestItem.responseCookies,
         "There should be a responseCookies data available.");
       is(requestItem.responseCookies.cookies.length, 2,
         "The responseCookies data has an incorrect |cookies| property.");
 
       verifyRequestItemTarget(
         document,
         getDisplayedRequests(gStore.getState()),
         requestItem,
         "GET",
         SIMPLE_SJS
       );
     });
 
-    monitor.panelWin.once(EVENTS.STARTED_RECEIVING_RESPONSE, () => {
+    monitor.panelWin.once(EVENTS.STARTED_RECEIVING_RESPONSE, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.httpVersion &&
+               requestItem.status &&
+               requestItem.statusText &&
+               requestItem.headersSize;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       is(requestItem.httpVersion, "HTTP/1.1",
         "The httpVersion data has an incorrect value.");
       is(requestItem.status, "200",
         "The status data has an incorrect value.");
       is(requestItem.statusText, "Och Aye",
         "The statusText data has an incorrect value.");
@@ -188,17 +217,25 @@ function test() {
         SIMPLE_SJS,
         {
           status: "200",
           statusText: "Och Aye"
         }
       );
     });
 
-    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT, () => {
+    monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.transferredSize &&
+               requestItem.contentSize &&
+               requestItem.mimeType &&
+               requestItem.responseContent;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       is(requestItem.transferredSize, "12",
         "The transferredSize data has an incorrect value.");
       is(requestItem.contentSize, "12",
         "The contentSize data has an incorrect value.");
       is(requestItem.mimeType, "text/plain; charset=utf-8",
         "The mimeType data has an incorrect value.");
@@ -228,17 +265,22 @@ function test() {
           type: "plain",
           fullMimeType: "text/plain; charset=utf-8",
           transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
           size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
         }
       );
     });
 
-    monitor.panelWin.once(EVENTS.UPDATING_EVENT_TIMINGS, () => {
+    monitor.panelWin.once(EVENTS.UPDATING_EVENT_TIMINGS, async () => {
+      await waitUntil(() => {
+        let requestItem = getSortedRequests(gStore.getState()).get(0);
+        return requestItem.eventTimings;
+      });
+
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       is(typeof requestItem.totalTime, "number",
         "The attached totalTime is incorrect.");
       ok(requestItem.totalTime >= 0,
         "The attached totalTime should be positive.");
 
       verifyRequestItemTarget(