Bug 1244227 - Add an API to enable throttling. r=Honza

MozReview-Commit-ID: BirjFHVSZN7
This commit is contained in:
Tom Tromey 2016-03-01 11:13:41 -07:00
Родитель e660321898
Коммит 8cfae2d757
9 изменённых файлов: 233 добавлений и 20 удалений

Просмотреть файл

@ -9,3 +9,4 @@ support-files =
[browser_net_har_copy_all_as_har.js]
[browser_net_har_post_data.js]
[browser_net_har_throttle_upload.js]

Просмотреть файл

@ -0,0 +1,72 @@
/* 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* () {
yield throttleUploadTest(true);
yield throttleUploadTest(false);
});
function* throttleUploadTest(actuallyThrottle) {
let [ , debuggee, monitor ] = yield initNetMonitor(
HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
let { NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
const size = 4096;
const uploadSize = actuallyThrottle ? size / 3 : 0;
const request = {
"NetworkMonitor.throttleData": {
roundTripTimeMean: 0,
roundTripTimeMax: 0,
downloadBPSMean: 200000,
downloadBPSMax: 200000,
uploadBPSMean: uploadSize,
uploadBPSMax: uploadSize,
},
};
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");
const wasTwoSeconds = entry.timings.send >= 2000;
if (actuallyThrottle) {
ok(wasTwoSeconds, "upload should have taken more than 2 seconds");
} else {
ok(!wasTwoSeconds, "upload should not have taken more than 2 seconds");
}
// Clean up
yield teardown(monitor);
}

Просмотреть файл

@ -27,6 +27,12 @@
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>

Просмотреть файл

@ -140,6 +140,7 @@ skip-if = (e10s && debug && os == 'mac') # Bug 1253037
[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]

Просмотреть файл

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Network throttling integration test.
"use strict";
add_task(function* () {
yield throttleTest(true);
yield throttleTest(false);
});
function* throttleTest(actuallyThrottle) {
requestLongerTimeout(2);
let [, , monitor] = yield initNetMonitor(SIMPLE_URL);
const {ACTIVITY_TYPE, NetMonitorController, NetMonitorView} =
monitor.panelWin;
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
// When throttling, must be smaller than the length of the content
// of SIMPLE_URL in bytes.
const size = actuallyThrottle ? 200 : 0;
const request = {
"NetworkMonitor.throttleData": {
roundTripTimeMean: 0,
roundTripTimeMax: 0,
downloadBPSMean: size,
downloadBPSMax: size,
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;
let eventPromise =
monitor.panelWin.once(monitor.panelWin.EVENTS.RECEIVED_EVENT_TIMINGS);
yield NetMonitorController
.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DISABLED);
yield eventPromise;
let requestItem = NetMonitorView.RequestsMenu.getItemAtIndex(0);
const reportedOneSecond = requestItem.attachment.eventTimings.timings.receive > 1000;
if (actuallyThrottle) {
ok(reportedOneSecond, "download reported as taking more than one second");
} else {
ok(!reportedOneSecond, "download reported as taking less than one second");
}
yield teardown(monitor);
}

Просмотреть файл

@ -387,6 +387,7 @@ WebConsoleFrame.prototype = {
_destroyer: null,
_saveRequestAndResponseBodies: true,
_throttleData: null,
// Chevron width at the starting of Web Console's input box.
_chevronWidth: 0,
@ -424,6 +425,36 @@ WebConsoleFrame.prototype = {
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

Просмотреть файл

@ -1055,11 +1055,18 @@ WebConsoleActor.prototype =
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];
}
}
}
}

Просмотреть файл

@ -1454,6 +1454,7 @@ NetworkMonitorChild.prototype = {
owner: null,
_netEvents: null,
_saveRequestAndResponseBodies: true,
_throttleData: null,
get saveRequestAndResponseBodies() {
return this._saveRequestAndResponseBodies;
@ -1470,6 +1471,21 @@ NetworkMonitorChild.prototype = {
});
},
get throttleData() {
return this._throttleData;
},
set throttleData(val) {
this._throttleData = val;
this._messageManager.sendAsyncMessage("debug:netmonitor", {
action: "setPreferences",
preferences: {
throttleData: this._throttleData,
},
});
},
init: function () {
this.conn.setupInParent({
module: "devtools/shared/webconsole/network-monitor",
@ -1676,8 +1692,9 @@ NetworkMonitorParent.prototype = {
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;

Просмотреть файл

@ -360,16 +360,28 @@ NetworkThrottleQueue.prototype = {
* downloadBPSMax {Number} Maximum bytes per second for downloads.
* uploadBPSMean {Number} Mean bytes per second for uploads.
* uploadBPSMax {Number} Maximum bytes per second for uploads.
*
* Download throttling will not be done if downloadBPSMean and
* downloadBPSMax are <= 0. Upload throttling will not be done if
* uploadBPSMean and uploadBPSMax are <= 0.
*/
function NetworkThrottleManager({roundTripTimeMean, roundTripTimeMax,
downloadBPSMean, downloadBPSMax,
uploadBPSMean, uploadBPSMax}) {
this.downloadQueue =
new NetworkThrottleQueue(downloadBPSMean, downloadBPSMax,
roundTripTimeMean, roundTripTimeMax);
this.uploadQueue = Cc["@mozilla.org/network/throttlequeue;1"]
.createInstance(Ci.nsIInputChannelThrottleQueue);
this.uploadQueue.init(uploadBPSMean, uploadBPSMax);
if (downloadBPSMax <= 0 && downloadBPSMean <= 0) {
this.downloadQueue = null;
} else {
this.downloadQueue =
new NetworkThrottleQueue(downloadBPSMean, downloadBPSMax,
roundTripTimeMean, roundTripTimeMax);
}
if (uploadBPSMax <= 0 && uploadBPSMean <= 0) {
this.uploadQueue = null;
} else {
this.uploadQueue = Cc["@mozilla.org/network/throttlequeue;1"]
.createInstance(Ci.nsIInputChannelThrottleQueue);
this.uploadQueue.init(uploadBPSMean, uploadBPSMax);
}
}
exports.NetworkThrottleManager = NetworkThrottleManager;
@ -379,13 +391,17 @@ NetworkThrottleManager.prototype = {
* install it using |setNewListener|.
*
* @param {nsITraceableChannel} channel the channel to manage
* @return {NetworkThrottleListener} the new listener
* @return {NetworkThrottleListener} the new listener, or null if
* download throttling is not being done.
*/
manage: function (channel) {
let listener = new NetworkThrottleListener(this.downloadQueue);
let originalListener = channel.setNewListener(listener);
listener.setOriginalListener(originalListener);
return listener;
if (this.downloadQueue) {
let listener = new NetworkThrottleListener(this.downloadQueue);
let originalListener = channel.setNewListener(listener);
listener.setOriginalListener(originalListener);
return listener;
}
return null;
},
/**
@ -394,7 +410,9 @@ NetworkThrottleManager.prototype = {
* @param {nsITraceableChannel} channel the channel to manage
*/
manageUpload: function (channel) {
channel = channel.QueryInterface(Ci.nsIThrottledInputChannel);
channel.throttleQueue = this.uploadQueue;
if (this.uploadQueue) {
channel = channel.QueryInterface(Ci.nsIThrottledInputChannel);
channel.throttleQueue = this.uploadQueue;
}
},
};