summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js')
-rw-r--r--toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js721
1 files changed, 721 insertions, 0 deletions
diff --git a/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js b/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
new file mode 100644
index 0000000000..cd51e7bdee
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
@@ -0,0 +1,721 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests to ensure that we correctly switch and update engines when
+ * adding and removing application provided engines which overlap
+ * with engines in the override allow list.
+ */
+
+"use strict";
+
+const SEARCH_URL_BASE = "https://example.com/";
+const SEARCH_URL_PARAMS = `?sourceId=enterprise&q={searchTerms}`;
+const ENGINE_NAME = "Simple Engine";
+
+const ALLOWLIST = [
+ {
+ thirdPartyId: "simpleengine@tests.mozilla.org",
+ overridesId: "simple@search.mozilla.org",
+ urls: [
+ { search_url: SEARCH_URL_BASE, search_url_get_params: SEARCH_URL_PARAMS },
+ ],
+ },
+ {
+ thirdPartyId: "opensearch@search.mozilla.org",
+ engineName: ENGINE_NAME,
+ overridesId: "simple@search.mozilla.org",
+ urls: [
+ { search_url: SEARCH_URL_BASE, search_url_get_params: SEARCH_URL_PARAMS },
+ ],
+ },
+];
+
+const CONFIG_SIMPLE_LOCALE_DE = [
+ {
+ webExtension: {
+ id: "basic@search.mozilla.org",
+ name: "basic",
+ search_url:
+ "https://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB",
+ params: [
+ {
+ name: "search",
+ value: "{searchTerms}",
+ },
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ },
+ appliesTo: [
+ {
+ included: { everywhere: true },
+ default: "yes",
+ },
+ ],
+ },
+ {
+ webExtension: {
+ id: "simple@search.mozilla.org",
+ name: "Simple Engine",
+ search_url: "https://example.com",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ {
+ name: "search",
+ value: "{searchTerms}",
+ },
+ ],
+ },
+ appliesTo: [
+ {
+ included: { locales: { matches: ["de"] } },
+ default: "no",
+ },
+ ],
+ },
+];
+
+const CONFIG_SIMPLE_LOCALE_DE_V2 = [
+ {
+ recordType: "engine",
+ identifier: "basic",
+ base: {
+ name: "basic",
+ urls: {
+ search: {
+ base: "https://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ searchTermParamName: "search",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "simple",
+ base: {
+ name: "Simple Engine",
+ urls: {
+ search: {
+ base: "https://example.com",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ searchTermParamName: "search",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { locales: ["de"] },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "basic",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
+const CONFIG_SIMPLE_EVERYWHERE = [
+ {
+ webExtension: {
+ id: "basic@search.mozilla.org",
+ name: "basic",
+ search_url:
+ "https://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB",
+ params: [
+ {
+ name: "search",
+ value: "{searchTerms}",
+ },
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ },
+ appliesTo: [
+ {
+ included: { everywhere: true },
+ default: "yes",
+ },
+ ],
+ },
+ {
+ webExtension: {
+ id: "simple@search.mozilla.org",
+ name: "Simple Engine",
+ search_url: "https://example.com",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ {
+ name: "search",
+ value: "{searchTerms}",
+ },
+ ],
+ },
+ appliesTo: [
+ {
+ included: { everywhere: true },
+ default: "no",
+ },
+ ],
+ },
+];
+
+const CONFIG_SIMPLE_EVERYWHERE_V2 = [
+ {
+ recordType: "engine",
+ identifier: "basic",
+ base: {
+ name: "basic",
+ urls: {
+ search: {
+ base: "https://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ searchTermParamName: "search",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "simple",
+ base: {
+ name: "Simple Engine",
+ urls: {
+ search: {
+ base: "https://example.com",
+ params: [
+ {
+ name: "sourceId",
+ value: "Mozilla-search",
+ },
+ ],
+ searchTermParamName: "search",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "basic",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
+let lastEngineId;
+let extension;
+let configStub;
+let notificationBoxStub;
+
+add_setup(async function () {
+ let server = useHttpServer();
+ server.registerContentType("sjs", "sjs");
+ SearchTestUtils.useMockIdleService();
+ configStub = await SearchTestUtils.useTestEngines("simple-engines");
+ Services.locale.availableLocales = [
+ ...Services.locale.availableLocales,
+ "en",
+ "de",
+ ];
+ Services.locale.requestedLocales = ["en"];
+
+ await AddonTestUtils.promiseStartupManager();
+ await Services.search.init();
+
+ const settings = await RemoteSettings(SearchUtils.SETTINGS_ALLOWLIST_KEY);
+ sinon.stub(settings, "get").returns(ALLOWLIST);
+
+ notificationBoxStub = sinon.stub(
+ Services.search.wrappedJSObject,
+ "_showRemovalOfSearchEngineNotificationBox"
+ );
+
+ consoleAllowList.push("Failed to load");
+});
+
+/**
+ * Tests that overrides are correctly applied when the deployment of the app
+ * provided engine is extended into an area, or removed from an area, where a
+ * user has the WebExtension installed and set as default.
+ */
+add_task(async function test_app_provided_engine_deployment_extended() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info("Change configuration to include engine in user's environment");
+
+ await SearchTestUtils.updateRemoteSettingsConfig(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ });
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info("Change configuration to remove engine from user's environment");
+
+ await SearchTestUtils.updateRemoteSettingsConfig(CONFIG_SIMPLE_LOCALE_DE);
+ configStub.returns(CONFIG_SIMPLE_LOCALE_DE);
+ });
+});
+
+/**
+ * Tests that overrides are correctly applied when the deployment of the app
+ * provided engine is extended into an area, or removed from an area, where a
+ * user has the OpenSearch engine installed and set as default.
+ */
+add_task(
+ async function test_app_provided_engine_deployment_extended_opensearch() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info("Change configuration to include engine in user's environment");
+
+ await SearchTestUtils.updateRemoteSettingsConfig(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ }, true);
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info("Change configuration to remove engine from user's environment");
+
+ await SearchTestUtils.updateRemoteSettingsConfig(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ }, true);
+ }
+);
+
+add_task(
+ async function test_app_provided_engine_deployment_extended_restart_only() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info(
+ "Change configuration with restart to include engine in user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+ });
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info(
+ "Change configuration with restart to remove engine from user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+ // Ensure settings have been saved before the engines are added, so that
+ // we know we won't have race conditions when `addEnginesFromExtension`
+ // loads the settings itself.
+ await promiseAfterSettings();
+
+ // Simulate the add-on manager starting up and telling the
+ // search service about the add-on again.
+ let extensionData = {
+ ...extension.extension,
+ startupReason: "APP_STARTUP",
+ };
+ await Services.search.addEnginesFromExtension(extensionData);
+ });
+
+ let settingsData = await promiseSettingsData();
+ Assert.ok(
+ settingsData.engines.every(e => !e._metaData.overriddenBy),
+ "Should have cleared the overridden by flag after removal"
+ );
+ }
+);
+
+add_task(
+ async function test_app_provided_engine_deployment_extended_restart_only_startup_extension() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info(
+ "Change configuration with restart to include engine in user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+ });
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info(
+ "Change configuration with restart to remove engine from user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ // Simulate the add-on manager starting up and telling the
+ // search service about the add-on again.
+ //
+ // In this test, it does this before init() is called, to
+ // simulate this being a startup extension.
+ let extensionData = {
+ ...extension.extension,
+ startupReason: "APP_STARTUP",
+ };
+ await Services.search.addEnginesFromExtension(extensionData);
+
+ await Services.search.init();
+ });
+
+ let settingsData = await promiseSettingsData();
+ Assert.ok(
+ settingsData.engines.every(e => !e._metaData.overriddenBy),
+ "Should have cleared the overridden by flag after removal"
+ );
+ }
+);
+
+add_task(
+ async function test_app_provided_engine_deployment_extended_opensearch_restart_only() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info(
+ "Change configuration with restart to include engine in user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_EVERYWHERE_V2
+ : CONFIG_SIMPLE_EVERYWHERE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+ }, true);
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info(
+ "Change configuration with restart to remove engine from user's environment"
+ );
+
+ configStub.returns(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+ }, true);
+
+ let settingsData = await promiseSettingsData();
+ Assert.ok(
+ settingsData.engines.every(e => !e._metaData.overriddenBy),
+ "Should have cleared the overridden by flag after removal"
+ );
+ }
+);
+
+/**
+ * Tests that overrides are correctly applied when the user's environment changes
+ * e.g. they have the WebExtension installed and change to a locale where the
+ * application provided engine is (or is not) available.
+ */
+add_task(async function test_user_environment_changes() {
+ await assertCorrectlySwitchedWhenExtended(async () => {
+ info("Change locale to de");
+
+ await promiseSetLocale("de");
+ });
+
+ await assertCorrectlySwitchedWhenRemoved(async () => {
+ info("Change locale to en");
+
+ await promiseSetLocale("en");
+ });
+});
+
+/**
+ * Asserts that overrides are handled correctly when a WebExtension is
+ * installed, and an application provided engine is added for the user.
+ *
+ * This is designed to be used prior to assertCorrectlySwitchedWhenRemoved.
+ *
+ * @param {Function} changeFn
+ * A function that applies the change to cause the application provided
+ * engine to be added for the user.
+ * @param {boolean} testOpenSearch
+ * Set to true to test OpenSearch based engines.
+ */
+async function assertCorrectlySwitchedWhenExtended(
+ changeFn,
+ testOpenSearch = false
+) {
+ await SearchTestUtils.updateRemoteSettingsConfig(
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_SIMPLE_LOCALE_DE_V2
+ : CONFIG_SIMPLE_LOCALE_DE
+ );
+ notificationBoxStub.resetHistory();
+
+ info(
+ `Install ${
+ testOpenSearch ? "OpenSearch" : "WebExtension"
+ } based engine and set as default`
+ );
+
+ let engine;
+ if (testOpenSearch) {
+ engine = await SearchTestUtils.promiseNewSearchEngine({
+ url: `${gDataUrl}engineMaker.sjs?${JSON.stringify({
+ baseURL: SEARCH_URL_BASE,
+ queryString: SEARCH_URL_PARAMS,
+ name: ENGINE_NAME,
+ method: "GET",
+ })}`,
+ });
+ } else {
+ extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: ENGINE_NAME,
+ search_url: SEARCH_URL_BASE,
+ search_url_get_params: SEARCH_URL_PARAMS,
+ },
+ { skipUnload: true }
+ );
+ await extension.awaitStartup();
+
+ engine = Services.search.getEngineById(
+ "simpleengine@tests.mozilla.orgdefault"
+ );
+ }
+
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+
+ // Set a user defined alias.
+ engine.alias = "star";
+
+ await assertEngineCorrectlySet({
+ expectedId: engine.id,
+ expectedAlias: "star",
+ appEngineOverriden: false,
+ });
+
+ await changeFn();
+
+ await assertEngineCorrectlySet({
+ expectedId: "simple@search.mozilla.orgdefault",
+ expectedAlias: "star",
+ appEngineOverriden: true,
+ });
+ Assert.ok(
+ notificationBoxStub.notCalled,
+ "Should not have attempted to display a notification box"
+ );
+
+ info("Test restarting search service ensure settings are kept.");
+
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+
+ if (!testOpenSearch) {
+ let extensionData = {
+ ...extension.extension,
+ startupReason: "APP_STARTUP",
+ };
+ await Services.search.maybeSetAndOverrideDefault(extensionData);
+ }
+
+ Assert.ok(
+ notificationBoxStub.notCalled,
+ "Should not have attempted to display a notification box"
+ );
+ await assertEngineCorrectlySet({
+ expectedId: "simple@search.mozilla.orgdefault",
+ expectedAlias: "star",
+ appEngineOverriden: true,
+ });
+
+ // Save lastEngineId for use in assertCorrectlySwitchedWhenRemoved.
+ lastEngineId = engine.id;
+}
+
+/**
+ * Asserts that overrides are handled correctly when a WebExtension is
+ * installed and overriding an application provided engine, and then the
+ * application provided engine is removed from the user.
+ *
+ * This is designed to be used after to assertCorrectlySwitchedWhenExtended.
+ *
+ * @param {Function} changeFn
+ * A function that applies the change to cause the application provided
+ * engine to be removed for the user.
+ * @param {boolean} testOpenSearch
+ * Set to true to test OpenSearch based engines.
+ */
+async function assertCorrectlySwitchedWhenRemoved(
+ changeFn,
+ testOpenSearch = false
+) {
+ notificationBoxStub.resetHistory();
+
+ await changeFn();
+
+ await assertEngineCorrectlySet({
+ expectedId: lastEngineId,
+ expectedAlias: "star",
+ appEngineOverriden: false,
+ });
+
+ info("Test restarting search service to remove application provided engine");
+
+ await promiseAfterSettings();
+ Services.search.wrappedJSObject.reset();
+
+ if (!testOpenSearch) {
+ let extensionData = {
+ ...extension.extension,
+ startupReason: "APP_STARTUP",
+ };
+ await Services.search.addEnginesFromExtension(extensionData);
+ }
+
+ await Services.search.init();
+
+ await assertEngineCorrectlySet({
+ expectedId: lastEngineId,
+ expectedAlias: "star",
+ appEngineOverriden: false,
+ });
+
+ if (testOpenSearch) {
+ await Services.search.removeEngine(
+ Services.search.getEngineById(lastEngineId)
+ );
+ } else {
+ await extension.unload();
+ }
+}
+
+async function assertEngineCorrectlySet({
+ expectedAlias = "",
+ expectedId,
+ appEngineOverriden,
+}) {
+ let engines = await Services.search.getEngines();
+ Assert.equal(
+ engines.filter(e => e.name == ENGINE_NAME).length,
+ 1,
+ "Should only be one engine with matching name after changing configuration"
+ );
+
+ let defaultEngine = await Services.search.getDefault();
+ Assert.equal(
+ defaultEngine.id,
+ expectedId,
+ "Should have kept the third party engine as default"
+ );
+ Assert.equal(
+ decodeURI(defaultEngine.getSubmission("{searchTerms}").uri.spec),
+ SEARCH_URL_BASE + SEARCH_URL_PARAMS,
+ "Should have used the third party engine's URLs"
+ );
+ Assert.equal(
+ !!defaultEngine.wrappedJSObject.getAttr("overriddenBy"),
+ appEngineOverriden,
+ "Should have correctly overridden or not."
+ );
+
+ Assert.equal(
+ defaultEngine.telemetryId,
+ appEngineOverriden ? "simple-addon" : "other-Simple Engine",
+ "Should set the correct telemetry Id"
+ );
+
+ Assert.equal(
+ defaultEngine.alias,
+ expectedAlias,
+ "Should have the correct alias"
+ );
+}