"use strict"; const { AddonManager } = ChromeUtils.importESModule( "resource://gre/modules/AddonManager.sys.mjs" ); const { ExtensionPermissions } = ChromeUtils.importESModule( "resource://gre/modules/ExtensionPermissions.sys.mjs" ); ChromeUtils.defineESModuleGetters(this, { ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs", }); AddonTestUtils.init(this); AddonTestUtils.overrideCertDB(); AddonTestUtils.createAppInfo( "xpcshell@tests.mozilla.org", "XPCShell", "1", "42" ); Services.prefs.setBoolPref( "extensions.dataCollectionPermissions.enabled", true ); let OptionalPermissions; add_setup(async () => { // FOG needs a profile and to be initialized. do_get_profile(); Services.fog.initializeFOG(); Services.fog.testResetFOG(); // Bug 1646182: Force ExtensionPermissions to run in rkv mode, the legacy // storage mode will run in xpcshell-legacy-ep.toml await ExtensionPermissions._uninit(); Services.prefs.setBoolPref( "extensions.webextOptionalPermissionPrompts", false ); registerCleanupFunction(() => { Services.prefs.clearUserPref("extensions.webextOptionalPermissionPrompts"); }); await AddonTestUtils.promiseStartupManager(); AddonTestUtils.usePrivilegedSignatures = false; // We want to get a list of optional permissions prior to loading an extension, // so we'll get ExtensionParent to do that for us. await ExtensionParent.apiManager.lazyInit(); // These permissions have special behaviors and/or are not mapped directly to an // api namespace. They will have their own tests for specific behavior. let ignore = [ "activeTab", "clipboardRead", "clipboardWrite", "declarativeNetRequestFeedback", "devtools", "downloads.open", "geolocation", "management", "menus.overrideContext", "nativeMessaging", "scripting", "search", "tabHide", "tabs", "trialML", "webRequestAuthProvider", "webRequestBlocking", "webRequestFilterResponse", "webRequestFilterResponse.serviceWorkerScript", ]; // "OptionalOnlyPermission" is not included in the list below, because a test // below tries to request all permissions at once. That is not supported when // optional-only. See test_ext_permissions_optional_only.js instead. OptionalPermissions = Schemas.getPermissionNames([ "OptionalPermission", "OptionalPermissionNoPrompt", ]).filter(n => !ignore.includes(n)); }); add_task(async function test_api_on_permissions_changed() { async function background() { let manifest = browser.runtime.getManifest(); let permObj = { permissions: manifest.optional_permissions, origins: [] }; function verifyPermissions(enabled) { for (let perm of manifest.optional_permissions) { browser.test.assertEq( enabled, !!browser[perm], `${perm} API is ${ enabled ? "injected" : "removed" } after permission request` ); } } browser.permissions.onAdded.addListener(details => { browser.test.assertEq( JSON.stringify(details.permissions), JSON.stringify(manifest.optional_permissions), "expected permissions added" ); verifyPermissions(true); browser.test.sendMessage("added"); }); browser.permissions.onRemoved.addListener(details => { browser.test.assertEq( JSON.stringify(details.permissions), JSON.stringify(manifest.optional_permissions), "expected permissions removed" ); verifyPermissions(false); browser.test.sendMessage("removed"); }); browser.test.onMessage.addListener((msg, enabled) => { if (msg === "request") { browser.permissions.request(permObj); } else if (msg === "verify_access") { verifyPermissions(enabled); browser.test.sendMessage("verified"); } else if (msg === "revoke") { browser.permissions.remove(permObj); } }); } let extension = ExtensionTestUtils.loadExtension({ background, manifest: { optional_permissions: OptionalPermissions, }, useAddonManager: "permanent", }); await extension.startup(); function addPermissions() { extension.sendMessage("request"); return extension.awaitMessage("added"); } function removePermissions() { extension.sendMessage("revoke"); return extension.awaitMessage("removed"); } function verifyPermissions(enabled) { extension.sendMessage("verify_access", enabled); return extension.awaitMessage("verified"); } await withHandlingUserInput(extension, async () => { await addPermissions(); await removePermissions(); await addPermissions(); }); // reset handlingUserInput for the restart extensionHandlers.delete(extension); // Verify access on restart await AddonTestUtils.promiseRestartManager(); await extension.awaitBackgroundStarted(); await verifyPermissions(true); await withHandlingUserInput(extension, async () => { await removePermissions(); }); // Add private browsing to be sure it doesn't come through. let permObj = { permissions: OptionalPermissions.concat("internal:privateBrowsingAllowed"), origins: [], }; // enable the permissions while the addon is running await ExtensionPermissions.add(extension.id, permObj, extension.extension); await extension.awaitMessage("added"); await verifyPermissions(true); // disable the permissions while the addon is running await ExtensionPermissions.remove(extension.id, permObj, extension.extension); await extension.awaitMessage("removed"); await verifyPermissions(false); // Add private browsing to test internal permission. If it slips through, // we would get an error for an additional added message. await ExtensionPermissions.add( extension.id, { permissions: ["internal:privateBrowsingAllowed"], origins: [] }, extension.extension ); // disable the addon and re-test revoking permissions. await withHandlingUserInput(extension, async () => { await addPermissions(); }); let addon = await AddonManager.getAddonByID(extension.id); await addon.disable(); await ExtensionPermissions.remove(extension.id, permObj); await addon.enable(); await extension.awaitStartup(); await verifyPermissions(false); let perms = await ExtensionPermissions.get(extension.id); equal(perms.permissions.length, 0, "no permissions on startup"); await extension.unload(); }); add_task(async function test_geo_permissions() { async function background() { const permObj = { permissions: ["geolocation"] }; browser.test.onMessage.addListener(async msg => { if (msg === "request") { await browser.permissions.request(permObj); } else if (msg === "remove") { await browser.permissions.remove(permObj); } let result = await browser.permissions.contains(permObj); browser.test.sendMessage("done", result); }); } let extension = ExtensionTestUtils.loadExtension({ background, manifest: { browser_specific_settings: { gecko: { id: "geo-test@test" } }, optional_permissions: ["geolocation"], }, useAddonManager: "permanent", }); await extension.startup(); let policy = WebExtensionPolicy.getByID(extension.id); let principal = policy.extension.principal; equal( Services.perms.testPermissionFromPrincipal(principal, "geo"), Services.perms.UNKNOWN_ACTION, "geolocation not allowed on install" ); await withHandlingUserInput(extension, async () => { extension.sendMessage("request"); ok(await extension.awaitMessage("done"), "permission granted"); equal( Services.perms.testPermissionFromPrincipal(principal, "geo"), Services.perms.ALLOW_ACTION, "geolocation allowed after requested" ); extension.sendMessage("remove"); ok(!(await extension.awaitMessage("done")), "permission revoked"); equal( Services.perms.testPermissionFromPrincipal(principal, "geo"), Services.perms.UNKNOWN_ACTION, "geolocation not allowed after removed" ); // re-grant to test update removal extension.sendMessage("request"); ok(await extension.awaitMessage("done"), "permission granted"); equal( Services.perms.testPermissionFromPrincipal(principal, "geo"), Services.perms.ALLOW_ACTION, "geolocation allowed after re-requested" ); }); // We should not have geo permission after this upgrade. await extension.upgrade({ manifest: { browser_specific_settings: { gecko: { id: "geo-test@test" } }, }, useAddonManager: "permanent", }); equal( Services.perms.testPermissionFromPrincipal(principal, "geo"), Services.perms.UNKNOWN_ACTION, "geolocation not allowed after upgrade" ); await extension.unload(); }); add_task(async function test_browserSetting_permissions() { async function background() { const permObj = { permissions: ["browserSettings"] }; browser.test.onMessage.addListener(async msg => { if (msg === "request") { await browser.permissions.request(permObj); await browser.browserSettings.cacheEnabled.set({ value: false }); } else if (msg === "remove") { await browser.permissions.remove(permObj); } browser.test.sendMessage("done"); }); } function cacheIsEnabled() { return ( Services.prefs.getBoolPref("browser.cache.disk.enable") && Services.prefs.getBoolPref("browser.cache.memory.enable") ); } let extension = ExtensionTestUtils.loadExtension({ background, manifest: { optional_permissions: ["browserSettings"], }, useAddonManager: "permanent", }); await extension.startup(); ok(cacheIsEnabled(), "setting is not set after startup"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request"); await extension.awaitMessage("done"); ok(!cacheIsEnabled(), "setting was set after request"); extension.sendMessage("remove"); await extension.awaitMessage("done"); ok(cacheIsEnabled(), "setting is reset after remove"); extension.sendMessage("request"); await extension.awaitMessage("done"); ok(!cacheIsEnabled(), "setting was set after request"); }); await ExtensionPermissions._uninit(); extensionHandlers.delete(extension); await AddonTestUtils.promiseRestartManager(); await extension.awaitBackgroundStarted(); await withHandlingUserInput(extension, async () => { extension.sendMessage("remove"); await extension.awaitMessage("done"); ok(cacheIsEnabled(), "setting is reset after remove"); }); await extension.unload(); }); add_task(async function test_privacy_permissions() { async function background() { const permObj = { permissions: ["privacy"] }; browser.test.onMessage.addListener(async msg => { if (msg === "request") { await browser.permissions.request(permObj); await browser.privacy.websites.trackingProtectionMode.set({ value: "always", }); } else if (msg === "remove") { await browser.permissions.remove(permObj); } browser.test.sendMessage("done"); }); } function hasSetting() { return Services.prefs.getBoolPref("privacy.trackingprotection.enabled"); } let extension = ExtensionTestUtils.loadExtension({ background, manifest: { optional_permissions: ["privacy"], }, useAddonManager: "permanent", }); await extension.startup(); ok(!hasSetting(), "setting is not set after startup"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request"); await extension.awaitMessage("done"); ok(hasSetting(), "setting was set after request"); extension.sendMessage("remove"); await extension.awaitMessage("done"); ok(!hasSetting(), "setting is reset after remove"); extension.sendMessage("request"); await extension.awaitMessage("done"); ok(hasSetting(), "setting was set after request"); }); await ExtensionPermissions._uninit(); extensionHandlers.delete(extension); await AddonTestUtils.promiseRestartManager(); await extension.awaitBackgroundStarted(); await withHandlingUserInput(extension, async () => { extension.sendMessage("remove"); await extension.awaitMessage("done"); ok(!hasSetting(), "setting is reset after remove"); }); await extension.unload(); }); add_task( { pref_set: [["extensions.eventPages.enabled", true]] }, async function test_permissions_event_page() { let extension = ExtensionTestUtils.loadExtension({ useAddonManager: "permanent", manifest: { optional_permissions: ["privacy"], background: { persistent: false }, }, background() { browser.permissions.onAdded.addListener(details => { browser.test.sendMessage("added", details); }); browser.permissions.onRemoved.addListener(details => { browser.test.sendMessage("removed", details); }); }, }); await extension.startup(); let events = ["onAdded", "onRemoved"]; for (let event of events) { assertPersistentListeners(extension, "permissions", event, { primed: false, }); } await extension.terminateBackground(); for (let event of events) { assertPersistentListeners(extension, "permissions", event, { primed: true, }); } let permObj = { permissions: ["privacy"], origins: [], data_collection: [], }; // enable the permissions while the background is stopped await ExtensionPermissions.add( extension.id, // Prevent `permObj` from being mutated. { ...permObj }, extension.extension ); let details = await extension.awaitMessage("added"); Assert.deepEqual(permObj, details, "got added event"); // Restart and test that permission removal wakes the background. await AddonTestUtils.promiseRestartManager(); await extension.awaitStartup(); for (let event of events) { assertPersistentListeners(extension, "permissions", event, { primed: true, }); } // remove the permissions while the background is stopped await ExtensionPermissions.remove( extension.id, // Prevent `permObj` from being mutated. { ...permObj }, extension.extension ); details = await extension.awaitMessage("removed"); Assert.deepEqual(permObj, details, "got removed event"); await extension.unload(); } ); add_task( { pref_set: [ ["extensions.background.idle.timeout", 100], ["extensions.webextOptionalPermissionPrompts", true], ], }, async function test_permissions_request_idle_suspend() { info("Test that permissions.request() keeps bg page alive."); let pr = Glean.extensionsCounters.eventPageIdleResult.permissions_request; let before = pr.testGetValue() ?? 0; info(`Glean value permissions_request before: ${before}`); async function background() { browser.test.onMessage.addListener(async () => { browser.test.log("Calling permissions.request()."); await browser.permissions.request({ permissions: ["browserSettings"] }); browser.test.log("permissions.request() resolved."); browser.test.sendMessage("done"); }); } let extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 3, optional_permissions: ["browserSettings"], }, background, }); await extension.startup(); function obs(subject, _topic) { info("Waiting 200ms, normally the bg page would idle out."); // eslint-disable-next-line mozilla/no-arbitrary-setTimeout setTimeout(() => subject.wrappedJSObject.resolve(true), 200); } info("Setup permissions prompt observer."); Services.obs.addObserver(obs, "webextension-optional-permission-prompt"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request"); await extension.awaitMessage("done"); }); info("permissions.request() resolved successfully, bg page not suspended."); let count = pr.testGetValue() - before; // Because this "counter" measures time in increments of // background.idle.timeout, we know it should take at least 200ms, // but we need to leave slack of up to 500ms for slow test runs. ok(count >= 2 && count <= 5, `permissions_request counter: ${count}.`); Services.obs.removeObserver(obs, "webextension-optional-permission-prompt"); await extension.unload(); } ); add_task(async function test_getAll_with_data_collection() { async function background() { browser.test.onMessage.addListener(async msg => { browser.test.assertEq("getAll", msg, "expected correct message"); const permissions = await browser.permissions.getAll(); browser.test.sendMessage("all", permissions); }); browser.permissions.onAdded.addListener(details => { browser.test.sendMessage("added", details); }); browser.permissions.onRemoved.addListener(details => { browser.test.sendMessage("removed", details); }); browser.test.sendMessage("ready"); } const extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 3, permissions: ["bookmarks"], browser_specific_settings: { gecko: { data_collection_permissions: { // "none" shouldn't be added to the list of data collection // permissions returned by `getAll()`. required: ["none"], optional: ["technicalAndInteraction", "locationInfo"], }, }, }, }, background, }); await extension.startup(); await extension.awaitMessage("ready"); const getAllAndVerifyDataCollection = async expected => { extension.sendMessage("getAll"); const permissions = await extension.awaitMessage("all"); Assert.deepEqual( permissions, { permissions: ["bookmarks"], origins: [], data_collection: expected, }, "expected permissions with data collection" ); }; // Pretend the T&I permission was granted at install time. let perms = { permissions: [], origins: [], data_collection: ["technicalAndInteraction"], }; await ExtensionPermissions.add(extension.id, perms, extension.extension); let added = await extension.awaitMessage("added"); Assert.deepEqual( added, { permissions: [], origins: [], data_collection: ["technicalAndInteraction"], }, "expected new permissions granted" ); await getAllAndVerifyDataCollection(["technicalAndInteraction"]); // Grant another optional data collection permission. perms = { permissions: [], origins: [], data_collection: ["technicalAndInteraction", "locationInfo"], }; await ExtensionPermissions.add(extension.id, perms, extension.extension); added = await extension.awaitMessage("added"); Assert.deepEqual( added, { permissions: [], origins: [], data_collection: ["locationInfo"], }, "expected new permissions granted" ); await getAllAndVerifyDataCollection([ "technicalAndInteraction", "locationInfo", ]); // Revoke all optional data collection permissions. await ExtensionPermissions.remove(extension.id, perms, extension.extension); const removed = await extension.awaitMessage("removed"); Assert.deepEqual( removed, { permissions: [], origins: [], data_collection: ["technicalAndInteraction", "locationInfo"], }, "expected permissions revoked" ); await getAllAndVerifyDataCollection([]); await extension.unload(); }); add_task(async function test_getAll_with_required_data_collection() { async function background() { browser.test.onMessage.addListener(async msg => { browser.test.assertEq("getAll", msg, "expected correct message"); const permissions = await browser.permissions.getAll(); browser.test.sendMessage("all", permissions); }); browser.test.sendMessage("ready"); } const extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 3, permissions: ["bookmarks"], browser_specific_settings: { gecko: { data_collection_permissions: { required: ["bookmarksInfo"], optional: ["technicalAndInteraction", "locationInfo"], }, }, }, }, background, }); await extension.startup(); await extension.awaitMessage("ready"); extension.sendMessage("getAll"); let permissions = await extension.awaitMessage("all"); Assert.deepEqual( permissions, { permissions: ["bookmarks"], origins: [], data_collection: ["bookmarksInfo"], }, "expected permissions with required data collection" ); let perms = { permissions: [], origins: [], data_collection: ["technicalAndInteraction"], }; await ExtensionPermissions.add(extension.id, perms, extension.extension); extension.sendMessage("getAll"); permissions = await extension.awaitMessage("all"); Assert.deepEqual( permissions, { permissions: ["bookmarks"], origins: [], data_collection: ["bookmarksInfo", "technicalAndInteraction"], }, "expected permissions with newly added data collection" ); await extension.unload(); }); add_task(async function test_request_with_data_collection() { async function background() { browser.test.onMessage.addListener(async msg => { if (msg === "request-good") { await browser.permissions.request({ data_collection: ["technicalAndInteraction"], }); const permissions = await browser.permissions.getAll(); browser.test.sendMessage(`${msg}:done`, permissions); return; } if (msg === "request-invalid") { try { browser.permissions.request({ data_collection: ["invalid-permission"], }); browser.test.fail("expected error"); } catch (err) { browser.test.assertTrue( /Error processing data_collection.0: Value "invalid-permission" must either:/.test( err.message ), "expected error" ); } browser.test.sendMessage(`${msg}:done`); return; } if (msg === "request-bad") { await browser.test.assertRejects( browser.permissions.request({ data_collection: ["healthInfo"], }), /Cannot request data collection permission healthInfo since it was not declared in data_collection_permissions.optional/, "Expected rejection" ); browser.test.sendMessage(`${msg}:done`); return; } browser.test.fail(`Got unexpected msg "${msg}"`); }); browser.test.sendMessage("ready"); } const extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 2, browser_specific_settings: { gecko: { data_collection_permissions: { optional: ["technicalAndInteraction", "locationInfo"], }, }, }, }, background, }); await extension.startup(); await extension.awaitMessage("ready"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request-bad"); await extension.awaitMessage("request-bad:done"); }); await withHandlingUserInput(extension, async () => { extension.sendMessage("request-invalid"); await extension.awaitMessage("request-invalid:done"); }); let permissions; await withHandlingUserInput(extension, async () => { extension.sendMessage("request-good"); permissions = await extension.awaitMessage("request-good:done"); }); Assert.deepEqual( permissions, { permissions: [], origins: [], data_collection: ["technicalAndInteraction"], }, "expected permissions with data collection" ); // Reequest the same permission again, which should be already granted. await withHandlingUserInput(extension, async () => { extension.sendMessage("request-good"); permissions = await extension.awaitMessage("request-good:done"); }); Assert.deepEqual( permissions, { permissions: [], origins: [], data_collection: ["technicalAndInteraction"], }, "expected permissions with data collection" ); await extension.unload(); }); add_task(async function test_contains_data_collection() { async function background() { browser.test.onMessage.addListener(async (msg, arg) => { if (msg === "contains") { const result = await browser.permissions.contains(arg); browser.test.sendMessage(`${msg}:done`, result); return; } if (msg === "request") { await browser.permissions.request(arg); browser.test.sendMessage(`${msg}:done`); return; } if (msg === "remove") { await browser.permissions.remove(arg); browser.test.sendMessage(`${msg}:done`); return; } browser.test.fail(`Got unexpected msg "${msg}"`); }); browser.test.sendMessage("ready"); } const extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 2, optional_permissions: ["bookmarks", "http://*.mozilla.org/*"], browser_specific_settings: { gecko: { data_collection_permissions: { optional: ["technicalAndInteraction", "locationInfo"], }, }, }, }, background, }); await extension.startup(); await extension.awaitMessage("ready"); // A list of permission objects with various combination of api/data // collection permissions and origins. This will be used in different // assertions below. const PERMS = [ { permissions: ["bookmarks"] }, { origins: ["http://*.mozilla.org/*"] }, { permissions: ["bookmarks"], origins: ["http://*.mozilla.org/*"] }, { data_collection: ["technicalAndInteraction"] }, { data_collection: ["locationInfo"] }, { data_collection: ["technicalAndInteraction", "locationInfo"] }, { permissions: ["bookmarks"], data_collection: ["technicalAndInteraction", "locationInfo"], }, { permissions: ["bookmarks"], data_collection: ["locationInfo"], }, { permissions: ["bookmarks"], origins: ["http://*.mozilla.org/*"], data_collection: ["technicalAndInteraction", "locationInfo"], }, ]; let result; for (const perms of PERMS) { extension.sendMessage("contains", perms); result = await extension.awaitMessage("contains:done"); ok(!result, "Expected permission to not be granted"); } info("request a single data collection permission"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request", { data_collection: ["technicalAndInteraction"], }); await extension.awaitMessage("request:done"); }); extension.sendMessage("contains", { data_collection: ["technicalAndInteraction"], }); result = await extension.awaitMessage("contains:done"); ok(result, "Expected permission to be granted"); extension.sendMessage("contains", { permissions: ["bookmarks"], data_collection: ["technicalAndInteraction"], }); result = await extension.awaitMessage("contains:done"); ok(!result, "Expected false because bookmarks isn't granted"); info("request an API permission"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request", { permissions: ["bookmarks"], }); await extension.awaitMessage("request:done"); }); extension.sendMessage("contains", { permissions: ["bookmarks"], data_collection: ["technicalAndInteraction"], }); result = await extension.awaitMessage("contains:done"); ok(result, "Expected permissions to be granted"); extension.sendMessage("contains", { origins: ["http://*.mozilla.org/*"], data_collection: ["technicalAndInteraction"], }); result = await extension.awaitMessage("contains:done"); ok(!result, "Expected false because origin isn't granted"); info("remove data collection permission"); extension.sendMessage("remove", { data_collection: ["technicalAndInteraction"], }); await extension.awaitMessage("remove:done"); extension.sendMessage("contains", { data_collection: ["technicalAndInteraction"], }); result = await extension.awaitMessage("contains:done"); ok(!result, "Expected permission to not be granted"); info("request all optional permissions"); await withHandlingUserInput(extension, async () => { extension.sendMessage("request", { permissions: ["bookmarks"], origins: ["http://*.mozilla.org/*"], data_collection: ["technicalAndInteraction", "locationInfo"], }); await extension.awaitMessage("request:done"); }); for (const perms of PERMS) { extension.sendMessage("contains", perms); result = await extension.awaitMessage("contains:done"); ok(result, "Expected permission to be granted"); } info("remove all"); extension.sendMessage("remove", { permissions: ["bookmarks"], origins: ["http://*.mozilla.org/*"], data_collection: ["technicalAndInteraction", "locationInfo"], }); await extension.awaitMessage("remove:done"); for (const perms of PERMS) { extension.sendMessage("contains", perms); result = await extension.awaitMessage("contains:done"); ok(!result, "Expected permission to not be granted"); } await extension.unload(); }); // This test verifies that data collection permissions are taken into account when // an extension is installed before the `extensions.dataCollectionPermissions.enabled` // pref is enabled. add_task( { pref_set: [["extensions.dataCollectionPermissions.enabled", false]] }, async function test_database_updated_for_data_collection() { const extension = ExtensionTestUtils.loadExtension({ manifest: { manifest_version: 2, browser_specific_settings: { gecko: { id: "@updated-db-ext", data_collection_permissions: { required: ["locationInfo"], }, }, }, }, useAddonManager: "permanent", }); await extension.startup(); const addon = await AddonManager.getAddonByID(extension.id); ok(addon, "Expected add-on wrapper"); Assert.deepEqual( addon.userPermissions, { permissions: [], origins: [], data_collection: [] }, "Expected no permissions" ); // Flip the pref. let observePromise = TestUtils.topicObserved( "xpi-provider:database-updated" ); Services.prefs.setBoolPref( "extensions.dataCollectionPermissions.enabled", true ); await observePromise; Assert.deepEqual( addon.userPermissions, { permissions: [], origins: [], data_collection: ["locationInfo"] }, "Expected data collection permissions" ); // Flip the pref back to `false`. We do not rebuild the DB in this case. Services.prefs.setBoolPref( "extensions.dataCollectionPermissions.enabled", false ); Assert.deepEqual( addon.userPermissions, { permissions: [], origins: [], data_collection: ["locationInfo"] }, "Expected data collection permissions" ); await extension.unload(); } );