Bug 1244227 - Add an API to enable throttling. r=Honza draft
authorTom Tromey <tom@tromey.com>
Tue, 01 Mar 2016 11:13:41 -0700
changeset 396356 e2c942b6feb1cd9ce5a37d700518b99047cb1cde
parent 396355 89ff34f8f432795a53a34aa875d0c06f79f79e15
child 396357 0687b6d6af6a2ecff82d016ff74f396afd29e21f
push id24964
push userbmo:ttromey@mozilla.com
push dateWed, 03 Aug 2016 17:20:57 +0000
reviewersHonza
bugs1244227
milestone51.0a1
Bug 1244227 - Add an API to enable throttling. r=Honza MozReview-Commit-ID: BirjFHVSZN7
devtools/client/netmonitor/har/test/browser.ini
devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js
devtools/client/netmonitor/har/test/html_har_post-data-test-page.html
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_throttle.js
devtools/client/webconsole/webconsole.js
devtools/server/actors/webconsole.js
devtools/shared/webconsole/network-monitor.js
--- a/devtools/client/netmonitor/har/test/browser.ini
+++ b/devtools/client/netmonitor/har/test/browser.ini
@@ -4,8 +4,9 @@ subsuite = clipboard
 support-files =
   head.js
   html_har_post-data-test-page.html
   !/devtools/client/netmonitor/test/head.js
   !/devtools/client/netmonitor/test/html_simple-test-page.html
 
 [browser_net_har_copy_all_as_har.js]
 [browser_net_har_post_data.js]
