From 8a3e936845859420bf54f81a37f272c6d336755b Mon Sep 17 00:00:00 2001 From: Lin Clark Date: Mon, 11 Jan 2016 19:08:00 +0100 Subject: [PATCH 01/44] Bug 1064458 - Remove 'Log request and response bodies' preference. r=bgrins --- devtools/client/locales/en-US/webConsole.dtd | 5 - .../client/netmonitor/har/har-automation.js | 7 +- .../netmonitor/netmonitor-controller.js | 10 +- devtools/client/webconsole/test/browser.ini | 2 +- .../test/browser_console_netlogging.js | 50 +++++++ .../browser_webconsole_bug_600183_charset.js | 5 - ...le_bug_630733_response_redirect_headers.js | 23 ++-- ...1_toggle_response_logging_with_keyboard.js | 124 ------------------ .../test/browser_webconsole_netlogging.js | 48 +------ devtools/client/webconsole/webconsole.js | 88 +------------ devtools/client/webconsole/webconsole.xul | 5 - devtools/shared/webconsole/network-monitor.js | 7 +- .../webconsole/test/test_network_get.html | 12 +- .../test/test_network_longstring.html | 14 +- .../webconsole/test/test_network_post.html | 14 -- 15 files changed, 83 insertions(+), 331 deletions(-) create mode 100644 devtools/client/webconsole/test/browser_console_netlogging.js delete mode 100644 devtools/client/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js diff --git a/devtools/client/locales/en-US/webConsole.dtd b/devtools/client/locales/en-US/webConsole.dtd index a2f8b41c2317..17ae026992c7 100644 --- a/devtools/client/locales/en-US/webConsole.dtd +++ b/devtools/client/locales/en-US/webConsole.dtd @@ -11,11 +11,6 @@ - - - - diff --git a/devtools/client/netmonitor/har/har-automation.js b/devtools/client/netmonitor/har/har-automation.js index 112810d0229d..665917e17206 100644 --- a/devtools/client/netmonitor/har/har-automation.js +++ b/devtools/client/netmonitor/har/har-automation.js @@ -73,11 +73,8 @@ var HarAutomation = Class({ this.tabClient = this.toolbox.target.activeTab; this.webConsoleClient = this.toolbox.target.activeConsole; - let netPrefs = { "NetworkMonitor.saveRequestAndResponseBodies": true }; - this.webConsoleClient.setPreferences(netPrefs, () => { - this.tabWatcher = new TabWatcher(this.toolbox, this); - this.tabWatcher.connect(); - }); + this.tabWatcher = new TabWatcher(this.toolbox, this); + this.tabWatcher.connect(); }, pageLoadBegin: function(aResponse) { diff --git a/devtools/client/netmonitor/netmonitor-controller.js b/devtools/client/netmonitor/netmonitor-controller.js index f0dfdb03db98..e15ab28063b1 100644 --- a/devtools/client/netmonitor/netmonitor-controller.js +++ b/devtools/client/netmonitor/netmonitor-controller.js @@ -10,7 +10,6 @@ var { classes: Cc, interfaces: Ci, utils: Cu } = Components; const NET_STRINGS_URI = "chrome://devtools/locale/netmonitor.properties"; const PKI_STRINGS_URI = "chrome://pippki/locale/pippki.properties"; const LISTENERS = [ "NetworkActivity" ]; -const NET_PREFS = { "NetworkMonitor.saveRequestAndResponseBodies": true }; // The panel's window global is an EventEmitter firing the following events: const EVENTS = { @@ -223,13 +222,6 @@ var NetMonitorController = { this.tabClient = this._target.activeTab; } - let connectWebConsole = () => { - let deferred = promise.defer(); - this.webConsoleClient = this._target.activeConsole; - this.webConsoleClient.setPreferences(NET_PREFS, deferred.resolve); - return deferred.promise; - }; - let connectTimeline = () => { // Don't start up waiting for timeline markers if the server isn't // recent enough to emit the markers we're interested in. @@ -239,7 +231,7 @@ var NetMonitorController = { } }; - yield connectWebConsole(); + this.webConsoleClient = this._target.activeConsole; yield connectTimeline(); this.TargetEventsHandler.connect(); diff --git a/devtools/client/webconsole/test/browser.ini b/devtools/client/webconsole/test/browser.ini index 88c9125322bf..fb173e5bfbb2 100644 --- a/devtools/client/webconsole/test/browser.ini +++ b/devtools/client/webconsole/test/browser.ini @@ -171,6 +171,7 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests [browser_console_log_inspectable_object.js] [browser_console_native_getters.js] [browser_console_navigation_marker.js] +[browser_console_netlogging.js] [browser_console_nsiconsolemessage.js] skip-if = buildapp == 'mulet' [browser_console_optimized_out_vars.js] @@ -300,7 +301,6 @@ skip-if = os != "mac" [browser_webconsole_bug_817834_add_edited_input_to_history.js] [browser_webconsole_bug_837351_securityerrors.js] skip-if = buildapp == 'mulet' -[browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js] [browser_webconsole_filter_buttons_contextmenu.js] [browser_webconsole_bug_1006027_message_timestamps_incorrect.js] skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug intermittent) diff --git a/devtools/client/webconsole/test/browser_console_netlogging.js b/devtools/client/webconsole/test/browser_console_netlogging.js new file mode 100644 index 000000000000..50e0fd3d8453 --- /dev/null +++ b/devtools/client/webconsole/test/browser_console_netlogging.js @@ -0,0 +1,50 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests that network log messages bring up the network panel. + +"use strict"; + +const TEST_URI = "data:text/html;charset=utf-8,Web Console network " + + "logging tests"; + +const TEST_NETWORK_REQUEST_URI = + "http://example.com/browser/devtools/client/webconsole/test/" + + "test-network-request.html"; + +var hud; + +function test() { + loadTab(TEST_URI).then((tab) => { + HUDService.openBrowserConsoleOrFocus().then(aHud => { + hud = aHud; + HUDService.lastFinishedRequest.callback = testResponse; + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, + TEST_NETWORK_REQUEST_URI); + }); + }); +} + +function testResponse(request) { + hud.ui.webConsoleClient.getResponseContent(request.actor, + function(contentPacket) { + hud.ui.webConsoleClient.getRequestPostData(request.actor, + function(postDataPacket) { + // Check if page load was logged correctly. + ok(request, "Page load was logged"); + + is(request.request.url, TEST_NETWORK_REQUEST_URI, + "Logged network entry is page load"); + is(request.request.method, "GET", "Method is correct"); + ok(!postDataPacket.postData.text, "No request body was stored"); + ok(postDataPacket.postDataDiscarded, "Request body was discarded"); + ok(!contentPacket.content.text, "No response body was stored"); + ok(contentPacket.contentDiscarded || request.fromCache, + "Response body was discarded or response came from the cache"); + + executeSoon(finishTest); + }); + }); +} diff --git a/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js b/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js index 392831d51d45..c0880b122284 100644 --- a/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js +++ b/devtools/client/webconsole/test/browser_webconsole_bug_600183_charset.js @@ -54,11 +54,6 @@ add_task(function* () { let hud = yield openConsole(); - yield hud.ui.setSaveRequestAndResponseBodies(true); - - ok(hud.ui._saveRequestAndResponseBodies, - "The saveRequestAndResponseBodies property was successfully set."); - let gotLastRequest = waitForRequest(); let loaded = loadBrowser(browser); diff --git a/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js b/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js index 4821372b6469..c29be251c3ae 100644 --- a/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js +++ b/devtools/client/webconsole/test/browser_webconsole_bug_630733_response_redirect_headers.js @@ -33,20 +33,15 @@ function consoleOpened(hud) { let deferred = promise.defer(); webConsoleClient = hud.ui.webConsoleClient; - hud.ui.setSaveRequestAndResponseBodies(true).then(() => { - ok(hud.ui._saveRequestAndResponseBodies, - "The saveRequestAndResponseBodies property was successfully set."); - - HUDService.lastFinishedRequest.callback = (aHttpRequest) => { - let status = aHttpRequest.response.status; - lastFinishedRequests[status] = aHttpRequest; - if ("301" in lastFinishedRequests && - "404" in lastFinishedRequests) { - deferred.resolve(); - } - }; - content.location = TEST_URI2; - }); + HUDService.lastFinishedRequest.callback = (aHttpRequest) => { + let status = aHttpRequest.response.status; + lastFinishedRequests[status] = aHttpRequest; + if ("301" in lastFinishedRequests && + "404" in lastFinishedRequests) { + deferred.resolve(); + } + }; + content.location = TEST_URI2; return deferred.promise; } diff --git a/devtools/client/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js b/devtools/client/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js deleted file mode 100644 index dfb2aff53b4a..000000000000 --- a/devtools/client/webconsole/test/browser_webconsole_bug_915141_toggle_response_logging_with_keyboard.js +++ /dev/null @@ -1,124 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -// Tests that the 'Log Request and Response Bodies' buttons can be toggled -// with keyboard. - -"use strict"; - -const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " + - "bug 915141: Toggle log response bodies with keyboard"; -var hud; - -function test() { - let saveBodiesMenuItem; - let saveBodiesContextMenuItem; - - loadTab(TEST_URI).then(({tab: tab}) => { - return openConsole(tab); - }) - .then((aHud) => { - hud = aHud; - saveBodiesMenuItem = hud.ui.rootElement.querySelector("#saveBodies"); - saveBodiesContextMenuItem = hud.ui.rootElement.querySelector("#saveBodiesContextMenu"); - - // Test the context menu action. - info("Testing 'Log Request and Response Bodies' menuitem of right click " + - "context menu."); - - return openPopup(saveBodiesContextMenuItem); - }) - .then(() => { - is(saveBodiesContextMenuItem.getAttribute("checked"), "false", - "Context menu: 'log responses' is not checked before action."); - is(hud.ui._saveRequestAndResponseBodies, false, - "Context menu: Responses are not logged before action."); - - EventUtils.synthesizeKey("VK_DOWN", {}); - EventUtils.synthesizeKey("VK_RETURN", {}); - - return waitForUpdate(saveBodiesContextMenuItem); - }) - .then(() => { - is(saveBodiesContextMenuItem.getAttribute("checked"), "true", - "Context menu: 'log responses' is checked after menuitem was selected " + - "with keyboard."); - is(hud.ui._saveRequestAndResponseBodies, true, - "Context menu: Responses are saved after menuitem was selected with " + - "keyboard."); - - return openPopup(saveBodiesMenuItem); - }) - .then(() => { - // Test the 'Net' menu item. - info("Testing 'Log Request and Response Bodies' menuitem of 'Net' menu " + - "in the console."); - // 'Log Request and Response Bodies' should be selected due to previous - // test. - - is(saveBodiesMenuItem.getAttribute("checked"), "true", - "Console net menu: 'log responses' is checked before action."); - is(hud.ui._saveRequestAndResponseBodies, true, - "Console net menu: Responses are logged before action."); - - // The correct item is the last one in the menu. - EventUtils.synthesizeKey("VK_UP", {}); - EventUtils.synthesizeKey("VK_RETURN", {}); - - return waitForUpdate(saveBodiesMenuItem); - }) - .then(() => { - is(saveBodiesMenuItem.getAttribute("checked"), "false", - "Console net menu: 'log responses' is NOT checked after menuitem was " + - "selected with keyboard."); - is(hud.ui._saveRequestAndResponseBodies, false, - "Responses are NOT saved after menuitem was selected with keyboard."); - hud = null; - }) - .then(finishTest); -} - -/** - * Opens and waits for the menu containing menuItem to open. - * @param menuItem MenuItem - * A MenuItem in a menu that should be opened. - * @return A promise that's resolved once menu is open. - */ -function openPopup(menuItem) { - let menu = menuItem.parentNode; - - let menuOpened = promise.defer(); - let uiUpdated = promise.defer(); - // The checkbox menuitem is updated asynchronously on 'popupshowing' event so - // it's better to wait for both the update to happen and the menu to open - // before continuing or the test might fail due to a race between menu being - // shown and the item updated to have the correct state. - hud.ui.once("save-bodies-ui-toggled", uiUpdated.resolve); - menu.addEventListener("popupshown", function onPopup() { - menu.removeEventListener("popupshown", onPopup); - menuOpened.resolve(); - }); - - menu.openPopup(); - return Promise.all([menuOpened.promise, uiUpdated.promise]); -} - -/** - * Waits for the settings and menu containing menuItem to update. - * @param menuItem MenuItem - * The menuitem that should be updated. - * @return A promise that's resolved once the settings and menus are updated. - */ -function waitForUpdate(menuItem) { - info("Waiting for settings update to complete."); - let deferred = promise.defer(); - hud.ui.once("save-bodies-pref-reversed", function() { - hud.ui.once("save-bodies-ui-toggled", deferred.resolve); - // The checked state is only updated once the popup is shown. - menuItem.parentNode.openPopup(); - }); - return deferred.promise; -} diff --git a/devtools/client/webconsole/test/browser_webconsole_netlogging.js b/devtools/client/webconsole/test/browser_webconsole_netlogging.js index 42feaf3adcda..f304f44931bb 100644 --- a/devtools/client/webconsole/test/browser_webconsole_netlogging.js +++ b/devtools/client/webconsole/test/browser_webconsole_netlogging.js @@ -74,58 +74,16 @@ function testPageLoad() { "Logged network entry is page load"); is(lastRequest.request.method, "GET", "Method is correct"); ok(!lastRequest.request.postData.text, "No request body was stored"); - ok(lastRequest.discardRequestBody, "Request body was discarded"); - ok(!lastRequest.response.content.text, "No response body was stored"); - ok(lastRequest.discardResponseBody || lastRequest.fromCache, - "Response body was discarded or response came from the cache"); - - lastRequest = null; - requestCallback = null; - executeSoon(testPageLoadBody); - }; - - content.location = TEST_NETWORK_REQUEST_URI; -} - -function testPageLoadBody() { - // Turn on logging of request bodies and check again. - hud.ui.setSaveRequestAndResponseBodies(true).then(() => { - ok(hud.ui._saveRequestAndResponseBodies, - "The saveRequestAndResponseBodies property was successfully set."); - - testPageLoadBodyAfterSettingUpdate(); - }); -} - -function testPageLoadBodyAfterSettingUpdate() { - let loaded = false; - let requestCallbackInvoked = false; - - requestCallback = function() { - ok(lastRequest, "Page load was logged again"); - ok(!lastRequest.discardResponseBody, "Response body was not discarded"); + ok(!lastRequest.discardRequestBody, "Request body was not discarded"); is(lastRequest.response.content.text.indexOf(""), 0, "Response body's beginning is okay"); lastRequest = null; requestCallback = null; - requestCallbackInvoked = true; - - if (loaded) { - executeSoon(testXhrGet); - } + executeSoon(testXhrGet); }; - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - loaded = true; - - if (requestCallbackInvoked) { - executeSoon(testXhrGet); - } - }, true); - - content.location.reload(); + content.location = TEST_NETWORK_REQUEST_URI; } function testXhrGet() { diff --git a/devtools/client/webconsole/webconsole.js b/devtools/client/webconsole/webconsole.js index a3ee06710acf..b3ddc3094add 100644 --- a/devtools/client/webconsole/webconsole.js +++ b/devtools/client/webconsole/webconsole.js @@ -367,42 +367,13 @@ WebConsoleFrame.prototype = { _destroyer: null, - // Used in tests. - _saveRequestAndResponseBodies: false, + _saveRequestAndResponseBodies: true, // 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, - /** - * Tells whether to save the bodies of network requests and responses. - * Disabled by default to save memory. - * - * @return boolean - * The saveRequestAndResponseBodies pref value. - */ - getSaveRequestAndResponseBodies: - function WCF_getSaveRequestAndResponseBodies() { - let deferred = promise.defer(); - let toGet = [ - "NetworkMonitor.saveRequestAndResponseBodies" - ]; - - // Make sure the web console client connection is established first. - this.webConsoleClient.getPreferences(toGet, response => { - if (!response.error) { - this._saveRequestAndResponseBodies = response.preferences[toGet[0]]; - deferred.resolve(this._saveRequestAndResponseBodies); - } - else { - deferred.reject(response.error); - } - }); - - return deferred.promise; - }, - /** * Setter for saving of network request and response bodies. * @@ -560,47 +531,6 @@ WebConsoleFrame.prototype = { // calculations. this._updateCharSize(); - let updateSaveBodiesPrefUI = (element) => { - this.getSaveRequestAndResponseBodies().then(value => { - element.setAttribute("checked", value); - this.emit("save-bodies-ui-toggled"); - }); - } - - let reverseSaveBodiesPref = ({ target: element }) => { - this.getSaveRequestAndResponseBodies().then(value => { - this.setSaveRequestAndResponseBodies(!value); - element.setAttribute("checked", value); - this.emit("save-bodies-pref-reversed"); - }); - } - - let saveBodiesDisabled = !this.getFilterState("networkinfo") && - !this.getFilterState("netxhr") && - !this.getFilterState("network"); - - let saveBodies = doc.getElementById("saveBodies"); - saveBodies.addEventListener("command", reverseSaveBodiesPref); - saveBodies.disabled = saveBodiesDisabled; - - let saveBodiesContextMenu = doc.getElementById("saveBodiesContextMenu"); - saveBodiesContextMenu.addEventListener("command", reverseSaveBodiesPref); - saveBodiesContextMenu.disabled = saveBodiesDisabled; - - saveBodies.parentNode.addEventListener("popupshowing", () => { - updateSaveBodiesPrefUI(saveBodies); - saveBodies.disabled = !this.getFilterState("networkinfo") && - !this.getFilterState("netxhr") && - !this.getFilterState("network"); - }); - - saveBodiesContextMenu.parentNode.addEventListener("popupshowing", () => { - updateSaveBodiesPrefUI(saveBodiesContextMenu); - saveBodiesContextMenu.disabled = !this.getFilterState("networkinfo") && - !this.getFilterState("netxhr") && - !this.getFilterState("network"); - }); - let clearButton = doc.getElementsByClassName("webconsole-clear-console-button")[0]; clearButton.addEventListener("command", () => { this.owner._onClearButton(); @@ -951,15 +881,6 @@ WebConsoleFrame.prototype = { let prefKey = target.getAttribute("prefKey"); this.setFilterState(prefKey, state); - // Disable the log response and request body if network logging is off. - if (prefKey == "networkinfo" || prefKey == "netxhr" || prefKey == "network") { - let checkState = !this.getFilterState("networkinfo") && - !this.getFilterState("netxhr") && - !this.getFilterState("network"); - this.document.getElementById("saveBodies").disabled = checkState; - this.document.getElementById("saveBodiesContextMenu").disabled = checkState; - } - // Adjust the state of the button appropriately. let menuPopup = target.parentNode; @@ -5089,8 +5010,13 @@ WebConsoleConnectionProxy.prototype = { } this.webConsoleClient = webConsoleClient; - this._hasNativeConsoleAPI = response.nativeConsoleAPI; + + // There is no way to view response bodies from the Browser Console, so do + // not waste the memory. + let saveBodies = !this.webConsoleFrame.owner._browserConsole; + this.webConsoleFrame.setSaveRequestAndResponseBodies(saveBodies); + this.webConsoleClient.on("networkEvent", this._onNetworkEvent); this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate); diff --git a/devtools/client/webconsole/webconsole.xul b/devtools/client/webconsole/webconsole.xul index e7052f5b98b6..b7d96516d14b 100644 --- a/devtools/client/webconsole/webconsole.xul +++ b/devtools/client/webconsole/webconsole.xul @@ -72,8 +72,6 @@ function goUpdateConsoleCommands() { - @@ -110,9 +108,6 @@ function goUpdateConsoleCommands() { prefKey="netxhr"/> - - Date: Fri, 8 Jan 2016 15:09:57 +0100 Subject: [PATCH 02/44] Bug 1223385 - refactor mach helper into LocalesMixin, r=rail --HG-- extra : transplant_source : %99%B3%B1%82%81%16%92tb%8C%FF%B0%18F%81%7F%BE%5B%84%E9 --- .../mozharness/mozharness/mozilla/l10n/locales.py | 13 +++++++++++++ testing/mozharness/scripts/desktop_l10n.py | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/l10n/locales.py b/testing/mozharness/mozharness/mozilla/l10n/locales.py index 395f78243ae7..1d6ee5b0a6d8 100755 --- a/testing/mozharness/mozharness/mozilla/l10n/locales.py +++ b/testing/mozharness/mozharness/mozilla/l10n/locales.py @@ -31,6 +31,19 @@ class LocalesMixin(ChunkingMixin): self.gecko_locale_revisions = None self.l10n_revisions = {} + def _get_mach_executable(self): + python = self.query_exe('python2.7') + return [python, 'mach'] + + def _mach(self, target, env, halt_on_failure=True, output_parser=None): + dirs = self.query_abs_dirs() + mach = self._get_mach_executable() + return self.run_command(mach + target, + halt_on_failure=True, + env=env, + cwd=dirs['abs_mozilla_dir'], + output_parser=None) + def query_locales(self): if self.locales is not None: return self.locales diff --git a/testing/mozharness/scripts/desktop_l10n.py b/testing/mozharness/scripts/desktop_l10n.py index f0a571deb18f..0abf78f218a1 100755 --- a/testing/mozharness/scripts/desktop_l10n.py +++ b/testing/mozharness/scripts/desktop_l10n.py @@ -606,25 +606,12 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin, self.copyfile(src, dst) self.read_from_file(dst, verbose=True) - def _mach(self, target, env, halt_on_failure=True, output_parser=None): - dirs = self.query_abs_dirs() - mach = self._get_mach_executable() - return self.run_command(mach + target, - halt_on_failure=True, - env=env, - cwd=dirs['abs_mozilla_dir'], - output_parser=None) - def _mach_configure(self): """calls mach configure""" env = self.query_bootstrap_env() target = ["configure"] return self._mach(target=target, env=env) - def _get_mach_executable(self): - python = self.query_exe('python2.7') - return [python, 'mach'] - def _get_make_executable(self): config = self.config dirs = self.query_abs_dirs() From 1b12f9ca0724acedda4f30d5eafb06372a26922b Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Fri, 8 Jan 2016 16:21:24 +0100 Subject: [PATCH 03/44] Bug 1223385 - use in-tree compare-locales in mozharness, r=rail --HG-- extra : transplant_source : %9C%3B%3DK%06%2C%7C%8F%A5j%93%809%8El%60%3A7%29%23 --- .../mozharness/mozilla/l10n/locales.py | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/l10n/locales.py b/testing/mozharness/mozharness/mozilla/l10n/locales.py index 1d6ee5b0a6d8..1389092258b3 100755 --- a/testing/mozharness/mozharness/mozilla/l10n/locales.py +++ b/testing/mozharness/mozharness/mozilla/l10n/locales.py @@ -35,10 +35,12 @@ class LocalesMixin(ChunkingMixin): python = self.query_exe('python2.7') return [python, 'mach'] - def _mach(self, target, env, halt_on_failure=True, output_parser=None): + def _mach(self, target, env, error_list=None, halt_on_failure=True, + output_parser=None): dirs = self.query_abs_dirs() mach = self._get_mach_executable() return self.run_command(mach + target, + error_list=error_list, halt_on_failure=True, env=env, cwd=dirs['abs_mozilla_dir'], @@ -154,20 +156,13 @@ class LocalesMixin(ChunkingMixin): def run_compare_locales(self, locale, halt_on_failure=False): dirs = self.query_abs_dirs() - compare_locales_script = os.path.join(dirs['abs_compare_locales_dir'], - 'scripts', 'compare-locales') - env = self.query_env(partial_env={'PYTHONPATH': - os.path.join(dirs['abs_compare_locales_dir'], - 'lib')}) + env = self.query_bootstrap_env() compare_locales_error_list = list(PythonErrorList) - self.rmtree(dirs['abs_merge_dir']) - self.mkdir_p(dirs['abs_merge_dir']) - command = "python %s -m %s l10n.ini %s %s" % (compare_locales_script, - dirs['abs_merge_dir'], dirs['abs_l10n_dir'], locale) + command = ['compare-locales', + '--merge-dir', dirs['abs_merge_dir'], locale] self.info("*** BEGIN compare-locales %s" % locale) - status = self.run_command(command, error_list=compare_locales_error_list, - cwd=dirs['abs_locales_src_dir'], env=env, - halt_on_failure=halt_on_failure) + status = self._mach(command, env, error_list=compare_locales_error_list, + halt_on_failure=halt_on_failure) self.info("*** END compare-locales %s" % locale) return status @@ -200,8 +195,6 @@ class LocalesMixin(ChunkingMixin): 'merged') dirs['abs_locales_dir'] = os.path.join(dirs['abs_objdir'], c['locales_dir']) - dirs['abs_compare_locales_dir'] = os.path.join(dirs['abs_work_dir'], - 'compare-locales') for key in dirs.keys(): if key not in abs_dirs: abs_dirs[key] = dirs[key] From a942827a5bbc75ffe85e15747cc2b8dafe5fb4cf Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Fri, 8 Jan 2016 16:37:52 +0100 Subject: [PATCH 04/44] Bug 1223385 - use in-tree compare-locales in Makefiles, r=gps Also fix that the default merge dir in the mach command creates a directory that's the merge make target, and thus keeps that make target from actually running. --HG-- extra : transplant_source : R%FE%7Eo%CDS%D1%B4%EA%DB%D0%19q%F92%A1V%91%10%5C --- browser/locales/Makefile.in | 2 +- mobile/android/locales/Makefile.in | 2 +- python/compare-locales/mach_commands.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/locales/Makefile.in b/browser/locales/Makefile.in index 6f75776caf60..f7e680767a87 100644 --- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -189,7 +189,7 @@ ident: merge-%: ifdef LOCALE_MERGEDIR $(RM) -rf $(LOCALE_MERGEDIR) - MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $* + $(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $* endif @echo diff --git a/mobile/android/locales/Makefile.in b/mobile/android/locales/Makefile.in index ebd054dbdd51..b8e541ba8d95 100644 --- a/mobile/android/locales/Makefile.in +++ b/mobile/android/locales/Makefile.in @@ -82,6 +82,6 @@ ident: merge-%: ifdef LOCALE_MERGEDIR $(RM) -rf $(LOCALE_MERGEDIR) - MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $* + $(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $* endif @echo diff --git a/python/compare-locales/mach_commands.py b/python/compare-locales/mach_commands.py index d0dc22e4f751..a42c6e7311a4 100644 --- a/python/compare-locales/mach_commands.py +++ b/python/compare-locales/mach_commands.py @@ -70,7 +70,7 @@ class CompareLocales(MachCommandBase): merge_dir = mozpath.join( self.topobjdir, self.substs['MOZ_BUILD_APP'], - 'locales', 'merge-{ab_CD}' + 'locales', 'merge-dir-{ab_CD}' ) except Exception: pass From c3ccb51bd4a6a34e95d5e6f353d90908b3b2727f Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 12 Jan 2016 11:29:00 +0100 Subject: [PATCH 05/44] Bug 1238048 - Add an architectural overview of the memory tool DONTBUILD; r=tromey,vporof,jsantell,jimb --- devtools/docs/memory-panel.md | 201 ++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 devtools/docs/memory-panel.md diff --git a/devtools/docs/memory-panel.md b/devtools/docs/memory-panel.md new file mode 100644 index 000000000000..5980691aadc8 --- /dev/null +++ b/devtools/docs/memory-panel.md @@ -0,0 +1,201 @@ +# Memory Tool Architecture + +The memory tool is built of three main elements: + +1. `JS::ubi::Node` provides an interface to either the live heap graph, or a + serialized, offline snapshot of some heap graph from a previous moment in + time. Our various heap analyses (census, dominator trees, shortest paths, + etc) run on top of `JS::ubi::Node` graphs. + +2. The `HeapAnalysesWorker` runs in a worker thread, performing analyses on + snapshots and translating the results into something the frontend can render + simply and quickly. + +3. Finally, the last element is the frontend that renders data received from the + `HeapAnalysesClient` to the DOM and translates user input into requests for + new data with the `HeapAnalysesClient`. + +Unlike other tools (such as the JavaScript debugger), the memory tool makes very +little use of the Remote Debugger Server and the actors that reside in it. Use +of the [`MemoryActor`](devtools/server/actors/memory.js) is limited to toggling +allocation stack recording on and off, and transferring heap snapshots from the +debuggee (which is on the server) to the `HeapAnalysesWorker` (which is on the +client). A nice benefit that naturally emerges, is that supporting "legacy" +servers (eg, using Firefox Developer Edition as a client to remote debug a +release Firefox for Android server) is a no-op. As we add new analyses, we can +run them on snapshots taken on old servers no problem. The only requirement is +that changes to the snapshot format itself remain backwards compatible. + +## `JS::ubi::Node` + +`JS::ubi::Node` itself is very well documented in the `js/public/UbiNode.h` +header. I suggest you at least skim that documentation before continuing. + +A "heap snapshot" is a representation of the heap graph at some particular past +instance in time. + +A "heap analysis" is an algorithm that runs on a `JS::ubi::Node` heap +graph. That's it. Generally, analyses can run on either the live heap graph or a +deserialized snapshot. Example analyses include "census", which aggregates and +counts nodes into various user-specified buckets; "dominator trees", which +compute the "dominates" relation and retained size for all nodes in the heap +graph; and "shortest paths" which finds the shortest paths from the GC roots to +some subset of nodes. + +### Saving Heap Snapshots + +Saving a heap snapshot has a few requirements: + +1. The binary format must remain backwards compatible and future extensible. + +2. The live heap graph must not mutate while we are in the process of + serializing it. + +3. The act of saving a heap snapshot should impose as little memory overhead as + possible. If we are taking a snapshot to debug frequent out-of-memory errors, + we don't want to trigger an OOM ourselves! + +To solve (1), we use the protobuf message format. The message definitions +themselves are in `devtools/shared/heapsnapshot/CoreDump.proto`. We always use +`optional` fields so we can change our mind about what fields are required +sometime in the future. Deserialization checks the semantic integrity of +deserialized protobuf messages. + +For (2), we rely on SpiderMonkey's GC rooting hazard static analysis and the +`AutoCheckCannotGC` dynamic analysis to ensure that neither JS nor GC runs and +modifies objects or moves them from one address in memory to another. There is +no equivalent suppression and static analysis technique for the +[cycle collector](https://developer.mozilla.org/en/docs/Interfacing_with_the_XPCOM_cycle_collector), +so care must be taken not to invoke methods that could start cycle collection or +mutate the heap graph from the cycle collector's perspective. At the time of +writing, we don't yet support saving the cycle collector's portion of the heap +graph in snapshots, but that work is deemed Very Important and Very High +Priority. + +Finally, (3) imposes upon us that we do not build the serialized heap snapshot +binary blob in memory, but instead stream it out to disk while generating it. + +Once all of that is accounted for, saving snapshots becomes pretty straight +forward. We traverse the live heap graph with `JS::ubi::Node` and +`JS::ubi::BreadthFirst`, create a protobuf message for each node and each node's +edges, and write these messages to disk before continuing the traversal to the +next node. + +This functionality is exposed to chrome JavaScript as the +`[ThreadSafe]ChromeUtils.saveHeapSnapshot` function. See +`dom/webidl/ThreadSafeChromeUtils.webidl` for API documentation. + +### Reading Heap Snapshots + +Reading heap snapshots has less restrictions than saving heap snapshots. The +protobuf messages that make up the core dump are deserialized one by one, stored +as a set of `DeserializedNode`s and a set of `DeserializedEdge`s, and the result +is a `HeapSnapshot` instance. + +The `DeserializedNode` and `DeserializedEdge` classes implement the +`JS::ubi::Node` interface. Analyses running on offline heap snapshots rather +than the live heap graph operate on these classes (unknowingly, of course). + +For more details, see the +[`mozilla::devtools::HeapSnapshot`](devtools/shared/heapsnapshot/HeapSnapshot.cpp) +and +[`mozilla::devtools::Deserialized{Node,Edge}`](devtools/shared/heapsnapshot/DeserializedNode.h) +classes. + +### Heap Analyses + +Heap analyses operate on `JS::ubi::Node` graphs without knowledge of whether +that graph is backed by the live heap graph or an offline heap snapshot. They +must make sure never to allocate GC things or modify the live heap graph. + +In general, analyses are implemented in their own `js/public/UbiFooBar.h` header +(eg `js/public/UbiCensus.h`), and are exposed to chrome JavaScript code via a +method on the [`HeapSnapshot`](dom/webidl/HeapSnapshot.webidl) webidl +interface. + +For each analysis we expose to chrome JavaScript on the `HeapSnapshot` webidl +interface, there is a small amount of glue code in Gecko. The +[`mozilla::devtools::HeapSnapshot`](devtools/shared/heapsnapshot/HeapSnapshot.h) +C++ class implements the webidl interface. The analyses methods (eg +`ComputeDominatorTree`) take the deserialized nodes and edges from the heap +snapshot, create `JS::ubi::Node`s from them, call the analyses from +`js/public/Ubi*.h`, and wrap the results in something that can be represented in +JavaScript. + +For API documentation on running specific analyses, see the +[`HeapSnapshot`](dom/webidl/HeapSnapshot.webidl) webidl interface. + +### Testing `JS::ubi::Node`, Snapshots, and Analyses + +The majority of the tests reside within `devtools/shared/heapsnapshot/tests/**`. +For reading and saving heap snapshots, most tests are gtests. The gtests can be +run with the `mach gtest DevTools.*` command. The rest are integration sanity +tests to make sure we can read and save snapshots in various environments, such +as xpcshell or workers. These can be run with the usual `mach test $PATH` +commands. + +There are also `JS::ubi::Node` related unit tests in +`js/src/jit-test/tests/heap-analysis/*`, `js/src/jit-test/tests/debug/Memory-*`, +and `js/src/jsapi-tests/testUbiNode.cpp`. See +https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Running_Automated_JavaScript_Tests#Running_jit-tests +for running the JIT tests. + +## `HeapAnalysesWorker` + +The `HeapAnalysesWorker` orchestrates running specific analyses on snapshots and +transforming the results into something that can simply and quickly be rendered +by the frontend. The analyses can take some time to run (sometimes on the order +of seconds), so doing them in a worker thread allows the interface to stay +responsive. The `HeapAnalysisClient` provides the main thread's interface to the +worker. + +The `HeapAnalysesWorker` doesn't actually do much itself; mostly just shuffling +data and transforming it from one representation to another or calling utility +functions that do those things. Most of these are implemented as traversals of +the resulting census or dominator trees. + +See the +`devtools/shared/heapsnapshot/{CensusUtils,CensusTreeNode,DominatorTreeNode}.js` +files for details on the various data transformations and shuffling that the +`HeapAnalysesWorker` delegates to. + +### Testing the `HeapAnalysesWorker` and `HeapAnalysesClient` + +Tests for the `HeapAnalysesWorker` and `HeapAnalysesClient` reside in +`devtools/shared/heapsnapshot/tests/**` and can be run with the usual `mach test +$PATH` command. + +## Frontend + +The frontend of the memory tool is built with React and Redux. + +[React has thorough documentation.](https://facebook.github.io/react/) + +[Redux has thorough documentation.](http://rackt.org/redux/index.html) + +We have React components in `devtools/client/memory/components/*`. + +We have Redux reducers in `devtools/client/memory/reducers/*`. + +We have Redux actions and action-creating tasks in +`devtools/client/memory/actions/*`. + +React components should be pure functions from their props to the rendered +(virtual) DOM. Redux reducers should also be observably pure. + +Impurity within the frontend is confined to the tasks that are creating and +dispatching actions. All communication with the outside world (such as the +`HeapAnalysesWorker`, the Remote Debugger Server, or the file system) is +restricted to within these tasks. + +### Testing the Frontend + +Unit tests for React components are in `devtools/client/memory/test/chrome/*`. + +Unit tests for actions, reducers, and state changes are in +`devtools/client/memory/test/unit/*`. + +Holistic integration tests for the frontend and the whole memory tool are in +`devtools/client/memory/test/browser/*`. + +All tests can be run with the usual `mach test $PATH` command. From ee09fb2a0b652be3c3989aacedb4fa8e21378f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Tue, 12 Jan 2016 02:53:00 +0100 Subject: [PATCH 06/44] Bug 1238901 - ""Start a conversation..." menu item should use title capitalization". r=gijskruitbosch --- browser/locales/en-US/chrome/browser/loop/loop.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/locales/en-US/chrome/browser/loop/loop.properties b/browser/locales/en-US/chrome/browser/loop/loop.properties index 34906a9e8308..ba9bbe2e0887 100644 --- a/browser/locales/en-US/chrome/browser/loop/loop.properties +++ b/browser/locales/en-US/chrome/browser/loop/loop.properties @@ -12,7 +12,7 @@ clientSuperShortname=Hello ## LOCALIZATION_NOTE(loopMenuItem_label): Label of the menu item that is placed ## inside the browser 'Tools' menu. Use the unicode ellipsis char, \u2026, or ## use "..." if \u2026 doesn't suit traditions in your locale. -loopMenuItem_label=Start a conversation… +loopMenuItem_label=Start a Conversation… loopMenuItem_accesskey=t ## LOCALIZATION_NOTE(sign_in_again_title_line_one, sign_in_again_title_line_two2): From 3288f619f94672f85d36392d15a4a17092b1f02e Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Wed, 13 Jan 2016 00:37:32 -0800 Subject: [PATCH 07/44] Bug 1238133 - Part 1: Make only one instance of fonts.css and rules.css r=bgrins --- devtools/client/inspector/fonts/fonts.css | 51 --------- devtools/client/inspector/fonts/fonts.xhtml | 1 - devtools/client/inspector/rules/rules.css | 118 -------------------- devtools/client/inspector/rules/rules.xhtml | 3 +- devtools/client/jar.mn | 2 - devtools/client/themes/fonts.css | 52 +++++++++ devtools/client/themes/rules.css | 103 ++++++++++++++++- 7 files changed, 155 insertions(+), 175 deletions(-) delete mode 100644 devtools/client/inspector/fonts/fonts.css delete mode 100644 devtools/client/inspector/rules/rules.css diff --git a/devtools/client/inspector/fonts/fonts.css b/devtools/client/inspector/fonts/fonts.css deleted file mode 100644 index 87d6926169b2..000000000000 --- a/devtools/client/inspector/fonts/fonts.css +++ /dev/null @@ -1,51 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -.dim > #root, -.font:not(.has-code) .font-css-code, -.font-is-local, -.font-is-remote, -.font.is-local .font-format-url, -#template { - display: none; -} - -.font.is-remote .font-is-remote, -.font.is-local .font-is-local { - display: inline; -} - -.font-format::before { - content: "("; -} - -.font-format::after { - content: ")"; -} - -.preview-input-toolbar { - display: flex; - width: 100%; -} - -.font-preview-container { - overflow-x: auto; -} - -#preview-text-input { - font: inherit; - margin-top: 1px; - margin-bottom: 1px; - padding-top: 0; - padding-bottom: 0; - flex: 1; -} - -:root { - height: 100%; -} - -#root { - overflow: auto; -} diff --git a/devtools/client/inspector/fonts/fonts.xhtml b/devtools/client/inspector/fonts/fonts.xhtml index 1aad0ccbb999..373c01a9072a 100644 --- a/devtools/client/inspector/fonts/fonts.xhtml +++ b/devtools/client/inspector/fonts/fonts.xhtml @@ -11,7 +11,6 @@ &title; - ', + ].join("\n"); + let parser = new Parser(); + let parsed = parser.get(source); + + is(parser.errors.length, 0, + "There should be no errors logged when parsing."); + is(parsed.scriptCount, 5, + "There should be 5 scripts parsed in the parent HTML source."); + + is(parsed.getScriptInfo(source.indexOf("foo.js\"/>") + 1).toSource(), "({start:-1, length:-1, index:-1})", + "the first script is empty"); + is(parsed.getScriptInfo(source.indexOf("baz.js\"/>") + 1).toSource(), "({start:-1, length:-1, index:-1})", + "the second script is empty"); + is(parsed.getScriptInfo(source.indexOf("foobar.js\"/>") + 1).toSource(), "({start:-1, length:-1, index:-1})", + "the third script is empty"); + + is(parsed.getScriptInfo(source.indexOf("hello third!")).toSource(), "({start:-1, length:-1, index:-1})", + "Inline script on self-closing tag not considered a script"); + is(parsed.getScriptInfo(source.indexOf("hello fourth")).toSource(), "({start:267, length:14, index:4})", + "The fourth script was located correctly."); + + finish(); +} diff --git a/devtools/shared/Parser.jsm b/devtools/shared/Parser.jsm index bd3d17360570..b4131f110c18 100644 --- a/devtools/shared/Parser.jsm +++ b/devtools/shared/Parser.jsm @@ -46,7 +46,7 @@ Parser.prototype = { // all the scripts. Fastest/easiest way is with a regular expression. // Don't worry, the rules of using a