forked from mirrors/gecko-dev
Bug 1800076 - Test about:logging. r=mossop
Differential Revision: https://phabricator.services.mozilla.com/D162014
This commit is contained in:
parent
dd75e63e38
commit
ac6e2fd862
3 changed files with 419 additions and 1 deletions
|
|
@ -97,6 +97,23 @@ const gLoggingSettings = {
|
|||
profilerThreads: null,
|
||||
};
|
||||
|
||||
// When the profiler has been started, this holds the promise the
|
||||
// Services.profiler.StartProfiler returns, to ensure the profiler has
|
||||
// effectively started.
|
||||
let gProfilerPromise = null;
|
||||
|
||||
function presets() {
|
||||
return gLoggingPresets;
|
||||
}
|
||||
|
||||
function settings() {
|
||||
return gLoggingSettings;
|
||||
}
|
||||
|
||||
function profilerPromise() {
|
||||
return gProfilerPromise;
|
||||
}
|
||||
|
||||
function populatePresets() {
|
||||
let dropdown = $("#logging-preset-dropdown");
|
||||
for (let presetName in gLoggingPresets) {
|
||||
|
|
@ -145,6 +162,7 @@ function updateLoggingOutputType(profilerOutputType) {
|
|||
$("#log-file-configuration").hidden = true;
|
||||
} else if (gLoggingSettings.loggingOutputType === "file") {
|
||||
$("#log-file-configuration").hidden = false;
|
||||
$("#no-log-file").hidden = !!$("#current-log-file").innerText.length;
|
||||
}
|
||||
|
||||
Services.prefs.setCharPref(
|
||||
|
|
@ -616,7 +634,7 @@ function startLogging() {
|
|||
CustomizableUI.dispatchToolboxEvent("customizationchange");
|
||||
}
|
||||
|
||||
Services.profiler.StartProfiler(
|
||||
gProfilerPromise = Services.profiler.StartProfiler(
|
||||
entries,
|
||||
interval,
|
||||
features,
|
||||
|
|
|
|||
|
|
@ -152,3 +152,6 @@ skip-if =
|
|||
debug # Bug 1388959
|
||||
[browser_about_networking.js]
|
||||
skip-if = socketprocess_networking
|
||||
[browser_about_logging.js]
|
||||
skip-if =
|
||||
tsan # Bug 1804081
|
||||
|
|
|
|||
397
toolkit/content/tests/browser/browser_about_logging.js
Normal file
397
toolkit/content/tests/browser/browser_about_logging.js
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
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(
|
||||
{
|
||||
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();
|
||||
});
|
||||
|
||||
// // 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.");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue