From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../content/tests/browser/browser_about_logging.js | 464 +++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 toolkit/content/tests/browser/browser_about_logging.js (limited to 'toolkit/content/tests/browser/browser_about_logging.js') 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(); +}); -- cgit v1.2.3