Bug 1244227 - Add an API to enable throttling. r=Honza
MozReview-Commit-ID: BirjFHVSZN7
--- 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();