summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/search')
-rw-r--r--toolkit/components/search/AppProvidedSearchEngine.sys.mjs185
-rw-r--r--toolkit/components/search/SearchEngine.sys.mjs4
-rw-r--r--toolkit/components/search/SearchService.sys.mjs207
-rw-r--r--toolkit/components/search/SearchSuggestionController.sys.mjs4
-rw-r--r--toolkit/components/search/SearchUtils.sys.mjs4
-rw-r--r--toolkit/components/search/nsISearchService.idl2
-rw-r--r--toolkit/components/search/schema/search-config-overrides-ui-schema.json3
-rw-r--r--toolkit/components/search/schema/search-config-overrides-v2-schema.json1
-rw-r--r--toolkit/components/search/schema/search-config-overrides-v2-ui-schema.json9
-rw-r--r--toolkit/components/search/schema/search-default-override-allowlist-ui-schema.json2
-rw-r--r--toolkit/components/search/tests/SearchTestUtils.sys.mjs10
-rw-r--r--toolkit/components/search/tests/xpcshell/data/search-config-v2-no-order-hint.json207
-rw-r--r--toolkit/components/search/tests/xpcshell/data/search-config-v2.json223
-rw-r--r--toolkit/components/search/tests/xpcshell/method-extensions/search-config-v2.json83
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_ui_schemas_valid.js36
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_validates.js191
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/test_searchicons_validates.js20
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml16
-rw-r--r--toolkit/components/search/tests/xpcshell/test-extensions/search-config-v2.json139
-rw-r--r--toolkit/components/search/tests/xpcshell/test_appProvided_icons.js211
-rw-r--r--toolkit/components/search/tests/xpcshell/test_defaultPrivateEngine.js4
-rw-r--r--toolkit/components/search/tests/xpcshell/test_engine_ids.js49
-rw-r--r--toolkit/components/search/tests/xpcshell/test_engine_set_alias.js2
-rw-r--r--toolkit/components/search/tests/xpcshell/test_getSubmission_params_pref.js9
-rw-r--r--toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus.js17
-rw-r--r--toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus_invalid.js5
-rw-r--r--toolkit/components/search/tests/xpcshell/test_initialization.js51
-rw-r--r--toolkit/components/search/tests/xpcshell/test_initialization_with_region.js87
-rw-r--r--toolkit/components/search/tests/xpcshell/test_maybereloadengine_order.js54
-rw-r--r--toolkit/components/search/tests/xpcshell/test_missing_engine.js52
-rw-r--r--toolkit/components/search/tests/xpcshell/test_opensearch_icon.js18
-rw-r--r--toolkit/components/search/tests/xpcshell/test_opensearch_icons_invalid.js6
-rw-r--r--toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js12
-rw-r--r--toolkit/components/search/tests/xpcshell/test_reload_engines.js322
-rw-r--r--toolkit/components/search/tests/xpcshell/test_reload_engines_experiment.js126
-rw-r--r--toolkit/components/search/tests/xpcshell/test_reload_engines_locales.js93
-rw-r--r--toolkit/components/search/tests/xpcshell/test_remove_engine_notification_box.js112
-rw-r--r--toolkit/components/search/tests/xpcshell/test_searchSuggest.js2
-rw-r--r--toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js2
-rw-r--r--toolkit/components/search/tests/xpcshell/test_searchSuggest_extraParams.js56
-rw-r--r--toolkit/components/search/tests/xpcshell/test_searchTermFromResult.js169
-rw-r--r--toolkit/components/search/tests/xpcshell/test_settings_persist.js62
-rw-r--r--toolkit/components/search/tests/xpcshell/test_sort_orders-no-hints.js8
-rw-r--r--toolkit/components/search/tests/xpcshell/test_telemetry_event_default.js206
-rw-r--r--toolkit/components/search/tests/xpcshell/test_validate_engines.js56
-rw-r--r--toolkit/components/search/tests/xpcshell/test_webextensions_install.js22
-rw-r--r--toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js6
-rw-r--r--toolkit/components/search/tests/xpcshell/xpcshell.toml13
48 files changed, 2681 insertions, 497 deletions
diff --git a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
index a8db801ac4..7401ba115c 100644
--- a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
+++ b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
@@ -12,10 +12,95 @@ import {
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
+ RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs",
});
/**
+ * Handles loading application provided search engine icons from remote settings.
+ */
+class IconHandler {
+ #iconList = null;
+ #iconCollection = null;
+
+ /**
+ * Returns the icon for the record that matches the engine identifier
+ * and the preferred width.
+ *
+ * @param {string} engineIdentifier
+ * The identifier of the engine to match against.
+ * @param {number} preferredWidth
+ * The preferred with of the icon.
+ * @returns {string}
+ * An object URL that can be used to reference the contents of the specified
+ * source object.
+ */
+ async getIcon(engineIdentifier, preferredWidth) {
+ if (!this.#iconList) {
+ await this.#getIconList();
+ }
+
+ let iconRecords = this.#iconList.filter(r => {
+ return r.engineIdentifiers.some(i => {
+ if (i.endsWith("*")) {
+ return engineIdentifier.startsWith(i.slice(0, -1));
+ }
+ return engineIdentifier == i;
+ });
+ });
+
+ if (!iconRecords.length) {
+ console.warn("No icon found for", engineIdentifier);
+ return null;
+ }
+
+ // Default to the first record, in the event we don't have any records
+ // that match the width.
+ let iconRecord = iconRecords[0];
+ for (let record of iconRecords) {
+ // TODO: Bug 1655070. We should be using the closest size, but for now use
+ // an exact match.
+ if (record.imageSize == preferredWidth) {
+ iconRecord = record;
+ break;
+ }
+ }
+
+ let iconURL;
+ try {
+ iconURL = await this.#iconCollection.attachments.get(iconRecord);
+ } catch (ex) {
+ console.error(ex);
+ return null;
+ }
+ if (!iconURL) {
+ console.warn("Unable to find the icon for", engineIdentifier);
+ return null;
+ }
+ return URL.createObjectURL(
+ new Blob([iconURL.buffer]),
+ iconRecord.attachment.mimetype
+ );
+ }
+
+ /**
+ * Obtains the icon list from the remote settings collection.
+ */
+ async #getIconList() {
+ this.#iconCollection = lazy.RemoteSettings("search-config-icons");
+ try {
+ this.#iconList = await this.#iconCollection.get();
+ } catch (ex) {
+ console.error(ex);
+ this.#iconList = [];
+ }
+ if (!this.#iconList.length) {
+ console.error("Failed to obtain search engine icon list records");
+ }
+ }
+}
+
+/**
* AppProvidedSearchEngine represents a search engine defined by the
* search configuration.
*/
@@ -25,6 +110,20 @@ export class AppProvidedSearchEngine extends SearchEngine {
["suggestions", lazy.SearchUtils.URL_TYPE.SUGGEST_JSON],
["trending", lazy.SearchUtils.URL_TYPE.TRENDING_JSON],
]);
+ static iconHandler = new IconHandler();
+
+ /**
+ * @typedef {?Promise<string>}
+ * A promise for the blob URL of the icon. We save the promise to avoid
+ * reentrancy issues.
+ */
+ #blobURLPromise = null;
+
+ /**
+ * @typedef {?string}
+ * The identifier from the configuration.
+ */
+ #configurationId = null;
/**
* @param {object} options
@@ -51,26 +150,35 @@ export class AppProvidedSearchEngine extends SearchEngine {
this._extensionID = extensionId;
this._locale = config.webExtension.locale;
+ this.#configurationId = config.identifier;
this.#init(config);
this._loadSettings(settings);
}
/**
+ * Used to clean up the engine when it is removed. This will revoke the blob
+ * URL for the icon.
+ */
+ async cleanup() {
+ if (this.#blobURLPromise) {
+ URL.revokeObjectURL(await this.#blobURLPromise);
+ this.#blobURLPromise = null;
+ }
+ }
+
+ /**
* Update this engine based on new config, used during
* config upgrades.
* @param {object} options
* The options object.
*
- * @param {object} options.locale
- * The locale that is being used for the engine.
* @param {object} options.configuration
* The search engine configuration for application provided engines.
*/
- update({ locale, configuration } = {}) {
+ update({ configuration } = {}) {
this._urls = [];
- this._iconMapObj = null;
this.#init(configuration);
lazy.SearchUtils.notifyAction(this, lazy.SearchUtils.MODIFIED_TYPE.CHANGED);
}
@@ -89,24 +197,10 @@ export class AppProvidedSearchEngine extends SearchEngine {
* Returns true if the engine was updated, false otherwise.
*/
async updateIfNoNameChange({ configuration, locale }) {
- let newName;
- if (locale != "default") {
- newName = configuration.webExtension.searchProvider[locale].name;
- } else if (
- locale == "default" &&
- configuration.webExtension.default_locale
- ) {
- newName =
- configuration.webExtension.searchProvider[
- configuration.webExtension.default_locale
- ].name;
- } else {
- newName = configuration.webExtension.name;
- }
-
- if (this.name != newName.trim()) {
+ if (this.name != configuration.name.trim()) {
return false;
}
+
this.update({ locale, configuration });
return true;
}
@@ -145,6 +239,25 @@ export class AppProvidedSearchEngine extends SearchEngine {
}
/**
+ * Returns the icon URL for the search engine closest to the preferred width.
+ *
+ * @param {number} preferredWidth
+ * The preferred width of the image.
+ * @returns {Promise<string>}
+ * A promise that resolves to the URL of the icon.
+ */
+ async getIconURL(preferredWidth) {
+ if (this.#blobURLPromise) {
+ return this.#blobURLPromise;
+ }
+ this.#blobURLPromise = AppProvidedSearchEngine.iconHandler.getIcon(
+ this.#configurationId,
+ preferredWidth
+ );
+ return this.#blobURLPromise;
+ }
+
+ /**
* Creates a JavaScript object that represents this engine.
*
* @returns {object}
@@ -175,38 +288,6 @@ export class AppProvidedSearchEngine extends SearchEngine {
this._telemetryId += `-${engineConfig.telemetrySuffix}`;
}
- // Set the main icon URL for the engine.
- // let iconURL = searchProvider.favicon_url;
-
- // if (!iconURL) {
- // iconURL =
- // manifest.icons &&
- // extensionBaseURI.resolve(
- // lazy.ExtensionParent.IconDetails.getPreferredIcon(manifest.icons).icon
- // );
- // }
-
- // // Record other icons that the WebExtension has.
- // if (manifest.icons) {
- // let iconList = Object.entries(manifest.icons).map(icon => {
- // return {
- // width: icon[0],
- // height: icon[0],
- // url: extensionBaseURI.resolve(icon[1]),
- // };
- // });
- // for (let icon of iconList) {
- // this._addIconToMap(icon.size, icon.size, icon.url);
- // }
- // }
-
- // this._initWithDetails(config);
-
- // this._sendAttributionRequest = config.sendAttributionRequest ?? false; // TODO check if we need to this?
- // if (details.iconURL) {
- // this._setIcon(details.iconURL, true);
- // }
-
this._name = engineConfig.name.trim();
this._definedAliases =
engineConfig.aliases?.map(alias => `@${alias}`) ?? [];
diff --git a/toolkit/components/search/SearchEngine.sys.mjs b/toolkit/components/search/SearchEngine.sys.mjs
index a043c7d4ca..832ffbe2d0 100644
--- a/toolkit/components/search/SearchEngine.sys.mjs
+++ b/toolkit/components/search/SearchEngine.sys.mjs
@@ -1685,9 +1685,9 @@ export class SearchEngine {
* @param {number} preferredWidth
* Width of the requested icon. If not specified, it is assumed that
* 16x16 is desired.
- * @returns {string|undefined}
+ * @returns {Promise<string|undefined>}
*/
- getIconURL(preferredWidth) {
+ async getIconURL(preferredWidth) {
// XPCOM interfaces pass optional number parameters as 0 and can't be
// handled in the same way.
if (!preferredWidth) {
diff --git a/toolkit/components/search/SearchService.sys.mjs b/toolkit/components/search/SearchService.sys.mjs
index 4e1a99671f..b9de8e0bb3 100644
--- a/toolkit/components/search/SearchService.sys.mjs
+++ b/toolkit/components/search/SearchService.sys.mjs
@@ -69,6 +69,18 @@ export const NON_SPLIT_ENGINE_IDS = [
"wolnelektury-pl",
"yahoo-jp",
"yahoo-jp-auctions",
+ // below are test engines
+ "engine-pref",
+ "engine-rel-searchform-purpose",
+ "engine-chromeicon",
+ "engine-resourceicon",
+ "engine-resourceicon-gd",
+ "engine-reordered",
+ "engine-same-name",
+ "engine-same-name-gd",
+ "engine-purpose",
+ "engine-fr",
+ "fixup_search",
];
const TOPIC_LOCALES_CHANGE = "intl:app-locales-changed";
@@ -627,7 +639,6 @@ export class SearchService {
* An Extension object containing data about the extension.
*/
async addEnginesFromExtension(extension) {
- lazy.logConsole.debug("addEnginesFromExtension: " + extension.id);
// Treat add-on upgrade and downgrades the same - either way, the search
// engine gets updated, not added. Generally, we don't expect a downgrade,
// but just in case...
@@ -640,7 +651,7 @@ export class SearchService {
// In either case, there will not be an existing engine.
let existing = await this.#upgradeExtensionEngine(extension);
if (existing?.length) {
- return existing;
+ return;
}
}
@@ -653,28 +664,32 @@ export class SearchService {
let { engines } = await this._fetchEngineSelectorEngines();
let inConfig = engines.filter(el => el.webExtension.id == extension.id);
if (inConfig.length) {
- return this.#installExtensionEngine(
+ await this.#installExtensionEngine(
extension,
inConfig.map(el => el.webExtension.locale)
);
+ return;
}
}
lazy.logConsole.debug(
- "addEnginesFromExtension: Ignoring builtIn engine."
+ "addEnginesFromExtension: Ignoring app engine during init or reload:",
+ extension.id
);
- return [];
+ return;
}
+ lazy.logConsole.debug("addEnginesFromExtension:", extension.id);
// If we havent started SearchService yet, store this extension
// to install in SearchService.init().
if (!this.isInitialized) {
this.#startupExtensions.add(extension);
- return [];
+ return;
}
- return this.#installExtensionEngine(extension, [
- lazy.SearchUtils.DEFAULT_TAG,
- ]);
+ await this.#createAndAddAddonEngine({
+ extension,
+ locale: lazy.SearchUtils.DEFAULT_TAG,
+ });
}
async addOpenSearchEngine(engineURL, iconURL) {
@@ -1082,7 +1097,7 @@ export class SearchService {
/**
* A Set of installed search extensions reported by AddonManager
* startup before SearchSevice has started. Will be installed
- * during init().
+ * during init(). Does not contain application provided engines.
*
* @type {Set<object>}
*/
@@ -1800,21 +1815,21 @@ export class SearchService {
}
lazy.logConsole.debug(
- "#loadEngines: loading",
+ "#loadStartupEngines: loading",
this.#startupExtensions.size,
"engines reported by AddonManager startup"
);
for (let extension of this.#startupExtensions) {
try {
- await this.#installExtensionEngine(
+ await this.#createAndAddAddonEngine({
extension,
- [lazy.SearchUtils.DEFAULT_TAG],
+ locale: lazy.SearchUtils.DEFAULT_TAG,
settings,
- true
- );
+ initEngine: true,
+ });
} catch (ex) {
lazy.logConsole.error(
- `#installExtensionEngine failed for ${extension.id}`,
+ `#createAndAddAddonEngine failed for ${extension.id}`,
ex
);
}
@@ -2196,60 +2211,7 @@ export class SearchService {
// Finally, remove any engines that need removing. We do this after sorting
// out the new default, as otherwise this could cause multiple notifications
// and the wrong engine to be selected as default.
-
- for (let engine of this._engines.values()) {
- if (!engine.pendingRemoval) {
- continue;
- }
-
- // If we have other engines that use the same extension ID, then
- // we do not want to remove the add-on - only remove the engine itself.
- let inUseEngines = [...this._engines.values()].filter(
- e => e._extensionID == engine._extensionID
- );
-
- if (inUseEngines.length <= 1) {
- if (inUseEngines.length == 1 && inUseEngines[0] == engine) {
- // No other engines are using this extension ID.
-
- // The internal remove is done first to avoid a call to removeEngine
- // which could adjust the sort order when we don't want it to.
- this.#internalRemoveEngine(engine);
-
- // Only uninstall application provided engines. We don't want to
- // remove third-party add-ons. Their search engine names might conflict,
- // but we still allow the add-on to be installed.
- if (engine.isAppProvided) {
- let addon = await lazy.AddonManager.getAddonByID(
- engine._extensionID
- );
- if (addon) {
- // AddonManager won't call removeEngine if an engine with the
- // WebExtension id doesn't exist in the search service.
- await addon.uninstall();
- }
- }
- }
- // For the case where `inUseEngines[0] != engine`:
- // This is a situation where there was an engine added earlier in this
- // function with the same name.
- // For example, eBay has the same name for both US and GB, but has
- // a different domain and uses a different locale of the same
- // WebExtension.
- // The result of this is the earlier addition has already replaced
- // the engine in `this._engines` (which is indexed by name), so all that
- // needs to be done here is to pretend the old engine was removed
- // which is notified below.
- } else {
- // More than one engine is using this extension ID, so we don't want to
- // remove the add-on.
- this.#internalRemoveEngine(engine);
- }
- lazy.SearchUtils.notifyAction(
- engine,
- lazy.SearchUtils.MODIFIED_TYPE.REMOVED
- );
- }
+ await this.#maybeRemoveEnginesAfterReload(this._engines);
// Save app default engine to the user's settings metaData incase it has
// been updated
@@ -2343,6 +2305,78 @@ export class SearchService {
return true;
}
+ /**
+ * Remove any engines that have been flagged for removal during reloadEngines.
+ *
+ * @param {SearchEngine[]} engines
+ * The list of engines to check.
+ */
+ async #maybeRemoveEnginesAfterReload(engines) {
+ for (let engine of engines.values()) {
+ if (!engine.pendingRemoval) {
+ continue;
+ }
+
+ if (lazy.SearchUtils.newSearchConfigEnabled) {
+ // Use the internal remove - _reloadEngines already deals with default
+ // engines etc, and we want to avoid adjusting the sort order unnecessarily.
+ this.#internalRemoveEngine(engine);
+
+ if (engine instanceof lazy.AppProvidedSearchEngine) {
+ await engine.cleanup();
+ }
+ } else {
+ // If we have other engines that use the same extension ID, then
+ // we do not want to remove the add-on - only remove the engine itself.
+ let inUseEngines = [...this._engines.values()].filter(
+ e => e._extensionID == engine._extensionID
+ );
+
+ if (inUseEngines.length <= 1) {
+ if (inUseEngines.length == 1 && inUseEngines[0] == engine) {
+ // No other engines are using this extension ID.
+
+ // The internal remove is done first to avoid a call to removeEngine
+ // which could adjust the sort order when we don't want it to.
+ this.#internalRemoveEngine(engine);
+
+ // Only uninstall application provided engines. We don't want to
+ // remove third-party add-ons. Their search engine names might conflict,
+ // but we still allow the add-on to be installed.
+ if (engine.isAppProvided) {
+ let addon = await lazy.AddonManager.getAddonByID(
+ engine._extensionID
+ );
+ if (addon) {
+ // AddonManager won't call removeEngine if an engine with the
+ // WebExtension id doesn't exist in the search service.
+ await addon.uninstall();
+ }
+ }
+ }
+ // For the case where `inUseEngines[0] != engine`:
+ // This is a situation where there was an engine added earlier in this
+ // function with the same name.
+ // For example, eBay has the same name for both US and GB, but has
+ // a different domain and uses a different locale of the same
+ // WebExtension.
+ // The result of this is the earlier addition has already replaced
+ // the engine in `this._engines` (which is indexed by name), so all that
+ // needs to be done here is to pretend the old engine was removed
+ // which is notified below.
+ } else {
+ // More than one engine is using this extension ID, so we don't want to
+ // remove the add-on.
+ this.#internalRemoveEngine(engine);
+ }
+ }
+ lazy.SearchUtils.notifyAction(
+ engine,
+ lazy.SearchUtils.MODIFIED_TYPE.REMOVED
+ );
+ }
+ }
+
#addEngineToStore(engine, skipDuplicateCheck = false) {
if (this.#engineMatchesIgnoreLists(engine)) {
lazy.logConsole.debug("#addEngineToStore: Ignoring engine");
@@ -2885,7 +2919,7 @@ export class SearchService {
* @param {initEngine} [options.initEngine]
* Set to true if this engine is being loaded during initialization.
*/
- async _createAndAddEngine({
+ async #createAndAddAddonEngine({
extension,
locale = lazy.SearchUtils.DEFAULT_TAG,
settings,
@@ -2904,7 +2938,7 @@ export class SearchService {
"Engine already loaded via settings, skipping due to APP_STARTUP:",
extension.id
);
- return engine;
+ return;
}
}
@@ -2915,6 +2949,12 @@ export class SearchService {
await this.init();
}
+ lazy.logConsole.debug(
+ "#createAndAddAddonEngine: installing:",
+ extension.id,
+ locale
+ );
+
let shouldSetAsDefault = false;
let changeReason = Ci.nsISearchService.CHANGE_REASON_UNKNOWN;
@@ -2988,7 +3028,6 @@ export class SearchService {
if (shouldSetAsDefault) {
this.#setEngineDefault(false, newEngine, changeReason);
}
- return newEngine;
}
/**
@@ -3046,26 +3085,14 @@ export class SearchService {
) {
lazy.logConsole.debug("installExtensionEngine:", extension.id);
- let installLocale = async locale => {
- return this._createAndAddEngine({
+ for (let locale of locales) {
+ await this.#createAndAddAddonEngine({
extension,
locale,
settings,
initEngine,
});
- };
-
- let engines = [];
- for (let locale of locales) {
- lazy.logConsole.debug(
- "addEnginesFromExtension: installing:",
- extension.id,
- ":",
- locale
- );
- engines.push(await installLocale(locale));
}
- return engines;
}
#internalRemoveEngine(engine) {
@@ -3953,11 +3980,7 @@ XPCOMUtils.defineLazyServiceGetter(
* Handles getting and checking extensions against the allow list.
*/
class SearchDefaultOverrideAllowlistHandler {
- /**
- * @param {Function} listener
- * A listener for configuration update changes.
- */
- constructor(listener) {
+ constructor() {
this._remoteConfig = lazy.RemoteSettings(
lazy.SearchUtils.SETTINGS_ALLOWLIST_KEY
);
diff --git a/toolkit/components/search/SearchSuggestionController.sys.mjs b/toolkit/components/search/SearchSuggestionController.sys.mjs
index b528066d84..871931c280 100644
--- a/toolkit/components/search/SearchSuggestionController.sys.mjs
+++ b/toolkit/components/search/SearchSuggestionController.sys.mjs
@@ -525,14 +525,14 @@ export class SearchSuggestionController {
this.#onRemoteLoaded(context, deferredResponse);
});
- request.addEventListener("error", evt => {
+ request.addEventListener("error", () => {
this.#reportTelemetryForEngine(context);
deferredResponse.resolve("HTTP error");
});
// Reject for an abort assuming it's always from .stop() in which case we
// shouldn't return local or remote results for existing searches.
- request.addEventListener("abort", evt => {
+ request.addEventListener("abort", () => {
context.timer.cancel();
this.#reportTelemetryForEngine(context);
deferredResponse.reject("HTTP request aborted");
diff --git a/toolkit/components/search/SearchUtils.sys.mjs b/toolkit/components/search/SearchUtils.sys.mjs
index c1a956e56e..27c8f8ad03 100644
--- a/toolkit/components/search/SearchUtils.sys.mjs
+++ b/toolkit/components/search/SearchUtils.sys.mjs
@@ -106,8 +106,8 @@ class LoadListener {
}
// nsIProgressEventSink
- onProgress(request, progress, progressMax) {}
- onStatus(request, status, statusArg) {}
+ onProgress() {}
+ onStatus() {}
}
export var SearchUtils = {
diff --git a/toolkit/components/search/nsISearchService.idl b/toolkit/components/search/nsISearchService.idl
index 769ba4eca7..4421c25974 100644
--- a/toolkit/components/search/nsISearchService.idl
+++ b/toolkit/components/search/nsISearchService.idl
@@ -99,7 +99,7 @@ interface nsISearchEngine : nsISupports
* Width of the requested icon. If not specified, it is assumed that
* 16x16 is desired.
*/
- jsval getIconURL([optional] in unsigned short preferredWidth);
+ Promise getIconURL([optional] in unsigned short preferredWidth);
/**
* Opens a speculative connection to the engine's search URI
diff --git a/toolkit/components/search/schema/search-config-overrides-ui-schema.json b/toolkit/components/search/schema/search-config-overrides-ui-schema.json
new file mode 100644
index 0000000000..d5c3fdc240
--- /dev/null
+++ b/toolkit/components/search/schema/search-config-overrides-ui-schema.json
@@ -0,0 +1,3 @@
+{
+ "ui:order": ["telemetryId", "telemetrySuffix", "clickUrl", "params"]
+}
diff --git a/toolkit/components/search/schema/search-config-overrides-v2-schema.json b/toolkit/components/search/schema/search-config-overrides-v2-schema.json
index cac02d8f2a..1fcb8e9cc0 100644
--- a/toolkit/components/search/schema/search-config-overrides-v2-schema.json
+++ b/toolkit/components/search/schema/search-config-overrides-v2-schema.json
@@ -56,6 +56,7 @@
}
},
"type": "object",
+ "required": ["identifier", "partnerCode", "clickUrl", "urls"],
"properties": {
"identifier": {
"title": "Identifier",
diff --git a/toolkit/components/search/schema/search-config-overrides-v2-ui-schema.json b/toolkit/components/search/schema/search-config-overrides-v2-ui-schema.json
new file mode 100644
index 0000000000..60fca49b8d
--- /dev/null
+++ b/toolkit/components/search/schema/search-config-overrides-v2-ui-schema.json
@@ -0,0 +1,9 @@
+{
+ "ui:order": [
+ "identifier",
+ "clickUrl",
+ "telemetrySuffix",
+ "partnerCode",
+ "urls"
+ ]
+}
diff --git a/toolkit/components/search/schema/search-default-override-allowlist-ui-schema.json b/toolkit/components/search/schema/search-default-override-allowlist-ui-schema.json
index 1b85489c13..65fb4f07e2 100644
--- a/toolkit/components/search/schema/search-default-override-allowlist-ui-schema.json
+++ b/toolkit/components/search/schema/search-default-override-allowlist-ui-schema.json
@@ -1,3 +1,3 @@
{
- "ui:order": ["thirdPartyId", "overridesId", "urls"]
+ "ui:order": ["thirdPartyId", "overridesId", "engineName", "urls"]
}
diff --git a/toolkit/components/search/tests/SearchTestUtils.sys.mjs b/toolkit/components/search/tests/SearchTestUtils.sys.mjs
index 8922070154..c3577d2887 100644
--- a/toolkit/components/search/tests/SearchTestUtils.sys.mjs
+++ b/toolkit/components/search/tests/SearchTestUtils.sys.mjs
@@ -429,6 +429,8 @@ export var SearchTestUtils = {
*
* @param {object} [options]
* The options for the manifest.
+ * @param {object} [options.icons]
+ * The icons to use for the WebExtension.
* @param {string} [options.id]
* The id to use for the WebExtension.
* @param {string} [options.name]
@@ -478,6 +480,10 @@ export var SearchTestUtils = {
},
};
+ if (options.icons) {
+ manifest.icons = options.icons;
+ }
+
if (options.default_locale) {
manifest.default_locale = options.default_locale;
}
@@ -541,11 +547,11 @@ export var SearchTestUtils = {
QueryInterface: ChromeUtils.generateQI(["nsIUserIdleService"]),
idleTime: 19999,
- addIdleObserver(observer, time) {
+ addIdleObserver(observer) {
this._observers.add(observer);
},
- removeIdleObserver(observer, time) {
+ removeIdleObserver(observer) {
this._observers.delete(observer);
},
},
diff --git a/toolkit/components/search/tests/xpcshell/data/search-config-v2-no-order-hint.json b/toolkit/components/search/tests/xpcshell/data/search-config-v2-no-order-hint.json
new file mode 100644
index 0000000000..6371a328f3
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/search-config-v2-no-order-hint.json
@@ -0,0 +1,207 @@
+{
+ "data": [
+ {
+ "recordType": "engine",
+ "identifier": "engine",
+ "base": {
+ "name": "Test search engine",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["gd"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-rel-searchform-purpose",
+ "base": {
+ "name": "engine-rel-searchform-purpose",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs",
+ "searchbar": "sb"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-chromeicon",
+ "base": {
+ "name": "engine-chromeicon",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ },
+ {
+ "environment": { "regions": ["ru"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-resourceicon",
+ "base": {
+ "name": "engine-resourceicon",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": {
+ "excludedRegions": ["ru"],
+ "locales": ["en-US", "fr"]
+ }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-resourceicon-gd",
+ "base": {
+ "name": "engine-resourceicon-gd",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": {
+ "locales": ["gd"]
+ }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-reordered",
+ "base": {
+ "name": "Test search engine (Reordered)",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-pref",
+ "base": {
+ "name": "engine-pref",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "code",
+ "experimentConfig": "code"
+ },
+ {
+ "name": "test",
+ "experimentConfig": "test"
+ }
+ ],
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de"] }
+ }
+ ]
+ },
+ {
+ "recordType": "defaultEngines",
+ "globalDefault": "engine",
+ "specificDefaults": [
+ {
+ "defaultPrivate": "engine-pref",
+ "environment": { "excludedLocales": ["de"] }
+ },
+ {
+ "default": "engine-resourceicon-gd",
+ "environment": { "locales": ["gd"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engineOrders",
+ "orders": [
+ {
+ "environment": { "allRegionsAndLocales": true },
+ "order": ["engine-chromeicon", "engine-rel-searchform-purpose"]
+ }
+ ]
+ }
+ ]
+}
diff --git a/toolkit/components/search/tests/xpcshell/data/search-config-v2.json b/toolkit/components/search/tests/xpcshell/data/search-config-v2.json
new file mode 100644
index 0000000000..569e16dfe4
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/search-config-v2.json
@@ -0,0 +1,223 @@
+{
+ "data": [
+ {
+ "recordType": "engine",
+ "identifier": "engine",
+ "base": {
+ "name": "Test search engine",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["gd"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-pref",
+ "base": {
+ "name": "engine-pref",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "code",
+ "experimentConfig": "code"
+ },
+ {
+ "name": "test",
+ "experimentConfig": "test"
+ }
+ ],
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-rel-searchform-purpose",
+ "base": {
+ "name": "engine-rel-searchform-purpose",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs",
+ "searchbar": "sb"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-chromeicon",
+ "base": {
+ "name": "engine-chromeicon",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ },
+ {
+ "environment": { "regions": ["ru"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-resourceicon",
+ "base": {
+ "name": "engine-resourceicon",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": {
+ "excludedRegions": ["ru"],
+ "locales": ["en-US", "fr"]
+ }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-resourceicon-gd",
+ "base": {
+ "name": "engine-resourceicon-gd",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "locales": ["gd"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "engine-reordered",
+ "base": {
+ "name": "Test search engine (Reordered)",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "channel",
+ "searchAccessPoint": {
+ "addressbar": "fflb",
+ "contextmenu": "rcs"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "excludedLocales": ["de", "fr"] }
+ }
+ ]
+ },
+ {
+ "recordType": "defaultEngines",
+ "globalDefault": "engine",
+ "specificDefaults": [
+ {
+ "defaultPrivate": "engine-pref",
+ "environment": { "excludedLocales": ["de"] }
+ },
+ {
+ "default": "engine-resourceicon-gd",
+ "environment": { "locales": ["gd"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engineOrders",
+ "orders": [
+ {
+ "environment": { "allRegionsAndLocales": true },
+ "order": [
+ "engine",
+ "engine-resourceicon",
+ "engine-chromeicon",
+ "engine-pref",
+ "engine-rel-searchform-purpose",
+ "engine-reordered"
+ ]
+ },
+ {
+ "environment": { "locales": ["gd"] },
+ "order": [
+ "engine",
+ "engine-rel-searchform-purpose",
+ "engine-resourceicon",
+ "engine-chromeicon",
+ "engine-pref",
+ "engine-reordered"
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/toolkit/components/search/tests/xpcshell/method-extensions/search-config-v2.json b/toolkit/components/search/tests/xpcshell/method-extensions/search-config-v2.json
new file mode 100644
index 0000000000..a8d3fcc515
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/method-extensions/search-config-v2.json
@@ -0,0 +1,83 @@
+{
+ "data": [
+ {
+ "recordType": "engine",
+ "identifier": "get",
+ "base": {
+ "name": "Get Engine",
+ "urls": {
+ "search": {
+ "base": "https://example.com",
+ "params": [
+ {
+ "name": "config",
+ "value": "1"
+ }
+ ],
+ "searchTermParamName": "search"
+ },
+ "suggestions": {
+ "base": "https://example.com",
+ "params": [
+ {
+ "name": "config",
+ "value": "1"
+ }
+ ],
+ "searchTermParamName": "suggest"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "allRegionsAndLocales": true }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "post",
+ "base": {
+ "name": "Post Engine",
+ "urls": {
+ "search": {
+ "base": "https://example.com",
+ "method": "POST",
+ "params": [
+ {
+ "name": "config",
+ "value": "1"
+ }
+ ],
+ "searchTermParamName": "search"
+ },
+ "suggestions": {
+ "base": "https://example.com",
+ "method": "POST",
+ "params": [
+ {
+ "name": "config",
+ "value": "1"
+ }
+ ],
+ "searchTermParamName": "suggest"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "allRegionsAndLocales": true }
+ }
+ ]
+ },
+ {
+ "recordType": "defaultEngines",
+ "globalDefault": "get",
+ "specificDefaults": []
+ },
+ {
+ "recordType": "engineOrders",
+ "orders": []
+ }
+ ]
+}
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_ui_schemas_valid.js b/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_ui_schemas_valid.js
new file mode 100644
index 0000000000..3315bf974f
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_ui_schemas_valid.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let schemas = [
+ ["search-config-schema.json", "search-config-ui-schema.json"],
+ ["search-config-v2-schema.json", "search-config-v2-ui-schema.json"],
+ ["search-config-icons-schema.json", "search-config-icons-ui-schema.json"],
+ [
+ "search-config-overrides-schema.json",
+ "search-config-overrides-ui-schema.json",
+ ],
+ [
+ "search-config-overrides-v2-schema.json",
+ "search-config-overrides-v2-ui-schema.json",
+ ],
+ [
+ "search-default-override-allowlist-schema.json",
+ "search-default-override-allowlist-ui-schema.json",
+ ],
+];
+
+add_task(async function test_ui_schemas_valid() {
+ for (let [schema, uiSchema] of schemas) {
+ info(`Validating ${uiSchema} has every top-level from ${schema}`);
+ let schemaData = await IOUtils.readJSON(
+ PathUtils.join(do_get_cwd().path, schema)
+ );
+ let uiSchemaData = await IOUtils.readJSON(
+ PathUtils.join(do_get_cwd().path, uiSchema)
+ );
+
+ await checkUISchemaValid(schemaData, uiSchemaData);
+ }
+});
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_validates.js b/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_validates.js
index 51e71ff573..86686b62f7 100644
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_validates.js
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchconfig_validates.js
@@ -65,103 +65,79 @@ function disallowAdditionalProperties(section) {
}
}
-let searchConfigSchemaV1;
-let searchConfigSchema;
-
-add_setup(async function () {
- searchConfigSchemaV1 = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-schema.json")
- );
- searchConfigSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-v2-schema.json")
+/**
+ * Asserts the remote setting collection validates against the schema.
+ *
+ * @param {object} options
+ * The options for the assertion.
+ * @param {string} options.collectionName
+ * The name of the collection under validation.
+ * @param {object[]} options.collectionData
+ * The collection data to validate.
+ * @param {string[]} [options.ignoreFields=[]]
+ * A list of fields to ignore in the collection data, e.g. where remote
+ * settings itself adds extra fields. `schema`, `id`, and `last_modified` are
+ * always ignored.
+ * @param {Function} [options.extraAssertsFn]
+ * An optional function to run additional assertions on each entry in the
+ * collection.
+ * @param {Function} options.getEntryId
+ * A function to get the identifier for each entry in the collection.
+ */
+async function assertSearchConfigValidates({
+ collectionName,
+ collectionData,
+ ignoreFields = [],
+ extraAssertsFn,
+ getEntryId,
+}) {
+ let schema = await IOUtils.readJSON(
+ PathUtils.join(do_get_cwd().path, `${collectionName}-schema.json`)
);
-});
-async function checkSearchConfigValidates(schema, searchConfig) {
disallowAdditionalProperties(schema);
let validator = new JsonSchema.Validator(schema);
- for (let entry of searchConfig) {
+ for (let entry of collectionData) {
// Records in Remote Settings contain additional properties independent of
// the schema. Hence, we don't want to validate their presence.
- delete entry.schema;
- delete entry.id;
- delete entry.last_modified;
+ for (let field of [...ignoreFields, "schema", "id", "last_modified"]) {
+ delete entry[field];
+ }
let result = validator.validate(entry);
- // entry.webExtension.id supports search-config v1.
- let message = `Should validate ${
- entry.identifier ?? entry.recordType ?? entry.webExtension.id
- }`;
+ let message = `Should validate ${getEntryId(entry)}`;
if (!result.valid) {
message += `:\n${JSON.stringify(result.errors, null, 2)}`;
}
Assert.ok(result.valid, message);
- // All engine objects should have the base URL defined for each entry in
- // entry.base.urls.
- // Unfortunately this is difficult to enforce in the schema as it would
- // need a `required` field that works across multiple levels.
- if (entry.recordType == "engine") {
- for (let urlEntry of Object.values(entry.base.urls)) {
- Assert.ok(
- urlEntry.base,
- "Should have a base url for every URL defined on the top-level base object."
- );
- }
- }
+ extraAssertsFn?.(entry);
}
}
-async function checkSearchConfigOverrideValidates(
- schema,
- searchConfigOverride
-) {
- let validator = new JsonSchema.Validator(schema);
-
- for (let entry of searchConfigOverride) {
- // Records in Remote Settings contain additional properties independent of
- // the schema. Hence, we don't want to validate their presence.
- delete entry.schema;
- delete entry.id;
- delete entry.last_modified;
-
- let result = validator.validate(entry);
-
- let message = `Should validate ${entry.identifier ?? entry.telemetryId}`;
- if (!result.valid) {
- message += `:\n${JSON.stringify(result.errors, null, 2)}`;
- }
- Assert.ok(result.valid, message);
- }
-}
+add_setup(async function () {
+ updateAppInfo({ ID: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" });
+});
add_task(async function test_search_config_validates_to_schema_v1() {
let selector = new SearchEngineSelectorOld(() => {});
- let searchConfig = await selector.getEngineConfiguration();
- await checkSearchConfigValidates(searchConfigSchemaV1, searchConfig);
-});
-
-add_task(async function test_ui_schema_valid_v1() {
- let uiSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-ui-schema.json")
- );
-
- await checkUISchemaValid(searchConfigSchemaV1, uiSchema);
+ await assertSearchConfigValidates({
+ collectionName: "search-config",
+ collectionData: await selector.getEngineConfiguration(),
+ getEntryId: entry => entry.webExtension.id,
+ });
});
add_task(async function test_search_config_override_validates_to_schema_v1() {
let selector = new SearchEngineSelectorOld(() => {});
- let searchConfigOverrides = await selector.getEngineConfigurationOverrides();
- let overrideSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-overrides-schema.json")
- );
- await checkSearchConfigOverrideValidates(
- overrideSchema,
- searchConfigOverrides
- );
+ await assertSearchConfigValidates({
+ collectionName: "search-config-overrides",
+ collectionData: await selector.getEngineConfigurationOverrides(),
+ getEntryId: entry => entry.telemetryId,
+ });
});
add_task(
@@ -171,20 +147,26 @@ add_task(
SearchUtils.newSearchConfigEnabled = true;
let selector = new SearchEngineSelector(() => {});
- let searchConfig = await selector.getEngineConfiguration();
-
- await checkSearchConfigValidates(searchConfigSchema, searchConfig);
- }
-);
-
-add_task(
- { skip_if: () => !SearchUtils.newSearchConfigEnabled },
- async function test_ui_schema_valid() {
- let uiSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-v2-ui-schema.json")
- );
- await checkUISchemaValid(searchConfigSchema, uiSchema);
+ await assertSearchConfigValidates({
+ collectionName: "search-config-v2",
+ collectionData: await selector.getEngineConfiguration(),
+ getEntryId: entry => entry.identifier,
+ extraAssertsFn: entry => {
+ // All engine objects should have the base URL defined for each entry in
+ // entry.base.urls.
+ // Unfortunately this is difficult to enforce in the schema as it would
+ // need a `required` field that works across multiple levels.
+ if (entry.recordType == "engine") {
+ for (let urlEntry of Object.values(entry.base.urls)) {
+ Assert.ok(
+ urlEntry.base,
+ "Should have a base url for every URL defined on the top-level base object."
+ );
+ }
+ }
+ },
+ });
}
);
@@ -192,18 +174,33 @@ add_task(
{ skip_if: () => !SearchUtils.newSearchConfigEnabled },
async function test_search_config_override_validates_to_schema() {
let selector = new SearchEngineSelector(() => {});
- let searchConfigOverrides =
- await selector.getEngineConfigurationOverrides();
- let overrideSchema = await IOUtils.readJSON(
- PathUtils.join(
- do_get_cwd().path,
- "search-config-overrides-v2-schema.json"
- )
- );
-
- await checkSearchConfigOverrideValidates(
- overrideSchema,
- searchConfigOverrides
- );
+
+ await assertSearchConfigValidates({
+ collectionName: "search-config-overrides-v2",
+ collectionData: await selector.getEngineConfigurationOverrides(),
+ getEntryId: entry => entry.identifier,
+ });
}
);
+
+add_task(async function test_search_config_icons_validates_to_schema() {
+ let searchIcons = RemoteSettings("search-config-icons");
+
+ await assertSearchConfigValidates({
+ collectionName: "search-config-icons",
+ collectionData: await searchIcons.get(),
+ ignoreFields: ["attachment"],
+ getEntryId: entry => entry.engineIdentifiers[0],
+ });
+});
+
+add_task(async function test_search_default_override_allowlist_validates() {
+ let allowlist = RemoteSettings("search-default-override-allowlist");
+
+ await assertSearchConfigValidates({
+ collectionName: "search-default-override-allowlist",
+ collectionData: await allowlist.get(),
+ ignoreFields: ["attachment"],
+ getEntryId: entry => entry.engineName || entry.thirdPartyId,
+ });
+});
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchicons_validates.js b/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchicons_validates.js
deleted file mode 100644
index c830bb7ade..0000000000
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/test_searchicons_validates.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-let searchIconsSchema;
-
-add_setup(async function () {
- searchIconsSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-icons-schema.json")
- );
-});
-
-add_task(async function test_ui_schema_valid() {
- let uiSchema = await IOUtils.readJSON(
- PathUtils.join(do_get_cwd().path, "search-config-icons-ui-schema.json")
- );
-
- await checkUISchemaValid(searchIconsSchema, uiSchema);
-});
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml b/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
index 8baff2a38d..07567005d6 100644
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
@@ -40,20 +40,30 @@ requesttimeoutfactor = 2
["test_rakuten.js"]
-["test_searchconfig_validates.js"]
+["test_searchconfig_ui_schemas_valid.js"]
support-files = [
+ "../../../schema/search-config-icons-schema.json",
+ "../../../schema/search-config-icons-ui-schema.json",
"../../../schema/search-config-overrides-schema.json",
+ "../../../schema/search-config-overrides-ui-schema.json",
"../../../schema/search-config-overrides-v2-schema.json",
+ "../../../schema/search-config-overrides-v2-ui-schema.json",
"../../../schema/search-config-schema.json",
"../../../schema/search-config-ui-schema.json",
"../../../schema/search-config-v2-schema.json",
"../../../schema/search-config-v2-ui-schema.json",
+ "../../../schema/search-default-override-allowlist-schema.json",
+ "../../../schema/search-default-override-allowlist-ui-schema.json",
]
-["test_searchicons_validates.js"]
+["test_searchconfig_validates.js"]
support-files = [
"../../../schema/search-config-icons-schema.json",
- "../../../schema/search-config-icons-ui-schema.json",
+ "../../../schema/search-config-overrides-schema.json",
+ "../../../schema/search-config-overrides-v2-schema.json",
+ "../../../schema/search-config-schema.json",
+ "../../../schema/search-config-v2-schema.json",
+ "../../../schema/search-default-override-allowlist-schema.json",
]
["test_selector_db_out_of_date.js"]
diff --git a/toolkit/components/search/tests/xpcshell/test-extensions/search-config-v2.json b/toolkit/components/search/tests/xpcshell/test-extensions/search-config-v2.json
new file mode 100644
index 0000000000..4f2e88a05b
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test-extensions/search-config-v2.json
@@ -0,0 +1,139 @@
+{
+ "data": [
+ {
+ "recordType": "engine",
+ "identifier": "plainengine",
+ "base": {
+ "name": "Plain",
+ "urls": {
+ "search": {
+ "base": "https://duckduckgo.com/",
+ "params": [
+ {
+ "name": "t",
+ "searchAccessPoint": {
+ "newtab": "ffnt",
+ "homepage": "ffhp",
+ "searchbar": "ffsb",
+ "addressbar": "ffab",
+ "contextmenu": "ffcm"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://ac.duckduckgo.com/ac/q={searchTerms}&type=list"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "allRegionsAndLocales": true }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "special-engine",
+ "base": {
+ "name": "Special",
+ "urls": {
+ "search": {
+ "base": "https://www.google.com/search",
+ "params": [
+ {
+ "name": "client",
+ "searchAccessPoint": {
+ "searchbar": "firefox-b-1",
+ "addressbar": "firefox-b-1-ab"
+ }
+ }
+ ],
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://www.google.com/complete/search?client=firefox&q={searchTerms}"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "allRegionsAndLocales": true }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "multilocale-an",
+ "base": {
+ "name": "Multilocale AN",
+ "urls": {
+ "search": {
+ "base": "https://an.wikipedia.org/wiki/Especial:Mirar",
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://an.wikipedia.org/w/api.php",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "regions": ["an"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engine",
+ "identifier": "multilocale-af",
+ "base": {
+ "name": "Multilocale AF",
+ "urls": {
+ "search": {
+ "base": "https://af.wikipedia.org/wiki/Spesiaal:Soek",
+ "searchTermParamName": "q"
+ },
+ "suggestions": {
+ "base": "https://af.wikipedia.org/w/api.php",
+ "searchTermParamName": "q"
+ }
+ }
+ },
+ "variants": [
+ {
+ "environment": { "regions": ["af"] }
+ }
+ ]
+ },
+ {
+ "recordType": "defaultEngines",
+ "globalDefault": "plainengine",
+ "specificDefaults": [
+ {
+ "default": "special-engine",
+ "environment": { "regions": ["tr"] }
+ },
+ {
+ "default": "multilocale-an",
+ "environment": { "regions": ["an"] }
+ }
+ ]
+ },
+ {
+ "recordType": "engineOrders",
+ "orders": [
+ {
+ "order": [
+ "plainengine",
+ "special-engine",
+ "multilocale-af",
+ "multilocale-an"
+ ],
+ "environment": { "allRegionsAndLocales": true }
+ }
+ ]
+ }
+ ]
+}
diff --git a/toolkit/components/search/tests/xpcshell/test_appProvided_icons.js b/toolkit/components/search/tests/xpcshell/test_appProvided_icons.js
new file mode 100644
index 0000000000..e4d8033993
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_appProvided_icons.js
@@ -0,0 +1,211 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests to ensure that icons for application provided engines are correctly
+ * loaded from remote settings.
+ */
+
+"use strict";
+
+// A skeleton configuration that gets filled in from TESTS during `add_setup`.
+let CONFIG = [
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine_no_icon",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
+let TESTS = [
+ {
+ engineId: "engine_no_icon",
+ expectedIcon: null,
+ },
+ {
+ engineId: "engine_exact_match",
+ icons: [
+ {
+ filename: "remoteIcon.ico",
+ engineIdentifiers: ["engine_exact_match"],
+ imageSize: 16,
+ },
+ ],
+ expectedIcon: "remoteIcon.ico",
+ },
+ {
+ engineId: "engine_begins_with",
+ icons: [
+ {
+ filename: "remoteIcon.ico",
+ engineIdentifiers: ["engine_begins*"],
+ imageSize: 16,
+ },
+ ],
+ expectedIcon: "remoteIcon.ico",
+ },
+ {
+ engineId: "engine_non_default_sized_icon",
+ icons: [
+ {
+ filename: "remoteIcon.ico",
+ engineIdentifiers: ["engine_non_default_sized_icon"],
+ imageSize: 32,
+ },
+ ],
+ expectedIcon: "remoteIcon.ico",
+ },
+ {
+ engineId: "engine_multiple_icons",
+ icons: [
+ {
+ filename: "bigIcon.ico",
+ engineIdentifiers: ["engine_multiple_icons"],
+ imageSize: 16,
+ },
+ {
+ filename: "remoteIcon.ico",
+ engineIdentifiers: ["engine_multiple_icons"],
+ imageSize: 32,
+ },
+ ],
+ expectedIcon: "bigIcon.ico",
+ },
+];
+
+async function getFileDataBuffer(filename) {
+ let data = await IOUtils.read(
+ PathUtils.join(do_get_cwd().path, "data", filename)
+ );
+ return new TextEncoder().encode(data).buffer;
+}
+
+async function mockRecordWithAttachment({
+ filename,
+ engineIdentifiers,
+ imageSize,
+}) {
+ let buffer = await getFileDataBuffer(filename);
+
+ let stream = Cc["@mozilla.org/io/arraybuffer-input-stream;1"].createInstance(
+ Ci.nsIArrayBufferInputStream
+ );
+ stream.setData(buffer, 0, buffer.byteLength);
+
+ // Generate a hash.
+ let hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
+ Ci.nsICryptoHash
+ );
+ hasher.init(Ci.nsICryptoHash.SHA256);
+ hasher.updateFromStream(stream, -1);
+ let hash = hasher.finish(false);
+ hash = Array.from(hash, (_, i) =>
+ ("0" + hash.charCodeAt(i).toString(16)).slice(-2)
+ ).join("");
+
+ let record = {
+ id: Services.uuid.generateUUID().toString(),
+ engineIdentifiers,
+ imageSize,
+ attachment: {
+ hash,
+ location: `main-workspace/search-config-icons/${filename}`,
+ filename,
+ size: buffer.byteLength,
+ mimetype: "application/json",
+ },
+ };
+
+ let attachment = {
+ record,
+ blob: new Blob([buffer]),
+ };
+
+ return { record, attachment };
+}
+
+async function insertRecordIntoCollection(client, db, item) {
+ let { record, attachment } = await mockRecordWithAttachment(item);
+ await db.create(record);
+ await client.attachments.cacheImpl.set(record.id, attachment);
+ await db.importChanges({}, Date.now());
+}
+
+add_setup(async function () {
+ let client = RemoteSettings("search-config-icons");
+ let db = client.db;
+
+ await db.clear();
+
+ for (let test of TESTS) {
+ CONFIG.push({
+ identifier: test.engineId,
+ recordType: "engine",
+ base: {
+ name: test.engineId + " name",
+ urls: {
+ search: {
+ base: "https://example.com/" + test.engineId,
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [{ environment: { allRegionsAndLocales: true } }],
+ });
+
+ if ("icons" in test) {
+ for (let icon of test.icons) {
+ await insertRecordIntoCollection(client, db, {
+ ...icon,
+ id: test.engineId,
+ });
+ }
+ }
+ }
+
+ await SearchTestUtils.useTestEngines("simple-engines", null, CONFIG);
+ await Services.search.init();
+});
+
+for (let test of TESTS) {
+ add_task(async function () {
+ info("Testing engine: " + test.engineId);
+
+ let engine = Services.search.getEngineByName(test.engineId + " name");
+ if (test.expectedIcon) {
+ let engineIconURL = await engine.getIconURL(16);
+ Assert.notEqual(
+ engineIconURL,
+ null,
+ "Should have an icon URL for the engine."
+ );
+
+ let response = await fetch(engineIconURL);
+ let buffer = new Uint8Array(await response.arrayBuffer());
+
+ let expectedBuffer = new Uint8Array(
+ await getFileDataBuffer(test.expectedIcon)
+ );
+
+ Assert.equal(
+ buffer.length,
+ expectedBuffer.length,
+ "Should have received matching buffer lengths for the expected icon"
+ );
+ Assert.ok(
+ buffer.every((value, index) => value === expectedBuffer[index]),
+ "Should have received matching data for the expected icon"
+ );
+ } else {
+ Assert.equal(
+ await engine.getIconURL(),
+ null,
+ "Should not have an icon URL for the engine."
+ );
+ }
+ });
+}
diff --git a/toolkit/components/search/tests/xpcshell/test_defaultPrivateEngine.js b/toolkit/components/search/tests/xpcshell/test_defaultPrivateEngine.js
index 053d91fe48..392700d84a 100644
--- a/toolkit/components/search/tests/xpcshell/test_defaultPrivateEngine.js
+++ b/toolkit/components/search/tests/xpcshell/test_defaultPrivateEngine.js
@@ -108,7 +108,9 @@ add_task(async function test_defaultPrivateEngine() {
loadPath: SearchUtils.newSearchConfigEnabled
? "[app]engine-rel-searchform-purpose@search.mozilla.org"
: "[addon]engine-rel-searchform-purpose@search.mozilla.org",
- submissionUrl: "https://www.google.com/search?q=&channel=sb",
+ submissionUrl: SearchUtils.newSearchConfigEnabled
+ ? "https://www.google.com/search?channel=sb&q="
+ : "https://www.google.com/search?q=&channel=sb",
verified: "default",
},
});
diff --git a/toolkit/components/search/tests/xpcshell/test_engine_ids.js b/toolkit/components/search/tests/xpcshell/test_engine_ids.js
index cef6a17c92..57b9ad26cf 100644
--- a/toolkit/components/search/tests/xpcshell/test_engine_ids.js
+++ b/toolkit/components/search/tests/xpcshell/test_engine_ids.js
@@ -47,9 +47,56 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(async function () {
useHttpServer("opensearch");
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
});
diff --git a/toolkit/components/search/tests/xpcshell/test_engine_set_alias.js b/toolkit/components/search/tests/xpcshell/test_engine_set_alias.js
index ec79fe6783..f15e257996 100644
--- a/toolkit/components/search/tests/xpcshell/test_engine_set_alias.js
+++ b/toolkit/components/search/tests/xpcshell/test_engine_set_alias.js
@@ -119,7 +119,7 @@ add_task(async function test_engine_change_alias() {
);
let observed = false;
- Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ Services.obs.addObserver(function observer() {
observed = true;
}, SearchUtils.TOPIC_ENGINE_MODIFIED);
diff --git a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_pref.js b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_pref.js
index 5283207394..54fd028474 100644
--- a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_pref.js
+++ b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_pref.js
@@ -14,6 +14,7 @@ const defaultBranch = Services.prefs.getDefaultBranch(
SearchUtils.BROWSER_SEARCH_PREF
);
const baseURL = "https://www.google.com/search?q=foo";
+const baseURLSearchConfigV2 = "https://www.google.com/search?";
add_setup(async function () {
// The test engines used in this test need to be recognized as 'default'
@@ -40,7 +41,9 @@ add_task(async function test_pref_initial_value() {
const engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=good%26id%3Dunique",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=good%26id%3Dunique&q=foo"
+ : baseURL + "&code=good%26id%3Dunique",
"Should have got the submission URL with the correct code"
);
@@ -59,7 +62,9 @@ add_task(async function test_pref_updated() {
const engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=supergood%26id%3Dunique123456",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=supergood%26id%3Dunique123456&q=foo"
+ : baseURL + "&code=supergood%26id%3Dunique123456",
"Should have got the submission URL with the updated code"
);
});
diff --git a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus.js b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus.js
index e9b55ff3dc..3963a07368 100644
--- a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus.js
+++ b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus.js
@@ -11,6 +11,7 @@ const { NimbusFeatures } = ChromeUtils.importESModule(
);
const baseURL = "https://www.google.com/search?q=foo";
+const baseURLSearchConfigV2 = "https://www.google.com/search?";
let getVariableStub;
let updateStub;
@@ -48,7 +49,9 @@ add_task(async function test_pref_initial_value() {
const engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=good%26id%3Dunique",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=good%26id%3Dunique&q=foo"
+ : baseURL + "&code=good%26id%3Dunique",
"Should have got the submission URL with the correct code"
);
});
@@ -68,7 +71,9 @@ add_task(async function test_pref_updated() {
const engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=supergood%26id%3Dunique123456",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=supergood%26id%3Dunique123456&q=foo"
+ : baseURL + "&code=supergood%26id%3Dunique123456",
"Should have got the submission URL with the updated code"
);
});
@@ -90,7 +95,9 @@ add_task(async function test_multiple_params() {
let engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=sng&test=sup",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=sng&test=sup&q=foo"
+ : baseURL + "&code=sng&test=sup",
"Should have got the submission URL with both parameters"
);
@@ -107,7 +114,9 @@ add_task(async function test_multiple_params() {
engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=sng",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=sng&q=foo"
+ : baseURL + "&code=sng",
"Should have got the submission URL with one parameter"
);
});
diff --git a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus_invalid.js b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus_invalid.js
index e519a74c64..090b108acf 100644
--- a/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus_invalid.js
+++ b/toolkit/components/search/tests/xpcshell/test_getSubmission_params_prefNimbus_invalid.js
@@ -15,6 +15,7 @@ const { NimbusFeatures } = ChromeUtils.importESModule(
);
const baseURL = "https://www.google.com/search?q=foo";
+const baseURLSearchConfigV2 = "https://www.google.com/search?";
let getVariableStub;
let updateStub;
@@ -66,7 +67,9 @@ add_task(async function test_switch_to_good_nimbus_setting() {
const engine = Services.search.getEngineByName("engine-pref");
Assert.equal(
engine.getSubmission("foo").uri.spec,
- baseURL + "&code=supergood%26id%3Dunique123456",
+ SearchUtils.newSearchConfigEnabled
+ ? baseURLSearchConfigV2 + "code=supergood%26id%3Dunique123456&q=foo"
+ : baseURL + "&code=supergood%26id%3Dunique123456",
"Should have got the submission URL with the updated code"
);
});
diff --git a/toolkit/components/search/tests/xpcshell/test_initialization.js b/toolkit/components/search/tests/xpcshell/test_initialization.js
index c89f3cfcb3..57894e1e55 100644
--- a/toolkit/components/search/tests/xpcshell/test_initialization.js
+++ b/toolkit/components/search/tests/xpcshell/test_initialization.js
@@ -43,13 +43,60 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(() => {
do_get_profile();
Services.fog.initializeFOG();
});
add_task(async function test_initialization_delayed_addon_manager() {
- let stub = await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ let stub = await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
// Wait until the search service gets its configuration before starting
// to initialise the add-on manager. This simulates the add-on manager
// starting late which used to cause the search service to fail to load any
@@ -58,7 +105,7 @@ add_task(async function test_initialization_delayed_addon_manager() {
Services.tm.dispatchToMainThread(() => {
AddonTestUtils.promiseStartupManager();
});
- return CONFIG;
+ return SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG;
});
await Services.search.init();
diff --git a/toolkit/components/search/tests/xpcshell/test_initialization_with_region.js b/toolkit/components/search/tests/xpcshell/test_initialization_with_region.js
index fb9cee5124..377772c6e1 100644
--- a/toolkit/components/search/tests/xpcshell/test_initialization_with_region.js
+++ b/toolkit/components/search/tests/xpcshell/test_initialization_with_region.js
@@ -76,6 +76,87 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { excludedRegions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-pref",
+ base: {
+ name: "engine-pref",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "code",
+ experimentConfig: "code",
+ },
+ {
+ name: "test",
+ experimentConfig: "test",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ specificDefaults: [
+ {
+ default: "engine",
+ defaultPrivate: "engine",
+ environment: { excludedRegions: ["FR"] },
+ },
+ {
+ default: "engine-pref",
+ defaultPrivate: "engine-pref",
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
// Default engine with no region defined.
const DEFAULT = "Test search engine";
// Default engine with region set to FR.
@@ -104,7 +185,11 @@ add_setup(async function () {
);
SearchTestUtils.useMockIdleService();
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
});
diff --git a/toolkit/components/search/tests/xpcshell/test_maybereloadengine_order.js b/toolkit/components/search/tests/xpcshell/test_maybereloadengine_order.js
index 663b7205a7..bdb8510812 100644
--- a/toolkit/components/search/tests/xpcshell/test_maybereloadengine_order.js
+++ b/toolkit/components/search/tests/xpcshell/test_maybereloadengine_order.js
@@ -1,56 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
+/*
+ * Test engine order is not set after engine reload.
+ */
-const TEST_CONFIG = [
- {
- webExtension: {
- id: "plainengine@search.mozilla.org",
- name: "Plain",
- search_url: "https://duckduckgo.com/",
- params: [
- {
- name: "q",
- value: "{searchTerms}",
- },
- ],
- suggest_url: "https://ac.duckduckgo.com/ac/q={searchTerms}&type=list",
- },
- appliesTo: [{ included: { everywhere: true } }],
- },
- {
- webExtension: {
- id: "special-engine@search.mozilla.org",
- name: "Special",
- search_url: "https://www.google.com/search",
- params: [
- {
- name: "q",
- value: "{searchTerms}",
- },
- {
- name: "client",
- condition: "purpose",
- purpose: "keyword",
- value: "firefox-b-1-ab",
- },
- {
- name: "client",
- condition: "purpose",
- purpose: "searchbar",
- value: "firefox-b-1",
- },
- ],
- suggest_url:
- "https://www.google.com/complete/search?client=firefox&q={searchTerms}",
- },
- appliesTo: [{ default: "yes", included: { regions: ["FR"] } }],
- },
-];
+"use strict";
add_setup(async function () {
- await SearchTestUtils.useTestEngines("test-extensions", null, TEST_CONFIG);
+ await SearchTestUtils.useTestEngines("test-extensions");
await AddonTestUtils.promiseStartupManager();
registerCleanupFunction(AddonTestUtils.promiseShutdownManager);
@@ -59,7 +17,7 @@ add_setup(async function () {
add_task(async function basic_multilocale_test() {
let resolver;
let initPromise = new Promise(resolve => (resolver = resolve));
- useCustomGeoServer("FR", initPromise);
+ useCustomGeoServer("TR", initPromise);
await Services.search.init();
await Services.search.getAppProvidedEngines();
diff --git a/toolkit/components/search/tests/xpcshell/test_missing_engine.js b/toolkit/components/search/tests/xpcshell/test_missing_engine.js
index 3da9fe14a6..259baf9c1a 100644
--- a/toolkit/components/search/tests/xpcshell/test_missing_engine.js
+++ b/toolkit/components/search/tests/xpcshell/test_missing_engine.js
@@ -55,6 +55,48 @@ const BAD_CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(async function () {
SearchTestUtils.useMockIdleService();
await AddonTestUtils.promiseStartupManager();
@@ -66,7 +108,11 @@ add_setup(async function () {
});
add_task(async function test_startup_with_missing() {
- await SearchTestUtils.useTestEngines("data", null, BAD_CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : BAD_CONFIG
+ );
const result = await Services.search.init();
Assert.ok(
@@ -89,7 +135,7 @@ add_task(async function test_update_with_missing() {
await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", {
data: {
- current: GOOD_CONFIG,
+ current: SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : GOOD_CONFIG,
},
});
@@ -110,7 +156,7 @@ add_task(async function test_update_with_missing() {
await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", {
data: {
- current: BAD_CONFIG,
+ current: SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : BAD_CONFIG,
},
});
diff --git a/toolkit/components/search/tests/xpcshell/test_opensearch_icon.js b/toolkit/components/search/tests/xpcshell/test_opensearch_icon.js
index 68cd9577c1..23f2d9d575 100644
--- a/toolkit/components/search/tests/xpcshell/test_opensearch_icon.js
+++ b/toolkit/components/search/tests/xpcshell/test_opensearch_icon.js
@@ -56,9 +56,9 @@ add_task(async function test_icon_types() {
engine.QueryInterface(Ci.nsISearchEngine);
await promiseEngineChanged;
- Assert.ok(engine.getIconURL(), `${test.name} engine has an icon`);
+ Assert.ok(await engine.getIconURL(), `${test.name} engine has an icon`);
Assert.ok(
- engine.getIconURL().startsWith(test.expected),
+ (await engine.getIconURL()).startsWith(test.expected),
`${test.name} iconURI starts with the expected information`
);
}
@@ -69,13 +69,13 @@ add_task(async function test_multiple_icons_in_file() {
url: `${gDataUrl}engineImages.xml`,
});
- Assert.ok(engine.getIconURL().includes("ico16"));
- Assert.ok(engine.getIconURL(16).includes("ico16"));
- Assert.ok(engine.getIconURL(32).includes("ico32"));
- Assert.ok(engine.getIconURL(74).includes("ico74"));
+ Assert.ok((await engine.getIconURL()).includes("ico16"));
+ Assert.ok((await engine.getIconURL(16)).includes("ico16"));
+ Assert.ok((await engine.getIconURL(32)).includes("ico32"));
+ Assert.ok((await engine.getIconURL(74)).includes("ico74"));
info("Invalid dimensions should return null until bug 1655070 is fixed.");
- Assert.equal(null, engine.getIconURL(50));
+ Assert.equal(null, await engine.getIconURL(50));
});
add_task(async function test_icon_not_in_opensearch_file() {
@@ -86,6 +86,6 @@ add_task(async function test_icon_not_in_opensearch_file() {
);
// Even though the icon wasn't specified inside the XML file, it should be
- // available both in the iconURI attribute and with getIconURLBySize.
- Assert.ok(engine.getIconURL(16).includes("ico16"));
+ // available.
+ Assert.ok((await engine.getIconURL(16)).includes("ico16"));
});
diff --git a/toolkit/components/search/tests/xpcshell/test_opensearch_icons_invalid.js b/toolkit/components/search/tests/xpcshell/test_opensearch_icons_invalid.js
index 6db13a0da8..744d46052e 100644
--- a/toolkit/components/search/tests/xpcshell/test_opensearch_icons_invalid.js
+++ b/toolkit/components/search/tests/xpcshell/test_opensearch_icons_invalid.js
@@ -21,8 +21,8 @@ add_task(async function test_installedresourceicon() {
url: `${gDataUrl}opensearch/chromeicon.xml`,
});
- Assert.equal(undefined, engine1.getIconURL());
- Assert.equal(undefined, engine2.getIconURL());
+ Assert.equal(undefined, await engine1.getIconURL());
+ Assert.equal(undefined, await engine2.getIconURL());
});
add_task(async function test_installedhttpplace() {
@@ -50,7 +50,7 @@ add_task(async function test_installedhttpplace() {
Assert.equal(
undefined,
- engine.getIconURL(),
+ await engine.getIconURL(),
"Should not have set an iconURI"
);
});
diff --git a/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js b/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
index cd51e7bdee..5ec485c4ec 100644
--- a/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
+++ b/toolkit/components/search/tests/xpcshell/test_override_allowlist_switch.js
@@ -306,8 +306,16 @@ add_task(async function test_app_provided_engine_deployment_extended() {
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);
+ 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
+ );
});
});
diff --git a/toolkit/components/search/tests/xpcshell/test_reload_engines.js b/toolkit/components/search/tests/xpcshell/test_reload_engines.js
index ac63b62e59..60cd3c2a13 100644
--- a/toolkit/components/search/tests/xpcshell/test_reload_engines.js
+++ b/toolkit/components/search/tests/xpcshell/test_reload_engines.js
@@ -238,6 +238,260 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-pref",
+ base: {
+ name: "engine-pref",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "code",
+ experimentConfig: "code",
+ },
+ {
+ name: "test",
+ experimentConfig: "test",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-chromeicon",
+ base: {
+ name: "engine-chromeicon",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ {
+ environment: { regions: ["FR"] },
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "c",
+ value: "my-test",
+ },
+ ],
+ searchTermParamName: "q1",
+ },
+ },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-rel-searchform-purpose",
+ base: {
+ name: "engine-rel-searchform-purpose",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { excludedRegions: ["FR"] },
+ urls: {
+ search: {
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ searchbar: "sb",
+ },
+ },
+ ],
+ },
+ },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-reordered",
+ base: {
+ name: "Test search engine (Reordered)",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-resourceicon",
+ base: {
+ name: "engine-resourceicon",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { excludedRegions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-resourceicon-gd",
+ base: {
+ name: "engine-resourceicon-gd",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-same-name",
+ base: {
+ name: "engine-same-name",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { excludedRegions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-same-name-gd",
+ base: {
+ name: "engine-same-name-gd",
+ urls: {
+ search: {
+ base: "https://www.example.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ specificDefaults: [
+ {
+ default: "engine",
+ defaultPrivate: "engine",
+ environment: { excludedRegions: ["FR"] },
+ },
+ {
+ default: "engine-pref",
+ defaultPrivate: "engine-pref",
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [
+ {
+ order: ["engine-resourceicon-gd"],
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+];
+
async function visibleEngines() {
return (await Services.search.getVisibleEngines()).map(e => e.identifier);
}
@@ -250,7 +504,11 @@ add_setup(async function () {
);
SearchTestUtils.useMockIdleService();
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
});
@@ -325,23 +583,47 @@ add_task(async function test_config_updated_engine_changes() {
await reloadObserved;
Services.obs.removeObserver(enginesObs, SearchUtils.TOPIC_ENGINE_MODIFIED);
- Assert.deepEqual(
- enginesAdded,
- ["engine-resourceicon-gd", "engine-reordered"],
- "Should have added the correct engines"
- );
-
- Assert.deepEqual(
- enginesModified.sort(),
- ["engine", "engine-chromeicon", "engine-pref", "engine-same-name-gd"],
- "Should have modified the expected engines"
- );
-
- Assert.deepEqual(
- enginesRemoved,
- ["engine-rel-searchform-purpose", "engine-resourceicon"],
- "Should have removed the expected engine"
- );
+ if (SearchUtils.newSearchConfigEnabled) {
+ Assert.deepEqual(
+ enginesAdded,
+ ["engine-resourceicon-gd", "engine-reordered", "engine-same-name-gd"],
+ "Should have added the correct engines"
+ );
+
+ Assert.deepEqual(
+ enginesModified.sort(),
+ ["engine", "engine-chromeicon", "engine-pref"],
+ "Should have modified the expected engines"
+ );
+
+ Assert.deepEqual(
+ enginesRemoved,
+ [
+ "engine-rel-searchform-purpose",
+ "engine-resourceicon",
+ "engine-same-name",
+ ],
+ "Should have removed the expected engine"
+ );
+ } else {
+ Assert.deepEqual(
+ enginesAdded,
+ ["engine-resourceicon-gd", "engine-reordered"],
+ "Should have added the correct engines"
+ );
+
+ Assert.deepEqual(
+ enginesModified.sort(),
+ ["engine", "engine-chromeicon", "engine-pref", "engine-same-name-gd"],
+ "Should have modified the expected engines"
+ );
+
+ Assert.deepEqual(
+ enginesRemoved,
+ ["engine-rel-searchform-purpose", "engine-resourceicon"],
+ "Should have removed the expected engine"
+ );
+ }
const installedEngines = await Services.search.getAppProvidedEngines();
@@ -382,7 +664,9 @@ add_task(async function test_config_updated_engine_changes() {
);
const engineWithSameName = await Services.search.getEngineByName(
- "engine-same-name"
+ SearchUtils.newSearchConfigEnabled
+ ? "engine-same-name-gd"
+ : "engine-same-name"
);
Assert.equal(
engineWithSameName.getSubmission("test").uri.spec,
diff --git a/toolkit/components/search/tests/xpcshell/test_reload_engines_experiment.js b/toolkit/components/search/tests/xpcshell/test_reload_engines_experiment.js
index ea5cdee3e5..5edcb6081b 100644
--- a/toolkit/components/search/tests/xpcshell/test_reload_engines_experiment.js
+++ b/toolkit/components/search/tests/xpcshell/test_reload_engines_experiment.js
@@ -72,8 +72,87 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-same-name-en",
+ base: {
+ name: "engine-same-name",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-same-name-gd",
+ base: {
+ name: "engine-same-name",
+ urls: {
+ search: {
+ base: "https://www.example.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true, experiment: "xpcshell" },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(async function () {
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
});
@@ -125,19 +204,42 @@ add_task(async function test_config_updated_engine_changes() {
await reloadObserved;
Services.obs.removeObserver(enginesObs, SearchUtils.TOPIC_ENGINE_MODIFIED);
- Assert.deepEqual(enginesAdded, [], "Should have added the correct engines");
+ if (SearchUtils.newSearchConfigEnabled) {
+ // In the new config, engine-same-name-en and engine-same-name-gd are two
+ // different engine configs and they will be treated as different engines
+ // and not the same. That's the reason why the assertions are different below.
+ Assert.deepEqual(
+ enginesAdded,
+ ["engine-same-name-gd"],
+ "Should have added the correct engines"
+ );
- Assert.deepEqual(
- enginesModified.sort(),
- ["engine", "engine-same-name-gd"],
- "Should have modified the expected engines"
- );
+ Assert.deepEqual(
+ enginesModified.sort(),
+ ["engine", "engine-same-name-en"],
+ "Should have modified the expected engines"
+ );
- Assert.deepEqual(
- enginesRemoved,
- [],
- "Should have removed the expected engine"
- );
+ Assert.deepEqual(
+ enginesRemoved,
+ ["engine-same-name"],
+ "Should have removed the expected engine"
+ );
+ } else {
+ Assert.deepEqual(enginesAdded, [], "Should have added the correct engines");
+
+ Assert.deepEqual(
+ enginesModified.sort(),
+ ["engine", "engine-same-name-gd"],
+ "Should have modified the expected engines"
+ );
+
+ Assert.deepEqual(
+ enginesRemoved,
+ [],
+ "Should have removed the expected engine"
+ );
+ }
const installedEngines = await Services.search.getAppProvidedEngines();
diff --git a/toolkit/components/search/tests/xpcshell/test_reload_engines_locales.js b/toolkit/components/search/tests/xpcshell/test_reload_engines_locales.js
index 6fa277655d..ed516c5a15 100644
--- a/toolkit/components/search/tests/xpcshell/test_reload_engines_locales.js
+++ b/toolkit/components/search/tests/xpcshell/test_reload_engines_locales.js
@@ -72,6 +72,85 @@ const CONFIG = [
},
];
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-diff-name-en",
+ base: {
+ name: "engine-diff-name-en",
+ urls: {
+ search: {
+ base: "https://en.wikipedia.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { excludedLocales: ["gd"] },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-diff-name-gd",
+ base: {
+ name: "engine-diff-name-gd",
+ urls: {
+ search: {
+ base: "https://gd.wikipedia.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { locales: ["gd"] },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(async () => {
Services.locale.availableLocales = [
...Services.locale.availableLocales,
@@ -80,7 +159,11 @@ add_setup(async () => {
];
Services.locale.requestedLocales = ["gd"];
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
});
@@ -101,7 +184,9 @@ add_task(async function test_config_updated_engine_changes() {
);
Assert.equal(
engine.getSubmission("test").uri.spec,
- "https://gd.wikipedia.com/search",
+ SearchUtils.newSearchConfigEnabled
+ ? "https://gd.wikipedia.com/search?q=test"
+ : "https://gd.wikipedia.com/search",
"Should have the gd search url"
);
@@ -122,7 +207,9 @@ add_task(async function test_config_updated_engine_changes() {
);
Assert.equal(
engine.getSubmission("test").uri.spec,
- "https://en.wikipedia.com/search",
+ SearchUtils.newSearchConfigEnabled
+ ? "https://en.wikipedia.com/search?q=test"
+ : "https://en.wikipedia.com/search",
"Should have the en search url"
);
});
diff --git a/toolkit/components/search/tests/xpcshell/test_remove_engine_notification_box.js b/toolkit/components/search/tests/xpcshell/test_remove_engine_notification_box.js
index 0222334255..d5b1366b93 100644
--- a/toolkit/components/search/tests/xpcshell/test_remove_engine_notification_box.js
+++ b/toolkit/components/search/tests/xpcshell/test_remove_engine_notification_box.js
@@ -57,6 +57,100 @@ const CONFIG_UPDATED = CONFIG.filter(r =>
r.webExtension.id.startsWith("engine-pref")
);
+const CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-pref",
+ base: {
+ name: "engine-pref",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ specificDefaults: [
+ {
+ default: "engine",
+ environment: { excludedRegions: ["FR"] },
+ },
+ {
+ default: "engine-pref",
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
+const CONFIG_V2_UPDATED = [
+ {
+ recordType: "engine",
+ identifier: "engine-pref",
+ base: {
+ name: "engine-pref",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ specificDefaults: [
+ {
+ default: "engine",
+ environment: { excludedRegions: ["FR"] },
+ },
+ {
+ default: "engine-pref",
+ environment: { regions: ["FR"] },
+ },
+ ],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
let stub;
let settingsFilePath;
let userSettings;
@@ -64,7 +158,11 @@ let userSettings;
add_setup(async function () {
SearchSettings.SETTINGS_INVALIDATION_DELAY = 100;
SearchTestUtils.useMockIdleService();
- await SearchTestUtils.useTestEngines("data", null, CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
stub = sinon.stub(
@@ -246,7 +344,9 @@ add_task(async function test_default_engine_changed_and_metadata_unchanged() {
};
// Update config by removing the app default engine
- await setConfigToLoad(CONFIG_UPDATED);
+ await setConfigToLoad(
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2_UPDATED : CONFIG_UPDATED
+ );
await reloadEngines(structuredClone(userSettings));
Assert.ok(
@@ -293,7 +393,9 @@ add_task(async function test_app_default_engine_changed_on_start_up() {
settings.metaData.current = "";
// Update config by removing the app default engine
- await setConfigToLoad(CONFIG_UPDATED);
+ await setConfigToLoad(
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2_UPDATED : CONFIG_UPDATED
+ );
await loadEngines(settings);
Assert.ok(
@@ -311,7 +413,9 @@ add_task(async function test_app_default_engine_change_start_up_still_exists() {
settings.metaData.current = "";
settings.metaData.appDefaultEngine = "Test search engine";
- await setConfigToLoad(CONFIG);
+ await setConfigToLoad(
+ SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : CONFIG
+ );
await loadEngines(settings);
Assert.ok(
diff --git a/toolkit/components/search/tests/xpcshell/test_searchSuggest.js b/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
index 48769be41e..4a30eb741a 100644
--- a/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
@@ -581,7 +581,7 @@ add_task(async function stop_search() {
let histogram = TelemetryTestUtils.getAndClearKeyedHistogram(
SEARCH_TELEMETRY_LATENCY
);
- let controller = new SearchSuggestionController(result => {
+ let controller = new SearchSuggestionController(() => {
do_throw("The callback shouldn't be called after stop()");
});
let resultPromise = controller.fetch("mo", false, getEngine);
diff --git a/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js b/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
index cfa9e56144..042c74d86a 100644
--- a/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchSuggest_cookies.js
@@ -28,7 +28,7 @@ function countCacheEntries() {
);
storage.asyncVisitStorage(
{
- onCacheStorageInfo(num, consumption) {
+ onCacheStorageInfo(num) {
this._num = num;
},
onCacheEntryInfo(uri) {
diff --git a/toolkit/components/search/tests/xpcshell/test_searchSuggest_extraParams.js b/toolkit/components/search/tests/xpcshell/test_searchSuggest_extraParams.js
index 8ecf4b02f3..3261174ebf 100644
--- a/toolkit/components/search/tests/xpcshell/test_searchSuggest_extraParams.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchSuggest_extraParams.js
@@ -22,8 +22,62 @@ const TEST_CONFIG = [
},
];
+const TEST_CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "get",
+ base: {
+ name: "Get Engine",
+ urls: {
+ search: {
+ base: "https://example.com",
+ params: [
+ {
+ name: "webExtension",
+ value: "1",
+ },
+ ],
+ searchTermParamName: "search",
+ },
+ suggestions: {
+ base: "https://example.com",
+ params: [
+ {
+ name: "custom_param",
+ experimentConfig: "test_pref_param",
+ },
+ {
+ name: "webExtension",
+ value: "1",
+ },
+ ],
+ searchTermParamName: "suggest",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "get",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
add_setup(async function () {
- await SearchTestUtils.useTestEngines("method-extensions", null, TEST_CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "method-extensions",
+ null,
+ SearchUtils.newSearchConfigEnabled ? TEST_CONFIG_V2 : TEST_CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
});
diff --git a/toolkit/components/search/tests/xpcshell/test_searchTermFromResult.js b/toolkit/components/search/tests/xpcshell/test_searchTermFromResult.js
index 700c6a3450..ea040aacd4 100644
--- a/toolkit/components/search/tests/xpcshell/test_searchTermFromResult.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchTermFromResult.js
@@ -6,6 +6,53 @@
* Tests searchTermFromResult API.
*/
+let CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine-purposes",
+ base: {
+ name: "Test Engine With Purposes",
+ urls: {
+ search: {
+ base: "https://www.example.com/search",
+ params: [
+ { name: "pc", value: "FIREFOX" },
+ {
+ name: "form",
+ searchAccessPoint: {
+ newtab: "MOZNEWTAB",
+ homepage: "MOZHOMEPAGE",
+ searchbar: "MOZSEARCHBAR",
+ addressbar: "MOZKEYWORD",
+ contextmenu: "MOZCONTEXT",
+ },
+ },
+ {
+ name: "channel",
+ experimentConfig: "testChannelEnabled",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine-purpose",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
let defaultEngine;
// The test string contains special characters to ensure
@@ -14,66 +61,72 @@ const TERM = "c;,?:@&=+$-_.!~*'()# d\u00E8f";
const TERM_ENCODED = "c%3B%2C%3F%3A%40%26%3D%2B%24-_.!~*'()%23+d%C3%A8f";
add_setup(async function () {
- await SearchTestUtils.useTestEngines("data", null, [
- {
- webExtension: {
- id: "engine-purposes@search.mozilla.org",
- name: "Test Engine With Purposes",
- search_url: "https://www.example.com/search",
- params: [
- {
- name: "form",
- condition: "purpose",
- purpose: "keyword",
- value: "MOZKEYWORD",
- },
- {
- name: "form",
- condition: "purpose",
- purpose: "contextmenu",
- value: "MOZCONTEXT",
- },
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled
+ ? CONFIG_V2
+ : [
{
- name: "form",
- condition: "purpose",
- purpose: "newtab",
- value: "MOZNEWTAB",
+ webExtension: {
+ id: "engine-purposes@search.mozilla.org",
+ name: "Test Engine With Purposes",
+ search_url: "https://www.example.com/search",
+ params: [
+ {
+ name: "form",
+ condition: "purpose",
+ purpose: "keyword",
+ value: "MOZKEYWORD",
+ },
+ {
+ name: "form",
+ condition: "purpose",
+ purpose: "contextmenu",
+ value: "MOZCONTEXT",
+ },
+ {
+ name: "form",
+ condition: "purpose",
+ purpose: "newtab",
+ value: "MOZNEWTAB",
+ },
+ {
+ name: "form",
+ condition: "purpose",
+ purpose: "searchbar",
+ value: "MOZSEARCHBAR",
+ },
+ {
+ name: "form",
+ condition: "purpose",
+ purpose: "homepage",
+ value: "MOZHOMEPAGE",
+ },
+ {
+ name: "pc",
+ value: "FIREFOX",
+ },
+ {
+ name: "channel",
+ condition: "pref",
+ pref: "testChannelEnabled",
+ },
+ {
+ name: "q",
+ value: "{searchTerms}",
+ },
+ ],
+ },
+ appliesTo: [
+ {
+ included: { everywhere: true },
+ default: "yes",
+ },
+ ],
},
- {
- name: "form",
- condition: "purpose",
- purpose: "searchbar",
- value: "MOZSEARCHBAR",
- },
- {
- name: "form",
- condition: "purpose",
- purpose: "homepage",
- value: "MOZHOMEPAGE",
- },
- {
- name: "pc",
- value: "FIREFOX",
- },
- {
- name: "channel",
- condition: "pref",
- pref: "testChannelEnabled",
- },
- {
- name: "q",
- value: "{searchTerms}",
- },
- ],
- },
- appliesTo: [
- {
- included: { everywhere: true },
- default: "yes",
- },
- ],
- },
- ]);
+ ]
+ );
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
diff --git a/toolkit/components/search/tests/xpcshell/test_settings_persist.js b/toolkit/components/search/tests/xpcshell/test_settings_persist.js
index bed6771554..5c2cbd85c4 100644
--- a/toolkit/components/search/tests/xpcshell/test_settings_persist.js
+++ b/toolkit/components/search/tests/xpcshell/test_settings_persist.js
@@ -1,9 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+/**
+ * Tests the removal of an engine is persisted in search settings.
+ */
+
"use strict";
-const CONFIG_DEFAULT = [
+const CONFIG_UPDATED = [
{
webExtension: {
id: "plainengine@search.mozilla.org",
@@ -18,26 +22,38 @@ const CONFIG_DEFAULT = [
},
appliesTo: [{ included: { everywhere: true } }],
},
+];
+
+const SEARCH_CONFIG_V2_UPDATED = [
{
- webExtension: {
- id: "special-engine@search.mozilla.org",
- name: "Special",
- search_url: "https://www.google.com/search",
- params: [
- {
- name: "q",
- value: "{searchTerms}",
+ recordType: "engine",
+ identifier: "plainengine",
+ base: {
+ name: "Plain",
+ urls: {
+ search: {
+ base: "https://duckduckgo.com/",
+ searchTermParamName: "q",
},
- ],
+ },
},
- appliesTo: [{ included: { everywhere: true } }],
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "plainengine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
},
];
-const CONFIG_UPDATED = CONFIG_DEFAULT.filter(r =>
- r.webExtension.id.startsWith("plainengine")
-);
-
async function startup() {
let settingsFileWritten = promiseAfterSettings();
let ss = new SearchService();
@@ -50,7 +66,10 @@ async function startup() {
async function updateConfig(config) {
const settings = await RemoteSettings(SearchUtils.SETTINGS_KEY);
settings.get.restore();
- sinon.stub(settings, "get").returns(config);
+
+ config == "test-extensions"
+ ? await SearchTestUtils.useTestEngines("test-extensions")
+ : sinon.stub(settings, "get").returns(config);
}
async function visibleEngines(ss) {
@@ -58,7 +77,7 @@ async function visibleEngines(ss) {
}
add_setup(async function () {
- await SearchTestUtils.useTestEngines("test-extensions", null, CONFIG_DEFAULT);
+ await SearchTestUtils.useTestEngines("test-extensions");
registerCleanupFunction(AddonTestUtils.promiseShutdownManager);
await AddonTestUtils.promiseStartupManager();
// This is only needed as otherwise events will not be properly notified
@@ -87,7 +106,11 @@ add_task(async function () {
);
ss._removeObservers();
- updateConfig(CONFIG_UPDATED);
+ await updateConfig(
+ SearchUtils.newSearchConfigEnabled
+ ? SEARCH_CONFIG_V2_UPDATED
+ : CONFIG_UPDATED
+ );
ss = await startup();
Assert.ok(
@@ -96,7 +119,8 @@ add_task(async function () {
);
ss._removeObservers();
- updateConfig(CONFIG_DEFAULT);
+ await updateConfig("test-extensions");
+
ss = await startup();
Assert.ok(
diff --git a/toolkit/components/search/tests/xpcshell/test_sort_orders-no-hints.js b/toolkit/components/search/tests/xpcshell/test_sort_orders-no-hints.js
index d2a2d7dd93..cb7e314fd4 100644
--- a/toolkit/components/search/tests/xpcshell/test_sort_orders-no-hints.js
+++ b/toolkit/components/search/tests/xpcshell/test_sort_orders-no-hints.js
@@ -15,7 +15,13 @@ add_setup(async function () {
"data",
null,
(
- await readJSONFile(do_get_file("data/engines-no-order-hint.json"))
+ await readJSONFile(
+ do_get_file(
+ SearchUtils.newSearchConfigEnabled
+ ? "data/search-config-v2-no-order-hint.json"
+ : "data/engines-no-order-hint.json"
+ )
+ )
).data
);
diff --git a/toolkit/components/search/tests/xpcshell/test_telemetry_event_default.js b/toolkit/components/search/tests/xpcshell/test_telemetry_event_default.js
index 84bd1be9cc..f1b6208326 100644
--- a/toolkit/components/search/tests/xpcshell/test_telemetry_event_default.js
+++ b/toolkit/components/search/tests/xpcshell/test_telemetry_event_default.js
@@ -45,6 +45,49 @@ const BASE_CONFIG = [
default: "yes",
},
];
+
+const BASE_CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine",
+ specificDefaults: [],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
const MAIN_CONFIG = [
{
webExtension: {
@@ -78,7 +121,6 @@ const MAIN_CONFIG = [
{
webExtension: {
id: "engine-chromeicon@search.mozilla.org",
-
name: "engine-chromeicon",
search_url: "https://www.google.com/search",
params: [
@@ -163,6 +205,154 @@ const MAIN_CONFIG = [
},
];
+const MAIN_CONFIG_V2 = [
+ {
+ recordType: "engine",
+ identifier: "engine",
+ base: {
+ name: "Test search engine",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "channel",
+ searchAccessPoint: {
+ addressbar: "fflb",
+ contextmenu: "rcs",
+ },
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ suggestions: {
+ base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-chromeicon",
+ base: {
+ name: "engine-chromeicon",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-fr",
+ base: {
+ name: "Test search engine (fr)",
+ urls: {
+ search: {
+ base: "https://www.google.fr/search",
+ params: [
+ {
+ name: "ie",
+ value: "iso-8859-1",
+ },
+ {
+ name: "oe",
+ value: "iso-8859-1",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine-pref",
+ base: {
+ name: "engine-pref",
+ urls: {
+ search: {
+ base: "https://www.google.com/search",
+ params: [
+ {
+ name: "code",
+ experimentConfig: "code",
+ },
+ {
+ name: "test",
+ experimentConfig: "test",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "engine",
+ identifier: "engine2",
+ base: {
+ name: "A second test engine",
+ urls: {
+ search: {
+ base: "https://duckduckgo.com/",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ },
+ {
+ recordType: "defaultEngines",
+ globalDefault: "engine-chromeicon",
+ specificDefaults: [
+ {
+ default: "engine-fr",
+ environment: { excludedRegions: ["DE"], locales: ["fr"] },
+ },
+ {
+ default: "engine-pref",
+ environment: { regions: ["DE"] },
+ },
+ {
+ default: "engine2",
+ environment: { experiment: "test1" },
+ },
+ ],
+ },
+ {
+ recordType: "engineOrders",
+ orders: [],
+ },
+];
+
const testSearchEngine = {
id: "engine",
name: "Test search engine",
@@ -186,7 +376,9 @@ const testFrEngine = {
loadPath: SearchUtils.newSearchConfigEnabled
? "[app]engine-fr@search.mozilla.org"
: "[addon]engine-fr@search.mozilla.org",
- submissionURL: "https://www.google.fr/search?q=&ie=iso-8859-1&oe=iso-8859-1",
+ submissionURL: SearchUtils.newSearchConfigEnabled
+ ? "https://www.google.fr/search?ie=iso-8859-1&oe=iso-8859-1&q="
+ : "https://www.google.fr/search?q=&ie=iso-8859-1&oe=iso-8859-1",
};
const testPrefEngine = {
id: "engine-pref",
@@ -335,7 +527,11 @@ add_setup(async () => {
"_showRemovalOfSearchEngineNotificationBox"
);
- await SearchTestUtils.useTestEngines("data", null, BASE_CONFIG);
+ await SearchTestUtils.useTestEngines(
+ "data",
+ null,
+ SearchUtils.newSearchConfigEnabled ? BASE_CONFIG_V2 : BASE_CONFIG
+ );
await AddonTestUtils.promiseStartupManager();
await Services.search.init();
@@ -344,7 +540,9 @@ add_setup(async () => {
add_task(async function test_configuration_changes_default() {
clearTelemetry();
- await SearchTestUtils.updateRemoteSettingsConfig(MAIN_CONFIG);
+ await SearchTestUtils.updateRemoteSettingsConfig(
+ SearchUtils.newSearchConfigEnabled ? MAIN_CONFIG_V2 : MAIN_CONFIG
+ );
await checkTelemetry(
"config",
diff --git a/toolkit/components/search/tests/xpcshell/test_validate_engines.js b/toolkit/components/search/tests/xpcshell/test_validate_engines.js
index 8a25216057..d311253183 100644
--- a/toolkit/components/search/tests/xpcshell/test_validate_engines.js
+++ b/toolkit/components/search/tests/xpcshell/test_validate_engines.js
@@ -15,18 +15,52 @@ const ss = new SearchService();
add_task(async function test_validate_engines() {
let settings = RemoteSettings(SearchUtils.SETTINGS_KEY);
let config = await settings.get();
- config = config.map(e => {
- return {
- appliesTo: [
- {
- included: {
- everywhere: true,
+
+ if (SearchUtils.newSearchConfigEnabled) {
+ // We do not load engines with the same name. However, in search-config-v2
+ // we have multiple engines named eBay, so we error out.
+ // We never deploy more than one eBay in each environment so this issue
+ // won't be a problem.
+ // Ignore the error and test the configs can be created to engine objects.
+ consoleAllowList.push("Could not load engine");
+ config = config.map(obj => {
+ if (obj.recordType == "engine") {
+ return {
+ recordType: "engine",
+ identifier: obj.identifier,
+ base: {
+ name: obj.base.name,
+ urls: {
+ search: {
+ base: obj.base.urls.search.base || "",
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: { allRegionsAndLocales: true },
+ },
+ ],
+ };
+ }
+
+ return obj;
+ });
+ } else {
+ config = config.map(e => {
+ return {
+ appliesTo: [
+ {
+ included: {
+ everywhere: true,
+ },
},
- },
- ],
- webExtension: e.webExtension,
- };
- });
+ ],
+ webExtension: e.webExtension,
+ };
+ });
+ }
sinon.stub(settings, "get").returns(config);
await AddonTestUtils.promiseStartupManager();
diff --git a/toolkit/components/search/tests/xpcshell/test_webextensions_install.js b/toolkit/components/search/tests/xpcshell/test_webextensions_install.js
index 6183d6f95a..a05218824a 100644
--- a/toolkit/components/search/tests/xpcshell/test_webextensions_install.js
+++ b/toolkit/components/search/tests/xpcshell/test_webextensions_install.js
@@ -80,7 +80,9 @@ add_task(async function test_install_duplicate_engine() {
let submission = engine.getSubmission("foo");
Assert.equal(
submission.uri.spec,
- "https://duckduckgo.com/?q=foo&t=ffsb",
+ SearchUtils.newSearchConfigEnabled
+ ? "https://duckduckgo.com/?t=ffsb&q=foo"
+ : "https://duckduckgo.com/?q=foo&t=ffsb",
"Should have not changed the app provided engine."
);
@@ -127,7 +129,7 @@ add_task(
let engine = await Services.search.getEngineByName("Multilocale AN");
Assert.ok(
- engine.getIconURL().endsWith("favicon-an.ico"),
+ (await engine.getIconURL()).endsWith("favicon-an.ico"),
"Should have the correct favicon for an extension of one locale using a different locale."
);
Assert.equal(
@@ -156,7 +158,11 @@ add_task(async function test_load_favicon_invalid() {
await observed;
let engine = await Services.search.getEngineByName("Example");
- Assert.equal(null, engine.getIconURL(), "Should not have set an iconURI");
+ Assert.equal(
+ null,
+ await engine.getIconURL(),
+ "Should not have set an iconURI"
+ );
// User uninstalls their engine
await extension.awaitStartup();
@@ -182,7 +188,11 @@ add_task(async function test_load_favicon_invalid_redirect() {
await observed;
let engine = await Services.search.getEngineByName("Example");
- Assert.equal(null, engine.getIconURL(), "Should not have set an iconURI");
+ Assert.equal(
+ null,
+ await engine.getIconURL(),
+ "Should not have set an iconURI"
+ );
// User uninstalls their engine
await extension.awaitStartup();
@@ -208,9 +218,9 @@ add_task(async function test_load_favicon_redirect() {
await promiseEngineChanged;
- Assert.ok(engine.getIconURL(), "Should have set an iconURI");
+ Assert.ok(await engine.getIconURL(), "Should have set an iconURI");
Assert.ok(
- engine.getIconURL().startsWith("data:image/x-icon;base64,"),
+ (await engine.getIconURL()).startsWith("data:image/x-icon;base64,"),
"Should have saved the expected content type for the icon"
);
diff --git a/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
index 3e42fdee13..eb7e67e66e 100644
--- a/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
+++ b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
@@ -27,7 +27,7 @@ add_task(async function test_install_duplicate_engine_startup() {
let name = "Plain";
let id = "plain@tests.mozilla.org";
consoleAllowList.push(
- `#installExtensionEngine failed for ${id}`,
+ `#createAndAddAddonEngine failed for ${id}`,
`An engine called ${name} already exists`
);
// Do not use SearchTestUtils.installSearchExtension, as we need to manually
@@ -51,7 +51,9 @@ add_task(async function test_install_duplicate_engine_startup() {
let submission = engine.getSubmission("foo");
Assert.equal(
submission.uri.spec,
- "https://duckduckgo.com/?q=foo&t=ffsb",
+ SearchUtils.newSearchConfigEnabled
+ ? "https://duckduckgo.com/?t=ffsb&q=foo"
+ : "https://duckduckgo.com/?q=foo&t=ffsb",
"Should have not changed the app provided engine."
);
diff --git a/toolkit/components/search/tests/xpcshell/xpcshell.toml b/toolkit/components/search/tests/xpcshell/xpcshell.toml
index 47847c93de..7dd023cbec 100644
--- a/toolkit/components/search/tests/xpcshell/xpcshell.toml
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.toml
@@ -33,6 +33,8 @@ support-files = [
"data/engine-same-name/_locales/gd/messages.json",
"data/engines-no-order-hint.json",
"data/engines.json",
+ "data/search-config-v2.json",
+ "data/search-config-v2-no-order-hint.json",
"data/iconsRedirect.sjs",
"data/search.json",
"data/search-legacy.json",
@@ -60,6 +62,7 @@ support-files = [
"simple-engines/basic/manifest.json",
"simple-engines/simple/manifest.json",
"test-extensions/engines.json",
+ "test-extensions/search-config-v2.json",
"test-extensions/plainengine/favicon.ico",
"test-extensions/plainengine/manifest.json",
"test-extensions/special-engine/favicon.ico",
@@ -75,6 +78,9 @@ support-files = [
["test_appDefaultEngine.js"]
+["test_appProvided_icons.js"]
+prefs = ["browser.search.newSearchConfig.enabled=true"]
+
["test_async.js"]
["test_config_engine_params.js"]
@@ -82,6 +88,7 @@ support-files = [
"method-extensions/get/manifest.json",
"method-extensions/post/manifest.json",
"method-extensions/engines.json",
+ "method-extensions/search-config-v2.json",
]
["test_defaultEngine.js"]
@@ -110,15 +117,15 @@ support-files = [
["test_engine_old_selector_override.js"]
+["test_engine_old_selector_remote_override.js"]
+
["test_engine_old_selector_remote_settings.js"]
tags = "remotesettings searchmain"
-["test_engine_old_selector_remote_override.js"]
+["test_engine_selector_defaults.js"]
["test_engine_selector_engine_orders.js"]
-["test_engine_selector_defaults.js"]
-
["test_engine_selector_environment.js"]
["test_engine_selector_variants.js"]