+[browser_net_har_throttle_upload.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test timing of upload when throttling.
+
+"use strict";
+
+add_task(function* () {
+  let [ , debuggee, monitor ] = yield initNetMonitor(
+    HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
+
+  info("Starting test... ");
+
+  let { NetMonitorView } = monitor.panelWin;
+  let { RequestsMenu } = NetMonitorView;
+
+  const size = 4096;
+  const request = {
+    "NetworkMonitor.throttleData": {
+      roundTripTimeMean: 0,
+      roundTripTimeMax: 0,
+      downloadBPSMean: 200000,
+      downloadBPSMax: 200000,
+      uploadBPSMean: size / 3,
+      uploadBPSMax: size / 3,
+    },
+  };
+  let client = monitor._controller.webConsoleClient;
+
+  info("sending throttle request");
+  let deferred = promise.defer();
+  client.setPreferences(request, response => {
+    deferred.resolve(response);
+  });
+  yield deferred.promise;
+
+  RequestsMenu.lazyUpdate = false;
+
+  // Execute one POST request on the page and wait till its done.
+  debuggee.executeTest2(size);
+  yield waitForNetworkEvents(monitor, 0, 1);
+
+  // Copy HAR into the clipboard (asynchronous).
+  let jsonString = yield RequestsMenu.copyAllAsHar();
+  let har = JSON.parse(jsonString);
+
+  // Check out the HAR log.
+  isnot(har.log, null, "The HAR log must exist");
+  is(har.log.pages.length, 1, "There must be one page");
+  is(har.log.entries.length, 1, "There must be one request");
+
+  let entry = har.log.entries[0];
+  is(entry.request.postData.text, "x".repeat(size),
+     "Check post data payload");
+
+  ok(entry.timings.send >= 2000, "upload should have taken more than 2 seconds");
+
+  // Clean up
+  teardown(monitor).then(finish);
+});
--- a/devtools/client/netmonitor/har/test/html_har_post-data-test-page.html
+++ b/devtools/client/netmonitor/har/test/html_har_post-data-test-page.html
@@ -22,12 +22,18 @@
         xhr.send(aData);
       }
 
       function executeTest() {
         var url = "html_har_post-data-test-page.html";
         var data = "{'first': 'John', 'last': 'Doe'}";
         post(url, data);
       }
+
+      function executeTest2(size) {
+        var url = "html_har_post-data-test-page.html";
+        var data = "x".repeat(size);
+        post(url, data);
+      }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -133,11 +133,12 @@ skip-if = true # Bug 1258809
 skip-if = (e10s && debug && os == 'mac') # Bug 1253037
 [browser_net_sort-02.js]
 [browser_net_sort-03.js]
 [browser_net_statistics-01.js]
 [browser_net_statistics-02.js]
 [browser_net_statistics-03.js]
 [browser_net_status-codes.js]
 [browser_net_streaming-response.js]
+[browser_net_throttle.js]
 [browser_net_timeline_ticks.js]
 [browser_net_timing-division.js]
 [browser_net_persistent_logs.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_throttle.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Network throttling integration test.
+
+"use strict";
+
+add_task(function* () {
+  requestLongerTimeout(2);
+
+  let [, , monitor] = yield initNetMonitor(SIMPLE_URL);
+  const {ACTIVITY_TYPE, NetMonitorController, NetMonitorView} =
+        monitor.panelWin;
+
+  info("Starting test... ");
+
+  const request = {
+    "NetworkMonitor.throttleData": {
+      roundTripTimeMean: 0,
+      roundTripTimeMax: 0,
+      // Must be smaller than the length of the content of SIMPLE_URL
+      // in bytes.
+      downloadBPSMean: 200,
+      downloadBPSMax: 200,
+      uploadBPSMean: 10000,
+      uploadBPSMax: 10000,
+    },
+  };
+  let client = monitor._controller.webConsoleClient;
+
+  info("sending throttle request");
+  let deferred = promise.defer();
+  client.setPreferences(request, response => {
+    deferred.resolve(response);
+  });
+  yield deferred.promise;
+
+  const startTime = Date.now();
+  let eventPromise =
+      monitor.panelWin.once(monitor.panelWin.EVENTS.RECEIVED_EVENT_TIMINGS);
+  yield NetMonitorController
+    .triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED);
+  const endTime = Date.now();
+  ok(endTime - startTime > 1000, "download took more than one second");
+
+  yield eventPromise;
+  let requestItem = NetMonitorView.RequestsMenu.getItemAtIndex(0);
+  ok(requestItem.attachment.eventTimings.timings.receive > 1000,
+     "download reported as taking more than one second");
+
+  yield teardown(monitor);
+  finish();
+});
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -382,16 +382,17 @@ WebConsoleFrame.prototype = {
    */
   get webConsoleClient() {
     return this.proxy ? this.proxy.webConsoleClient : null;
   },
 
   _destroyer: null,
 
   _saveRequestAndResponseBodies: true,
+  _throttleData: null,
 
   // Chevron width at the starting of Web Console's input box.
   _chevronWidth: 0,
   // Width of the monospace characters in Web Console's input box.
   _inputCharWidth: 0,
 
   /**
    * Setter for saving of network request and response bodies.
@@ -420,16 +421,46 @@ WebConsoleFrame.prototype = {
         deferred.reject(response.error);
       }
     });
 
     return deferred.promise;
   },
 
   /**
+   * Setter for throttling data.
+   *
+   * @param boolean value
+   *        The new value you want to set; @see NetworkThrottleManager.
+   */
+  setThrottleData: function(value) {
+    if (!this.webConsoleClient) {
+      // Don't continue if the webconsole disconnected.
+      return promise.resolve(null);
+    }
+
+    let deferred = promise.defer();
+    let toSet = {
+      "NetworkMonitor.throttleData": value,
+    };
+
+    // Make sure the web console client connection is established first.
+    this.webConsoleClient.setPreferences(toSet, response => {
+      if (!response.error) {
+        this._throttleData = value;
+        deferred.resolve(response);
+      } else {
+        deferred.reject(response.error);
+      }
+    });
+
+    return deferred.promise;
+  },
+
+  /**
    * Getter for the persistent logging preference.
    * @type boolean
    */
   get persistLog() {
     // For the browser console, we receive tab navigation
     // when the original top level window we attached to is closed,
     // but we don't want to reset console history and just switch to
     // the next available window.
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -1052,21 +1052,28 @@ WebConsoleActor.prototype =
    * @param object aRequest
    *        The request message - which preferences need to be updated.
    */
   onSetPreferences: function WCA_onSetPreferences(aRequest)
   {
     for (let key in aRequest.preferences) {
       this._prefs[key] = aRequest.preferences[key];
 
-      if (key == "NetworkMonitor.saveRequestAndResponseBodies" &&
-          this.networkMonitor) {
-        this.networkMonitor.saveRequestAndResponseBodies = this._prefs[key];
-        if (this.networkMonitorChild) {
-          this.networkMonitorChild.saveRequestAndResponseBodies = this._prefs[key];
+      if (this.networkMonitor) {
+        if (key == "NetworkMonitor.saveRequestAndResponseBodies") {
+          this.networkMonitor.saveRequestAndResponseBodies = this._prefs[key];
+          if (this.networkMonitorChild) {
+            this.networkMonitorChild.saveRequestAndResponseBodies =
+              this._prefs[key];
+          }
+        } else if (key == "NetworkMonitor.throttleData") {
+          this.networkMonitor.throttleData = this._prefs[key];
+          if (this.networkMonitorChild) {
+            this.networkMonitorChild.throttleData = this._prefs[key];
+          }
         }
       }
     }
     return { updated: Object.keys(aRequest.preferences) };
   },
 
   // ////////////////
   // End of request handlers.
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -1470,32 +1470,49 @@ function NetworkMonitorChild(appId, mess
 
 exports.NetworkMonitorChild = NetworkMonitorChild;
 
 NetworkMonitorChild.prototype = {
   appId: null,
   owner: null,
   _netEvents: null,
   _saveRequestAndResponseBodies: true,
+  _throttleData: null,
 
   get saveRequestAndResponseBodies() {
     return this._saveRequestAndResponseBodies;
   },
 
   set saveRequestAndResponseBodies(val) {
     this._saveRequestAndResponseBodies = val;
 
     this._messageManager.sendAsyncMessage("debug:netmonitor:" + this.connID, {
       action: "setPreferences",
       preferences: {
         saveRequestAndResponseBodies: this._saveRequestAndResponseBodies,
       },
     });
   },
 
+  get throttleData() {
+    return this._throttleData;
+  },
+
+  set throttleData(val) {
+    this._throttleData = val;
+
+    this._messageManager.sendAsyncMessage("debug:netmonitor:" + this.connID, {
+      appId: this.appId,
+      action: "setPreferences",
+      preferences: {
+        throttleData: this._throttleData,
+      },
+    });
+  },
+
   init: function () {
     let mm = this._messageManager;
     mm.addMessageListener("debug:netmonitor:" + this.connID + ":newEvent",
                           this._onNewEvent);
     mm.addMessageListener("debug:netmonitor:" + this.connID + ":updateEvent",
                           this._onUpdateEvent);
     mm.sendAsyncMessage("debug:netmonitor:" + this.connID, {
       appId: this.appId,
@@ -1670,18 +1687,19 @@ NetworkMonitorManager.prototype = {
             appId: appId,
           }, this);
           this.netMonitor.init();
         }
         break;
       case "setPreferences": {
         let {preferences} = msg.json;
         for (let key of Object.keys(preferences)) {
-          if (key == "saveRequestAndResponseBodies" && this.netMonitor) {
-            this.netMonitor.saveRequestAndResponseBodies = preferences[key];
+          if ((key == "saveRequestAndResponseBodies" ||
+               key == "throttleData") && this.netMonitor) {
+            this.netMonitor[key] = preferences[key];
           }
         }
         break;
       }
 
       case "stop":
         if (this.netMonitor) {
           this.netMonitor.destroy();