diff options
Diffstat (limited to 'browser/modules/test')
6 files changed, 591 insertions, 203 deletions
diff --git a/browser/modules/test/browser/browser.toml b/browser/modules/test/browser/browser.toml index 21b3cdf18c..82611ed4b2 100644 --- a/browser/modules/test/browser/browser.toml +++ b/browser/modules/test/browser/browser.toml @@ -36,6 +36,10 @@ support-files = [ "../../../base/content/test/tabs/file_mediaPlayback.html", "../../../base/content/test/general/audio.ogg", ] +skip-if = [ + "os == 'linux' && os_version == '18.04' && asan", # Bug 1781868 + "os == 'linux' && os_version == '18.04' && tsan", # Bug 1781868 +] ["browser_Telemetry_numberOfSiteOrigins.js"] support-files = ["contain_iframe.html"] diff --git a/browser/modules/test/browser/browser_ProcessHangNotifications.js b/browser/modules/test/browser/browser_ProcessHangNotifications.js index 9150c36d4c..963dc2d4b4 100644 --- a/browser/modules/test/browser/browser_ProcessHangNotifications.js +++ b/browser/modules/test/browser/browser_ProcessHangNotifications.js @@ -184,7 +184,7 @@ add_task(async function waitForScriptTest() { }); // Click the "Close" button this time, we shouldn't get a callback at all. - notification.currentNotification.closeButtonEl.click(); + notification.currentNotification.closeButton.click(); // send another hang pulse, we should not get a notification here Services.obs.notifyObservers(hangReport, "process-hang-report"); diff --git a/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js b/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js index 6300bd17ba..d105e8374e 100644 --- a/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js +++ b/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js @@ -292,7 +292,7 @@ add_task(async function test_other_ignored() { Assert.ok(notification, "There should be a notification"); // Dismiss notification, creating the .dmp.ignore file - notification.closeButtonEl.click(); + notification.closeButton.click(); gNotificationBox.removeNotification(notification, true); await waitForIgnoredReports(toIgnore); @@ -525,7 +525,7 @@ add_task(async function test_can_ignore() { Assert.ok(notification, "There should be a notification"); // Dismiss the notification by clicking on the "X" button. - notification.closeButtonEl.click(); + notification.closeButton.click(); // We'll not wait for the notification to finish its transition - // we'll just remove it right away. gNotificationBox.removeNotification(notification, true); @@ -599,7 +599,7 @@ add_task(async function test_shutdown_while_not_showing() { Assert.ok(notification, "There should be a notification"); // Dismiss the notification by clicking on the "X" button. - notification.closeButtonEl.click(); + notification.closeButton.click(); // We'll not wait for the notification to finish its transition - // we'll just remove it right away. gNotificationBox.removeNotification(notification, true); diff --git a/browser/modules/test/browser/browser_UsageTelemetry_interaction.js b/browser/modules/test/browser/browser_UsageTelemetry_interaction.js index 5fa436a349..56a7f530ad 100644 --- a/browser/modules/test/browser/browser_UsageTelemetry_interaction.js +++ b/browser/modules/test/browser/browser_UsageTelemetry_interaction.js @@ -33,6 +33,8 @@ const AREAS = [ // keys in the scalars. Also runs keyed scalar checks against non-area types // passed in through expectedOther. function assertInteractionScalars(expectedAreas, expectedOther = {}) { + // Every time this checks Scalars, it clears them. So clear FOG too. + Services.fog.testResetFOG(); let processScalars = Services.telemetry.getSnapshotForKeyedScalars("main", true)?.parent ?? {}; @@ -83,6 +85,7 @@ add_task(async function toolbarButtons() { }); Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser); let tabClose = BrowserTestUtils.waitForTabClosing(newTab); @@ -164,6 +167,22 @@ add_task(async function toolbarButtons() { click(customButton); + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "stop-reload-button"], + ["nav-bar", "back-button"], + ["nav-bar", "back-button"], + ["all-tabs-panel-entrypoint", "alltabs-button"], + ["tabs-bar", "alltabs-button"], + ["tabs-bar", "tab-close-button"], + ["bookmarks-bar", "bookmark-item"], + ["nav-bar", "12foo"], + ], + events + ); assertInteractionScalars( { nav_bar: { @@ -192,6 +211,7 @@ add_task(async function toolbarButtons() { add_task(async function contextMenu() { await BrowserTestUtils.withNewTab("https://example.com", async browser => { Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); let tab = gBrowser.getTabForBrowser(browser); let context = elem("tabContextMenu"); @@ -207,6 +227,16 @@ add_task(async function contextMenu() { context.activateItem(document.getElementById("context_toggleMuteTab")); await hidden; + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["tabs-context", "context-toggleMuteTab"], + ["tabs-context-entrypoint", "context-toggleMuteTab"], + ], + events + ); assertInteractionScalars({ tabs_context: { "context-toggleMuteTab": 1, @@ -233,6 +263,16 @@ add_task(async function contextMenu() { ); await hidden; + events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["tabs-context", "toolbar-context-selectAllTabs"], + ["tabs-context-entrypoint", "toolbar-context-selectAllTabs"], + ], + events + ); assertInteractionScalars({ tabs_context: { "toolbar-context-selectAllTabs": 1, @@ -318,6 +358,7 @@ add_task(async function contextMenu_entrypoints() { add_task(async function appMenu() { await BrowserTestUtils.withNewTab("https://example.com", async () => { Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); let shown = BrowserTestUtils.waitForEvent( elem("appMenu-popup"), @@ -339,9 +380,21 @@ add_task(async function appMenu() { nav_bar: { "PanelUI-menu-button": 1, }, - app_menu: {}, + app_menu: { + [findButtonID]: 1, + }, }; - expectedScalars.app_menu[findButtonID] = 1; + + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "PanelUI-menu-button"], + ["app-menu", findButtonID], + ], + events + ); assertInteractionScalars(expectedScalars); }); @@ -350,6 +403,7 @@ add_task(async function appMenu() { add_task(async function devtools() { await BrowserTestUtils.withNewTab("https://example.com", async () => { Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); let shown = BrowserTestUtils.waitForEvent( elem("appMenu-popup"), @@ -381,6 +435,17 @@ add_task(async function devtools() { BrowserTestUtils.removeTab(tab); // Note that item ID's have '_' converted to '-'. + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "PanelUI-menu-button"], + ["app-menu", "appMenu-more-button2"], + ["app-menu", "key-viewSource"], + ], + events + ); assertInteractionScalars({ nav_bar: { "PanelUI-menu-button": 1, @@ -398,6 +463,7 @@ add_task(async function webextension() { await BrowserTestUtils.withNewTab("https://example.com", async browser => { Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); function background() { browser.commands.onCommand.addListener(() => { @@ -470,6 +536,11 @@ add_task(async function webextension() { // As the first add-on interacted with this should show up as `addon0`. click("random_addon_example_com-browser-action"); + let events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["nav-bar", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ nav_bar: { addon0: 1, @@ -482,6 +553,11 @@ add_task(async function webextension() { ); click("pageAction-urlbar-random_addon_example_com"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["pageaction-urlbar", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ pageaction_urlbar: { addon0: 1, @@ -490,6 +566,11 @@ add_task(async function webextension() { EventUtils.synthesizeKey("j", { altKey: true, shiftKey: true }); await extension.awaitMessage("oncommand"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["keyboard", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ keyboard: { addon0: 1, @@ -498,6 +579,11 @@ add_task(async function webextension() { EventUtils.synthesizeKey("q", { altKey: true, shiftKey: true }); await extension.awaitMessage("sidebar-opened"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["keyboard", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ keyboard: { addon0: 1, @@ -537,6 +623,11 @@ add_task(async function webextension() { // A second extension should be `addon1`. click("random_addon2_example_com-browser-action"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["nav-bar", "addon1"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ nav_bar: { addon1: 1, @@ -549,6 +640,11 @@ add_task(async function webextension() { ); click("pageAction-urlbar-random_addon2_example_com"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["pageaction-urlbar", "addon1"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ pageaction_urlbar: { addon1: 1, @@ -557,6 +653,11 @@ add_task(async function webextension() { EventUtils.synthesizeKey("9", { altKey: true, shiftKey: true }); await extension2.awaitMessage("oncommand"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["keyboard", "addon1"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ keyboard: { addon1: 1, @@ -565,6 +666,11 @@ add_task(async function webextension() { // The first should have retained its ID. click("random_addon_example_com-browser-action"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["nav-bar", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ nav_bar: { addon0: 1, @@ -573,6 +679,11 @@ add_task(async function webextension() { EventUtils.synthesizeKey("j", { altKey: true, shiftKey: true }); await extension.awaitMessage("oncommand"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["keyboard", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ keyboard: { addon0: 1, @@ -580,6 +691,11 @@ add_task(async function webextension() { }); click("pageAction-urlbar-random_addon_example_com"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["pageaction-urlbar", "addon0"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ pageaction_urlbar: { addon0: 1, @@ -590,11 +706,19 @@ add_task(async function webextension() { // Clear the last opened ID so if this test runs again the sidebar won't // automatically open when the extension is installed. - window.SidebarUI.lastOpenedId = null; + window.SidebarController.lastOpenedId = null; // The second should retain its ID. click("random_addon2_example_com-browser-action"); click("random_addon2_example_com-browser-action"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [ + ["nav-bar", "addon1"], + ["nav-bar", "addon1"], + ], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ nav_bar: { addon1: 2, @@ -602,6 +726,11 @@ add_task(async function webextension() { }); click("pageAction-urlbar-random_addon2_example_com"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["pageaction-urlbar", "addon1"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ pageaction_urlbar: { addon1: 1, @@ -610,6 +739,11 @@ add_task(async function webextension() { EventUtils.synthesizeKey("9", { altKey: true, shiftKey: true }); await extension2.awaitMessage("oncommand"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["keyboard", "addon1"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ keyboard: { addon1: 1, @@ -643,6 +777,11 @@ add_task(async function webextension() { await shown; click("random_addon3_example_com-browser-action"); + events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["unified-extensions-area", "addon2"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ unified_extensions_area: { addon2: 1, @@ -669,6 +808,7 @@ add_task(async function mainMenu() { await BrowserTestUtils.withNewTab("https://example.com", async () => { Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); CustomizableUI.setToolbarVisibility("toolbar-menubar", true); @@ -686,6 +826,11 @@ add_task(async function mainMenu() { click("menu_selectAll"); await hidden; + let events = Glean.browserUsage.interaction.testGetValue(); + Assert.deepEqual( + [["menu-bar", "menu-selectAll"]], + events.map(e => [e.extra.source, e.extra.widget_id]) + ); assertInteractionScalars({ menu_bar: { // Note that the _ is replaced with - for telemetry identifiers. @@ -706,6 +851,7 @@ add_task(async function preferences() { await finalPrefPaneLoaded; Services.telemetry.getSnapshotForKeyedScalars("main", true); + Services.fog.testResetFOG(); await BrowserTestUtils.synthesizeMouseAtCenter( "#browserRestoreSession", @@ -742,6 +888,16 @@ add_task(async function preferences() { await onLearnMoreOpened; gBrowser.removeCurrentTab(); + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["preferences_paneGeneral", "browserRestoreSession"], + ["preferences_panePrivacy", "contentBlockingLearnMore"], + ], + events + ); assertInteractionScalars({ preferences_paneGeneral: { browserRestoreSession: 1, @@ -806,6 +962,17 @@ async function history_appMenu(useContextClick) { app_menu: { "history-item": 1, "appMenu-history-button": 1 }, }; + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "PanelUI-menu-button"], + ["app-menu", "appMenu-history-button"], + ["app-menu", "history-item"], + ], + events + ); assertInteractionScalars(expectedScalars); }); } @@ -852,6 +1019,17 @@ async function bookmarks_appMenu(useContextClick) { app_menu: { "bookmark-item": 1, "appMenu-bookmarks-button": 1 }, }; + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "PanelUI-menu-button"], + ["app-menu", "appMenu-bookmarks-button"], + ["app-menu", "bookmark-item"], + ], + events + ); assertInteractionScalars(expectedScalars); }); } @@ -893,6 +1071,17 @@ async function bookmarks_library_navbar(useContextClick) { "appMenu-library-bookmarks-button": 1, }, }; + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "library-button"], + ["nav-bar", "appMenu-library-bookmarks-button"], + ["nav-bar", "bookmark-item"], + ], + events + ); assertInteractionScalars(expectedScalars); }); @@ -940,6 +1129,17 @@ async function history_library_navbar(useContextClick) { "appMenu-library-history-button": 1, }, }; + let events = Glean.browserUsage.interaction + .testGetValue() + .map(e => [e.extra.source, e.extra.widget_id]); + Assert.deepEqual( + [ + ["nav-bar", "library-button"], + ["nav-bar", "appMenu-library-history-button"], + ["nav-bar", "history-item"], + ], + events + ); assertInteractionScalars(expectedScalars); }); diff --git a/browser/modules/test/unit/test_FirefoxBridgeExtensionUtils.js b/browser/modules/test/unit/test_FirefoxBridgeExtensionUtils.js index 77db0d8286..d4dcd4fad6 100644 --- a/browser/modules/test/unit/test_FirefoxBridgeExtensionUtils.js +++ b/browser/modules/test/unit/test_FirefoxBridgeExtensionUtils.js @@ -7,9 +7,10 @@ const { FirefoxBridgeExtensionUtils } = ChromeUtils.importESModule( "resource:///modules/FirefoxBridgeExtensionUtils.sys.mjs" ); -const FIREFOX_SHELL_OPEN_COMMAND_PATH = "firefox\\shell\\open\\command"; -const FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH = - "firefox-private\\shell\\open\\command"; +const OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL}\\shell\\open\\command`; +const OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL}\\shell\\open\\command`; +const FIREFOX_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL}\\shell\\open\\command`; +const FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH = `${FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL}\\shell\\open\\command`; class StubbedRegistryKey { #children; @@ -145,206 +146,274 @@ class StubbedDeleteBridgeProtocolRegistryEntryHelper { } add_task(async function test_DeleteWhenSameFirefoxInstall() { - const applicationPath = "testPath"; - - const firefoxEntries = new Map(); - firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`); - - const firefoxProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxEntries - ); - - const firefoxPrivateEntries = new Map(); - firefoxPrivateEntries.set( - "", - `\"${applicationPath}\" -osint -private-window \"%1\"` - ); - const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxPrivateEntries - ); - - const children = new Map(); - children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey); - children.set( - FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, - firefoxPrivateProtocolRegKey - ); - - const registryRootKey = new StubbedRegistryKey(children, new Map()); - - const stubbedDeleteBridgeProtocolRegistryHelper = - new StubbedDeleteBridgeProtocolRegistryEntryHelper({ - applicationPath, - registryRootKey, - }); - - FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( - stubbedDeleteBridgeProtocolRegistryHelper - ); - - ok(registryRootKey.wasCloseCalled, "Root key closed"); - - ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); - ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); - ok( - registryRootKey.isChildDeleted("firefox"), - "Firefox protocol registry entry deleted" - ); - - ok( - firefoxPrivateProtocolRegKey.wasOpenedForRead, - "Firefox private key opened" - ); - ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed"); - ok( - registryRootKey.isChildDeleted("firefox-private"), - "Firefox private protocol registry entry deleted" - ); + for (let protocols of [ + [ + FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL, + OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH, + OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + [ + FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL, + FIREFOX_SHELL_OPEN_COMMAND_PATH, + FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + ]) { + let [publicProtocol, privateProtocol, publicPath, privatePath] = protocols; + const applicationPath = "testPath"; + + const firefoxEntries = new Map(); + firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`); + + const firefoxProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxEntries + ); + + const firefoxPrivateEntries = new Map(); + firefoxPrivateEntries.set( + "", + `\"${applicationPath}\" -osint -private-window \"%1\"` + ); + const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxPrivateEntries + ); + + const children = new Map(); + children.set(publicPath, firefoxProtocolRegKey); + children.set(privatePath, firefoxPrivateProtocolRegKey); + + const registryRootKey = new StubbedRegistryKey(children, new Map()); + + const stubbedDeleteBridgeProtocolRegistryHelper = + new StubbedDeleteBridgeProtocolRegistryEntryHelper({ + applicationPath, + registryRootKey, + }); + + FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( + publicProtocol, + privateProtocol, + stubbedDeleteBridgeProtocolRegistryHelper + ); + + ok(registryRootKey.wasCloseCalled, "Root key closed"); + + ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); + ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); + ok( + registryRootKey.isChildDeleted(publicProtocol), + "Firefox protocol registry entry deleted" + ); + + ok( + firefoxPrivateProtocolRegKey.wasOpenedForRead, + "Firefox private key opened" + ); + ok( + firefoxPrivateProtocolRegKey.wasCloseCalled, + "Firefox private key closed" + ); + ok( + registryRootKey.isChildDeleted(privateProtocol), + "Firefox private protocol registry entry deleted" + ); + } }); add_task(async function test_DeleteWhenDifferentFirefoxInstall() { - const applicationPath = "testPath"; - const badApplicationPath = "testPath2"; - - const firefoxEntries = new Map(); - firefoxEntries.set("", `\"${badApplicationPath}\" -osint -url \"%1\"`); - - const firefoxProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxEntries - ); - - const firefoxPrivateEntries = new Map(); - firefoxPrivateEntries.set( - "", - `\"${badApplicationPath}\" -osint -private-window \"%1\"` - ); - const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxPrivateEntries - ); - - const children = new Map(); - children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey); - children.set( - FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, - firefoxPrivateProtocolRegKey - ); - - const registryRootKey = new StubbedRegistryKey(children, new Map()); - - const stubbedDeleteBridgeProtocolRegistryHelper = - new StubbedDeleteBridgeProtocolRegistryEntryHelper({ - applicationPath, - registryRootKey, - }); - - FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( - stubbedDeleteBridgeProtocolRegistryHelper - ); - - ok(registryRootKey.wasCloseCalled, "Root key closed"); - - ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); - ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); - ok( - !registryRootKey.isChildDeleted("firefox"), - "Firefox protocol registry entry not deleted" - ); - - ok( - firefoxPrivateProtocolRegKey.wasOpenedForRead, - "Firefox private key opened" - ); - ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed"); - ok( - !registryRootKey.isChildDeleted("firefox-private"), - "Firefox private protocol registry entry not deleted" - ); + for (let protocols of [ + [ + FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL, + OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH, + OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + [ + FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL, + FIREFOX_SHELL_OPEN_COMMAND_PATH, + FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + ]) { + let [publicProtocol, privateProtocol, publicPath, privatePath] = protocols; + const applicationPath = "testPath"; + const badApplicationPath = "testPath2"; + + const firefoxEntries = new Map(); + firefoxEntries.set("", `\"${badApplicationPath}\" -osint -url \"%1\"`); + + const firefoxProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxEntries + ); + + const firefoxPrivateEntries = new Map(); + firefoxPrivateEntries.set( + "", + `\"${badApplicationPath}\" -osint -private-window \"%1\"` + ); + const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxPrivateEntries + ); + + const children = new Map(); + children.set(publicPath, firefoxProtocolRegKey); + children.set(privatePath, firefoxPrivateProtocolRegKey); + + const registryRootKey = new StubbedRegistryKey(children, new Map()); + + const stubbedDeleteBridgeProtocolRegistryHelper = + new StubbedDeleteBridgeProtocolRegistryEntryHelper({ + applicationPath, + registryRootKey, + }); + + FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( + publicProtocol, + privateProtocol, + stubbedDeleteBridgeProtocolRegistryHelper + ); + + ok(registryRootKey.wasCloseCalled, "Root key closed"); + + ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); + ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); + ok( + !registryRootKey.isChildDeleted(publicProtocol), + "Firefox protocol registry entry not deleted" + ); + + ok( + firefoxPrivateProtocolRegKey.wasOpenedForRead, + "Firefox private key opened" + ); + ok( + firefoxPrivateProtocolRegKey.wasCloseCalled, + "Firefox private key closed" + ); + ok( + !registryRootKey.isChildDeleted(privateProtocol), + "Firefox private protocol registry entry not deleted" + ); + } }); add_task(async function test_DeleteWhenNoRegistryEntries() { - const applicationPath = "testPath"; - - const firefoxPrivateEntries = new Map(); - const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxPrivateEntries - ); - - const children = new Map(); - children.set( - FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, - firefoxPrivateProtocolRegKey - ); - - const registryRootKey = new StubbedRegistryKey(children, new Map()); - - const stubbedDeleteBridgeProtocolRegistryHelper = - new StubbedDeleteBridgeProtocolRegistryEntryHelper({ - applicationPath, - registryRootKey, - }); - - FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( - stubbedDeleteBridgeProtocolRegistryHelper - ); - - ok(registryRootKey.wasCloseCalled, "Root key closed"); - - ok( - firefoxPrivateProtocolRegKey.wasOpenedForRead, - "Firefox private key opened" - ); - ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed"); - ok( - !registryRootKey.isChildDeleted("firefox"), - "Firefox protocol registry entry deleted when it shouldn't be" - ); - ok( - !registryRootKey.isChildDeleted("firefox-private"), - "Firefox private protocol registry deleted when it shouldn't be" - ); + for (let protocols of [ + [ + FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL, + OLD_FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + [ + FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL, + FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH, + ], + ]) { + let [publicProtocol, privateProtocol, privatePath] = protocols; + const applicationPath = "testPath"; + + const firefoxPrivateEntries = new Map(); + const firefoxPrivateProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxPrivateEntries + ); + + const children = new Map(); + children.set(privatePath, firefoxPrivateProtocolRegKey); + + const registryRootKey = new StubbedRegistryKey(children, new Map()); + + const stubbedDeleteBridgeProtocolRegistryHelper = + new StubbedDeleteBridgeProtocolRegistryEntryHelper({ + applicationPath, + registryRootKey, + }); + + FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( + publicProtocol, + privateProtocol, + stubbedDeleteBridgeProtocolRegistryHelper + ); + + ok(registryRootKey.wasCloseCalled, "Root key closed"); + + ok( + firefoxPrivateProtocolRegKey.wasOpenedForRead, + "Firefox private key opened" + ); + ok( + firefoxPrivateProtocolRegKey.wasCloseCalled, + "Firefox private key closed" + ); + ok( + !registryRootKey.isChildDeleted(publicProtocol), + "Firefox protocol registry entry deleted when it shouldn't be" + ); + ok( + !registryRootKey.isChildDeleted(privateProtocol), + "Firefox private protocol registry deleted when it shouldn't be" + ); + } }); add_task(async function test_DeleteWhenUnexpectedRegistryEntries() { - const applicationPath = "testPath"; - - const firefoxEntries = new Map(); - firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`); - firefoxEntries.set("extraEntry", "extraValue"); - const firefoxProtocolRegKey = new StubbedRegistryKey( - new Map(), - firefoxEntries - ); - - const children = new Map(); - children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey); - - const registryRootKey = new StubbedRegistryKey(children, new Map()); - - const stubbedDeleteBridgeProtocolRegistryHelper = - new StubbedDeleteBridgeProtocolRegistryEntryHelper({ - applicationPath, - registryRootKey, - }); - - FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( - stubbedDeleteBridgeProtocolRegistryHelper - ); - - ok(registryRootKey.wasCloseCalled, "Root key closed"); - - ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); - ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); - ok( - !registryRootKey.isChildDeleted("firefox"), - "Firefox protocol registry entry deleted when it shouldn't be" - ); - ok( - !registryRootKey.isChildDeleted("firefox-private"), - "Firefox private protocol registry deleted when it shouldn't be" - ); + for (let protocols of [ + [ + FirefoxBridgeExtensionUtils.OLD_PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.OLD_PRIVATE_PROTOCOL, + OLD_FIREFOX_SHELL_OPEN_COMMAND_PATH, + ], + [ + FirefoxBridgeExtensionUtils.PUBLIC_PROTOCOL, + FirefoxBridgeExtensionUtils.PRIVATE_PROTOCOL, + FIREFOX_SHELL_OPEN_COMMAND_PATH, + ], + ]) { + let [publicProtocol, privateProtocol, publicPath] = protocols; + const applicationPath = "testPath"; + + const firefoxEntries = new Map(); + firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`); + firefoxEntries.set("extraEntry", "extraValue"); + const firefoxProtocolRegKey = new StubbedRegistryKey( + new Map(), + firefoxEntries + ); + + const children = new Map(); + children.set(publicPath, firefoxProtocolRegKey); + + const registryRootKey = new StubbedRegistryKey(children, new Map()); + + const stubbedDeleteBridgeProtocolRegistryHelper = + new StubbedDeleteBridgeProtocolRegistryEntryHelper({ + applicationPath, + registryRootKey, + }); + + FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries( + publicProtocol, + privateProtocol, + stubbedDeleteBridgeProtocolRegistryHelper + ); + + ok(registryRootKey.wasCloseCalled, "Root key closed"); + + ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened"); + ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed"); + ok( + !registryRootKey.isChildDeleted(publicProtocol), + "Firefox protocol registry entry deleted when it shouldn't be" + ); + ok( + !registryRootKey.isChildDeleted(privateProtocol), + "Firefox private protocol registry deleted when it shouldn't be" + ); + } }); diff --git a/browser/modules/test/unit/test_FirefoxBridgeExtensionUtilsNativeManifest.js b/browser/modules/test/unit/test_FirefoxBridgeExtensionUtilsNativeManifest.js index cef550d705..8686871255 100644 --- a/browser/modules/test/unit/test_FirefoxBridgeExtensionUtilsNativeManifest.js +++ b/browser/modules/test/unit/test_FirefoxBridgeExtensionUtilsNativeManifest.js @@ -16,6 +16,30 @@ const { FirefoxBridgeExtensionUtils } = ChromeUtils.importESModule( const DUAL_BROWSER_EXTENSION_ORIGIN = ["chrome-extension://fake-origin/"]; const NATIVE_MESSAGING_HOST_ID = "org.mozilla.firefox_bridge_test"; +if (AppConstants.platform == "win") { + var { MockRegistry } = ChromeUtils.importESModule( + "resource://testing-common/MockRegistry.sys.mjs" + ); +} + +let registry = null; +add_setup(() => { + if (AppConstants.platform == "win") { + registry = new MockRegistry(); + registerCleanupFunction(() => { + registry.shutdown(); + }); + } +}); + +function resetMockRegistry() { + if (AppConstants.platform != "win") { + return; + } + registry.shutdown(); + registry = new MockRegistry(); +} + let dir = FileUtils.getDir("TmpD", ["NativeMessagingHostsTest"]); dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); @@ -75,6 +99,35 @@ function getExpectedOutput() { }; } +function DumpWindowsRegistry() { + let key = ""; + let pathBuffer = []; + + if (AppConstants.platform == "win") { + function bufferPrint(line) { + let regPath = line.trimStart(); + if (regPath.includes(":")) { + // After trimming white space, keys are formatted as + // ": <key> (<value_type>)". We can assume it's only ever + // going to be of type REG_SZ for this test. + key = regPath.slice(2, regPath.length - " (REG_SZ)".length); + } else { + pathBuffer.push(regPath); + } + } + + MockRegistry.dump( + MockRegistry.getRoot(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER), + "", + bufferPrint + ); + } else { + Assert.ok(false, "Only windows has a registry!"); + } + + return [pathBuffer, key]; +} + add_task(async function test_maybeWriteManifestFiles() { await FirefoxBridgeExtensionUtils.maybeWriteManifestFiles( USER_TEST_PATH, @@ -196,6 +249,7 @@ add_task(async function test_ensureRegistered() { appDir.path, "Mozilla\\Firefox" ); + resetMockRegistry(); } else { throw new Error("Unsupported platform"); } @@ -219,4 +273,65 @@ add_task(async function test_ensureRegistered() { let JSONContent = await IOUtils.readUTF8(expectedJSONPath); await IOUtils.remove(expectedJSONPath); Assert.equal(JSONContent, expectedOutput); + + // Test that the registry key is written for Windows only + if (AppConstants.platform == "win") { + let [pathBuffer, key] = DumpWindowsRegistry(); + Assert.equal( + pathBuffer.toString(), + [ + "Software", + "Google", + "Chrome", + "NativeMessagingHosts", + nativeHostId, + ].toString() + ); + Assert.equal(key, expectedJSONPath); + } +}); + +add_task(async function test_maybeWriteNativeMessagingRegKeys() { + if (AppConstants.platform != "win") { + return; + } + resetMockRegistry(); + FirefoxBridgeExtensionUtils.maybeWriteNativeMessagingRegKeys( + "Test\\Path\\For\\Reg\\Key", + binFile.parent.path, + NATIVE_MESSAGING_HOST_ID + ); + let [pathBuffer, key] = DumpWindowsRegistry(); + registry.shutdown(); + Assert.equal( + pathBuffer.toString(), + ["Test", "Path", "For", "Reg", "Key", NATIVE_MESSAGING_HOST_ID].toString() + ); + console.log("The key is: " + key); + Assert.equal(key, `${binFile.parent.path}\\${NATIVE_MESSAGING_HOST_ID}.json`); +}); + +add_task(async function test_maybeWriteNativeMessagingRegKeysIncorrectValue() { + if (AppConstants.platform != "win") { + return; + } + resetMockRegistry(); + registry.setValue( + Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + `Test\\Path\\For\\Reg\\Key\\${NATIVE_MESSAGING_HOST_ID}`, + "", + "IncorrectValue" + ); + FirefoxBridgeExtensionUtils.maybeWriteNativeMessagingRegKeys( + "Test\\Path\\For\\Reg\\Key", + binFile.parent.path, + NATIVE_MESSAGING_HOST_ID + ); + let [pathBuffer, key] = DumpWindowsRegistry(); + registry.shutdown(); + Assert.equal( + pathBuffer.toString(), + ["Test", "Path", "For", "Reg", "Key", NATIVE_MESSAGING_HOST_ID].toString() + ); + Assert.equal(key, `${binFile.parent.path}\\${NATIVE_MESSAGING_HOST_ID}.json`); }); |