summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/browser_about_logging.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser/browser_about_logging.js')
-rw-r--r--toolkit/content/tests/browser/browser_about_logging.js464
1 files changed, 464 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/browser_about_logging.js b/toolkit/content/tests/browser/browser_about_logging.js
new file mode 100644
index 0000000000..f458b36e0d
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_about_logging.js
@@ -0,0 +1,464 @@
+const PAGE = "about:logging";
+
+function clearLoggingPrefs() {
+ for (let pref of Services.prefs.getBranch("logging.").getChildList("")) {
+ info(`Clearing: ${pref}`);
+ Services.prefs.clearUserPref("logging." + pref);
+ }
+}
+
+// Before running, save any MOZ_LOG environment variable that might be preset,
+// and restore them at the end of this test.
+add_setup(async function saveRestoreLogModules() {
+ let savedLogModules = Services.env.get("MOZ_LOG");
+ Services.env.set("MOZ_LOG", "");
+ registerCleanupFunction(() => {
+ clearLoggingPrefs();
+ info(" -- Restoring log modules: " + savedLogModules);
+ for (let pref of savedLogModules.split(",")) {
+ let [logModule, level] = pref.split(":");
+ Services.prefs.setIntPref("logging." + logModule, parseInt(level));
+ }
+ // Removing this line causes a sandboxxing error in nsTraceRefCnt.cpp (!).
+ Services.env.set("MOZ_LOG", savedLogModules);
+ });
+});
+
+// Test that some UI elements are disabled in some cirumstances.
+add_task(async function testElementsDisabled() {
+ // This test needs a MOZ_LOG env var set.
+ Services.env.set("MOZ_LOG", "example:4");
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ $("#set-log-modules-button").disabled,
+ "Because a MOZ_LOG env var is set by the harness, it should be impossible to set new log modules."
+ );
+ });
+ });
+ Services.env.set("MOZ_LOG", "");
+
+ await BrowserTestUtils.withNewTab(
+ PAGE + "?modules=example:5&output=profiler",
+ async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#some-elements-unavailable").hidden,
+ "If a log modules are configured via URL params, a warning should be visible."
+ );
+ Assert.ok(
+ $("#set-log-modules-button").disabled,
+ "If a log modules are configured via URL params, some in-page elements should be disabled (button)."
+ );
+ Assert.ok(
+ $("#log-modules").disabled,
+ "If a log modules are configured via URL params, some in-page elements should be disabled (input)."
+ );
+ Assert.ok(
+ $("#logging-preset-dropdown").disabled,
+ "If a log modules are configured via URL params, some in-page elements should be disabled (dropdown)."
+ );
+ Assert.ok(
+ $("#radio-logging-profiler").disabled &&
+ $("#radio-logging-file").disabled,
+ "If the ouptut type is configured via URL param, the radio buttons should be disabled."
+ );
+ });
+ }
+ );
+ await BrowserTestUtils.withNewTab(
+ PAGE + "?preset=media-playback",
+ async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#some-elements-unavailable").hidden,
+ "If a preset is selected via URL, a warning should be displayed."
+ );
+ Assert.ok(
+ $("#set-log-modules-button").disabled,
+ "If a preset is selected via URL, some in-page elements should be disabled (button)."
+ );
+ Assert.ok(
+ $("#log-modules").disabled,
+ "If a preset is selected via URL, some in-page elements should be disabled (input)."
+ );
+ Assert.ok(
+ $("#logging-preset-dropdown").disabled,
+ "If a preset is selected via URL, some in-page elements should be disabled (dropdown)."
+ );
+ });
+ }
+ );
+ clearLoggingPrefs();
+});
+
+// Test URL parameters
+const modulesInURL = "example:4,otherexample:5";
+const presetInURL = "media-playback";
+const threadsInURL = "example,otherexample";
+const profilerPresetInURL = "media";
+add_task(async function testURLParameters() {
+ await BrowserTestUtils.withNewTab(
+ PAGE + "?modules=" + modulesInURL,
+ async browser => {
+ await SpecialPowers.spawn(browser, [modulesInURL], async modulesInURL => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#some-elements-unavailable").hidden,
+ "If modules are selected via URL, a warning should be displayed."
+ );
+ var inPageSorted = $("#current-log-modules")
+ .innerText.split(",")
+ .sort()
+ .join(",");
+ var inURLSorted = modulesInURL.split(",").sort().join(",");
+ Assert.equal(
+ inPageSorted,
+ inURLSorted,
+ "When selecting modules via URL params, the same modules are reflected in the page."
+ );
+ });
+ }
+ );
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: PAGE + "?preset=" + presetInURL,
+ },
+ async browser => {
+ await SpecialPowers.spawn(browser, [presetInURL], async presetInURL => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#some-elements-unavailable").hidden,
+ "If a preset is selected via URL, a warning should be displayed."
+ );
+ var inPageSorted = $("#current-log-modules")
+ .innerText.split(",")
+ .sort()
+ .join(",");
+ var presetSorted = content
+ .presets()
+ [presetInURL].modules.split(",")
+ .sort()
+ .join(",");
+ Assert.equal(
+ inPageSorted,
+ presetSorted,
+ "When selecting a preset via URL params, the correct log modules are reflected in the page."
+ );
+ });
+ }
+ );
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: PAGE + "?profiler-preset=" + profilerPresetInURL,
+ },
+ async browser => {
+ await SpecialPowers.spawn(browser, [profilerPresetInURL], async inURL => {
+ let $ = content.document.querySelector.bind(content.document);
+ // Threads override doesn't have a UI element, the warning shouldn't
+ // be displayed.
+ Assert.ok(
+ $("#some-elements-unavailable").hidden,
+ "When overriding the profiler preset, no warning is displayed on the page."
+ );
+ var inSettings = content.settings().profilerPreset;
+ Assert.equal(
+ inSettings,
+ inURL,
+ "When overriding the profiler preset via URL param, the correct preset is set in the logging manager settings."
+ );
+ });
+ }
+ );
+ await BrowserTestUtils.withNewTab(PAGE + "?profilerstacks", async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#some-elements-unavailable").hidden,
+ "If the profiler stacks config is set via URL, a warning should be displayed."
+ );
+ Assert.ok(
+ $("#with-profiler-stacks-checkbox").disabled,
+ "If the profiler stacks config is set via URL, its checkbox should be disabled."
+ );
+
+ Assert.ok(
+ Services.prefs.getBoolPref("logging.config.profilerstacks"),
+ "The preference for profiler stacks is set initially, as a result of parsing the URL parameter"
+ );
+
+ $("#radio-logging-file").click();
+ $("#radio-logging-profiler").click();
+
+ Assert.ok(
+ $("#with-profiler-stacks-checkbox").disabled,
+ "If the profiler stacks config is set via URL, its checkbox should be disabled even after clicking around."
+ );
+ });
+ });
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: PAGE + "?invalid-param",
+ },
+ async browser => {
+ await SpecialPowers.spawn(browser, [profilerPresetInURL], async inURL => {
+ let $ = content.document.querySelector.bind(content.document);
+ Assert.ok(
+ !$("#error").hidden,
+ "When an invalid URL param is passed in, the page displays a warning."
+ );
+ });
+ }
+ );
+ clearLoggingPrefs();
+});
+
+// Test various things related to presets: that it's populated correctly, that
+// setting presets work in terms of UI, but also that it sets the logging.*
+// prefs correctly.
+add_task(async function testAboutLoggingPresets() {
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ let presetsDropdown = $("#logging-preset-dropdown");
+ Assert.equal(
+ Object.keys(content.presets()).length,
+ presetsDropdown.childNodes.length,
+ "Presets populated."
+ );
+
+ Assert.equal(presetsDropdown.value, "networking");
+ $("#set-log-modules-button").click();
+ Assert.ok(
+ $("#no-log-modules").hidden && !$("#current-log-modules").hidden,
+ "When log modules are set, they are visible."
+ );
+ var lengthModuleListNetworking = $("#log-modules").value.length;
+ var lengthCurrentModuleListNetworking = $("#current-log-modules")
+ .innerText.length;
+ Assert.notEqual(
+ lengthModuleListNetworking,
+ 0,
+ "When setting a profiler preset, the module string is non-empty (input)."
+ );
+ Assert.notEqual(
+ lengthCurrentModuleListNetworking,
+ 0,
+ "When setting a profiler preset, the module string is non-empty (selected modules)."
+ );
+
+ // Change preset
+ presetsDropdown.value = "media-playback";
+ presetsDropdown.dispatchEvent(new content.Event("change"));
+
+ // Check the following after "onchange".
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => content.setTimeout(resolve, 0));
+
+ Assert.equal(
+ presetsDropdown.value,
+ "media-playback",
+ "Selecting another preset is reflected in the page"
+ );
+ $("#set-log-modules-button").click();
+ Assert.ok(
+ $("#no-log-modules").hidden && !$("#current-log-modules").hidden,
+ "When other log modules are set, they are still visible"
+ );
+ Assert.notEqual(
+ $("#log-modules").value.length,
+ 0,
+ "When setting a profiler preset, the module string is non-empty (input)."
+ );
+ Assert.notEqual(
+ $("#current-log-modules").innerText.length,
+ 0,
+ "When setting a profiler preset, the module string is non-empty (selected modules)."
+ );
+ Assert.notEqual(
+ $("#log-modules").value.length,
+ lengthModuleListNetworking,
+ "When setting another profiler preset, the module string changes (input)."
+ );
+ let currentLogModulesString = $("#current-log-modules").innerText;
+ Assert.notEqual(
+ currentLogModulesString.length,
+ lengthCurrentModuleListNetworking,
+
+ "When setting another profiler preset, the module string changes (selected modules)."
+ );
+
+ // After setting some log modules via the preset dropdown, verify
+ // that they have been reflected to logging.* preferences.
+ var activeLogModules = [];
+ let children = Services.prefs.getBranch("logging.").getChildList("");
+ for (let pref of children) {
+ if (pref.startsWith("config.")) {
+ continue;
+ }
+
+ try {
+ let value = Services.prefs.getIntPref(`logging.${pref}`);
+ activeLogModules.push(`${pref}:${value}`);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ let mod;
+ while ((mod = activeLogModules.pop())) {
+ Assert.ok(
+ currentLogModulesString.includes(mod),
+ `${mod} was effectively set`
+ );
+ }
+ });
+ });
+ clearLoggingPrefs();
+});
+
+// Test various things around the profiler stacks feature
+add_task(async function testProfilerStacks() {
+ // Check the initial state before changing anything.
+ Assert.ok(
+ !Services.prefs.getBoolPref("logging.config.profilerstacks", false),
+ "The preference for profiler stacks isn't set initially"
+ );
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ const checkbox = $("#with-profiler-stacks-checkbox");
+ Assert.ok(
+ !checkbox.checked,
+ "The profiler stacks checkbox isn't checked at load time."
+ );
+ checkbox.checked = true;
+ checkbox.dispatchEvent(new content.Event("change"));
+ Assert.ok(
+ Services.prefs.getBoolPref("logging.config.profilerstacks"),
+ "The preference for profiler stacks is now set to true"
+ );
+ checkbox.checked = false;
+ checkbox.dispatchEvent(new content.Event("change"));
+ Assert.ok(
+ !Services.prefs.getBoolPref("logging.config.profilerstacks"),
+ "The preference for profiler stacks is now back to false"
+ );
+
+ $("#radio-logging-file").click();
+ Assert.ok(
+ checkbox.disabled,
+ "The profiler stacks checkbox is disabled when the output type is 'file'"
+ );
+ $("#radio-logging-profiler").click();
+ Assert.ok(
+ !checkbox.disabled,
+ "The profiler stacks checkbox is enabled when the output type is 'profiler'"
+ );
+ });
+ });
+ clearLoggingPrefs();
+});
+
+// Here we test that starting and stopping log collection to the Firefox
+// Profiler opens a new tab. We don't actually check the content of the profile.
+add_task(async function testProfilerOpens() {
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ let profilerOpenedPromise = BrowserTestUtils.waitForNewTab(
+ gBrowser,
+ "https://example.com/",
+ false
+ );
+ SpecialPowers.spawn(browser, [], async savedLogModules => {
+ let $ = content.document.querySelector.bind(content.document);
+ // Override the URL the profiler uses to avoid hitting external
+ // resources (and crash).
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["devtools.performance.recording.ui-base-url", "https://example.com"],
+ ["devtools.performance.recording.ui-base-url-path", "/"],
+ ],
+ });
+ $("#radio-logging-file").click();
+ $("#radio-logging-profiler").click();
+ $("#logging-preset-dropdown").value = "networking";
+ $("#logging-preset-dropdown").dispatchEvent(new content.Event("change"));
+ $("#set-log-modules-button").click();
+ $("#toggle-logging-button").click();
+ // Wait for the profiler to start. This can be very slow.
+ await content.profilerPromise();
+
+ // Wait for some time for good measure while the profiler collects some
+ // data. We don't really care about the data itself.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => content.setTimeout(resolve, 1000));
+ $("#toggle-logging-button").click();
+ });
+ let tab = await profilerOpenedPromise;
+ Assert.ok(true, "Profiler tab opened after profiling");
+ await BrowserTestUtils.removeTab(tab);
+ });
+ clearLoggingPrefs();
+});
+
+// Same test, outputing to a file, with network logging, while opening and
+// closing a tab. We only check that the file exists and has a non-zero size.
+add_task(async function testLogFileFound() {
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ await SpecialPowers.spawn(browser, [], async () => {
+ // Clear any previous log file.
+ let $ = content.document.querySelector.bind(content.document);
+ $("#radio-logging-file").click();
+ $("#log-file").value = "";
+ $("#log-file").dispatchEvent(new content.Event("change"));
+ $("#set-log-file-button").click();
+
+ Assert.ok(
+ !$("#no-log-file").hidden,
+ "When a log file hasn't been set, it's indicated as such."
+ );
+ });
+ });
+ await BrowserTestUtils.withNewTab(PAGE, async browser => {
+ let logPath = await SpecialPowers.spawn(browser, [], async () => {
+ let $ = content.document.querySelector.bind(content.document);
+ $("#radio-logging-file").click();
+ // Set the log file (use the default path)
+ $("#set-log-file-button").click();
+ var logPath = $("#current-log-file").innerText;
+ // Set log modules for networking
+ $("#logging-preset-dropdown").value = "networking";
+ $("#logging-preset-dropdown").dispatchEvent(new content.Event("change"));
+ $("#set-log-modules-button").click();
+ return logPath;
+ });
+
+ // No need to start or stop logging when logging to a file. Just open
+ // a tab, any URL will do. Wait for this tab to be loaded so we're sure
+ // something (anything) has happened in necko.
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "https://example.com",
+ true /* waitForLoad */
+ );
+ await BrowserTestUtils.removeTab(tab);
+ let logDirectory = PathUtils.parent(logPath);
+ let logBasename = PathUtils.filename(logPath);
+ let entries = await IOUtils.getChildren(logDirectory);
+ let foundNonEmptyLogFile = false;
+ for (let entry of entries) {
+ if (entry.includes(logBasename)) {
+ info("-- Log file found: " + entry);
+ let fileinfo = await IOUtils.stat(entry);
+ foundNonEmptyLogFile |= fileinfo.size > 0;
+ }
+ }
+ Assert.ok(foundNonEmptyLogFile, "Found at least one non-empty log file.");
+ });
+ clearLoggingPrefs();
+});