mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1870138 - Add remote settings support for search overrides. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D196490
This commit is contained in:
parent
e0933655b5
commit
05f593b0cc
@ -10,6 +10,17 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
|
||||
});
|
||||
|
||||
// `contextId` is a unique identifier used by Contextual Services
|
||||
const CONTEXT_ID_PREF = "browser.contextual-services.contextId";
|
||||
ChromeUtils.defineLazyGetter(lazy, "contextId", () => {
|
||||
let _contextId = Services.prefs.getStringPref(CONTEXT_ID_PREF, null);
|
||||
if (!_contextId) {
|
||||
_contextId = Services.uuid.generateUUID().toString();
|
||||
Services.prefs.setStringPref(CONTEXT_ID_PREF, _contextId);
|
||||
}
|
||||
return _contextId;
|
||||
});
|
||||
|
||||
// A map of known search origins.
|
||||
// The keys of this map are used in the calling code to recordSearch, and in
|
||||
// the SEARCH_COUNTS histogram.
|
||||
@ -171,6 +182,10 @@ class BrowserSearchTelemetryHandler {
|
||||
* @throws if source is not in the known sources list.
|
||||
*/
|
||||
recordSearch(browser, engine, source, details = {}) {
|
||||
if (engine.clickUrl) {
|
||||
this.#reportSearchInGlean(engine.clickUrl);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!this.shouldRecordSearchCount(browser)) {
|
||||
return;
|
||||
@ -281,6 +296,33 @@ class BrowserSearchTelemetryHandler {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the search in Glean for contextual services.
|
||||
*
|
||||
* @param {string} reportingUrl
|
||||
* The url to be sent to contextual services.
|
||||
*/
|
||||
#reportSearchInGlean(reportingUrl) {
|
||||
let defaultValuesByGleanKey = {
|
||||
contextId: lazy.contextId,
|
||||
};
|
||||
|
||||
let sendGleanPing = valuesByGleanKey => {
|
||||
valuesByGleanKey = { ...defaultValuesByGleanKey, ...valuesByGleanKey };
|
||||
for (let [gleanKey, value] of Object.entries(valuesByGleanKey)) {
|
||||
let glean = Glean.searchWith[gleanKey];
|
||||
if (value !== undefined && value !== "") {
|
||||
glean.set(value);
|
||||
}
|
||||
}
|
||||
GleanPings.searchWith.submit();
|
||||
};
|
||||
|
||||
sendGleanPing({
|
||||
reportingUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export var BrowserSearchTelemetry = new BrowserSearchTelemetryHandler();
|
||||
|
@ -318,3 +318,38 @@ serp:
|
||||
notification_emails:
|
||||
- fx-search-telemetry@mozilla.com
|
||||
expires: never
|
||||
|
||||
search_with:
|
||||
reporting_url:
|
||||
type: url
|
||||
description: >
|
||||
The external url to report this interaction to.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138
|
||||
data_sensitivity:
|
||||
- web_activity
|
||||
notification_emails:
|
||||
- mkaply@mozilla.com
|
||||
expires: never
|
||||
send_in_pings:
|
||||
- search-with
|
||||
|
||||
context_id:
|
||||
type: uuid
|
||||
description: >
|
||||
An identifier for Contextual Services user interaction pings. This is
|
||||
used internally for counting unique users as well as for anti-fraud. It
|
||||
is shared with other Contextual Services. It is not shared externally.
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138#c3
|
||||
data_sensitivity:
|
||||
- technical
|
||||
notification_emails:
|
||||
- mkaply@mozilla.com
|
||||
expires: never
|
||||
send_in_pings:
|
||||
- search-with
|
||||
|
22
browser/components/search/pings.yaml
Normal file
22
browser/components/search/pings.yaml
Normal file
@ -0,0 +1,22 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
---
|
||||
$schema: moz://mozilla.org/schemas/glean/pings/2-0-0
|
||||
|
||||
search-with:
|
||||
description: |
|
||||
A ping representing a "This time, search with" event with a partner search.
|
||||
Does not contain a `client_id`, preferring a `context_id` instead.
|
||||
The `context_id` is used internally for counting unique sers as well as for
|
||||
anti-fraud. It is shared with other Contextual Services. It is not shared
|
||||
externally.
|
||||
|
||||
include_client_id: false
|
||||
bugs:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1870138
|
||||
notification_emails:
|
||||
- mkaply@mozilla.com
|
@ -12,6 +12,8 @@ FINAL_TARGET_FILES.defaults.settings.main += [
|
||||
"language-dictionaries.json",
|
||||
"password-recipes.json",
|
||||
"password-rules.json",
|
||||
"search-config-overrides-v2.json",
|
||||
"search-config-overrides.json",
|
||||
"search-config-v2.json",
|
||||
"search-config.json",
|
||||
"search-default-override-allowlist.json",
|
||||
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"data": [],
|
||||
"timestamp": 1704379586890
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"data": [],
|
||||
"timestamp": 1704379586619
|
||||
}
|
@ -113,6 +113,7 @@ gecko_pings = [
|
||||
firefox_desktop_pings = [
|
||||
"browser/components/newtab/pings.yaml",
|
||||
"browser/components/pocket/pings.yaml",
|
||||
"browser/components/search/pings.yaml",
|
||||
"browser/components/urlbar/pings.yaml",
|
||||
"toolkit/components/crashes/pings.yaml",
|
||||
"toolkit/components/telemetry/pings.yaml",
|
||||
|
@ -1008,6 +1008,10 @@ export class SearchEngine {
|
||||
this._urls.push(trending);
|
||||
}
|
||||
|
||||
if (configuration.clickUrl) {
|
||||
this.clickUrl = configuration.clickUrl;
|
||||
}
|
||||
|
||||
if (details.encoding) {
|
||||
this._queryCharset = details.encoding;
|
||||
}
|
||||
|
@ -28,8 +28,13 @@ export class SearchEngineSelector {
|
||||
*/
|
||||
constructor(listener) {
|
||||
this._remoteConfig = lazy.RemoteSettings(lazy.SearchUtils.NEW_SETTINGS_KEY);
|
||||
this._remoteConfigOverrides = lazy.RemoteSettings(
|
||||
lazy.SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
this._listenerAdded = false;
|
||||
this._onConfigurationUpdated = this._onConfigurationUpdated.bind(this);
|
||||
this._onConfigurationOverridesUpdated =
|
||||
this._onConfigurationOverridesUpdated.bind(this);
|
||||
this._changeListener = listener;
|
||||
}
|
||||
|
||||
@ -41,8 +46,13 @@ export class SearchEngineSelector {
|
||||
return this._getConfigurationPromise;
|
||||
}
|
||||
|
||||
this._configuration = await (this._getConfigurationPromise =
|
||||
this._getConfiguration());
|
||||
this._getConfigurationPromise = Promise.all([
|
||||
this._getConfiguration(),
|
||||
this._getConfigurationOverrides(),
|
||||
]);
|
||||
let remoteSettingsData = await this._getConfigurationPromise;
|
||||
this._configuration = remoteSettingsData[0];
|
||||
this._configurationOverrides = remoteSettingsData[1];
|
||||
delete this._getConfigurationPromise;
|
||||
|
||||
if (!this._configuration?.length) {
|
||||
@ -54,12 +64,24 @@ export class SearchEngineSelector {
|
||||
|
||||
if (!this._listenerAdded) {
|
||||
this._remoteConfig.on("sync", this._onConfigurationUpdated);
|
||||
this._remoteConfigOverrides.on(
|
||||
"sync",
|
||||
this._onConfigurationOverridesUpdated
|
||||
);
|
||||
this._listenerAdded = true;
|
||||
}
|
||||
|
||||
return this._configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by tests to get the configuration overrides.
|
||||
*/
|
||||
async getEngineConfigurationOverrides() {
|
||||
await this.getEngineConfiguration();
|
||||
return this._configurationOverrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration from remote settings. This includes
|
||||
* verifying the signature of the record within the database.
|
||||
@ -119,6 +141,42 @@ export class SearchEngineSelector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles updating of the configuration. Note that the search service is
|
||||
* only updated after a period where the user is observed to be idle.
|
||||
*
|
||||
* @param {object} options
|
||||
* The options object
|
||||
* @param {object} options.data
|
||||
* The data to update
|
||||
* @param {Array} options.data.current
|
||||
* The new configuration object
|
||||
*/
|
||||
_onConfigurationOverridesUpdated({ data: { current } }) {
|
||||
this._configurationOverrides = current;
|
||||
lazy.logConsole.debug("Search configuration overrides updated remotely");
|
||||
if (this._changeListener) {
|
||||
this._changeListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration overrides from remote settings.
|
||||
*
|
||||
* @returns {Array}
|
||||
* An array of objects in the database, or an empty array if none
|
||||
* could be obtained.
|
||||
*/
|
||||
async _getConfigurationOverrides() {
|
||||
let result = [];
|
||||
try {
|
||||
result = await this._remoteConfigOverrides.get();
|
||||
} catch (ex) {
|
||||
// This data is remote only, so we just return an empty array if it fails.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
* The options object
|
||||
@ -205,6 +263,12 @@ export class SearchEngineSelector {
|
||||
engine = this.#deepCopyObject(engine, variant);
|
||||
}
|
||||
|
||||
for (let override of this._configurationOverrides) {
|
||||
if (override.identifier == engine.identifier) {
|
||||
engine = this.#deepCopyObject(engine, override);
|
||||
}
|
||||
}
|
||||
|
||||
engines.push(engine);
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,13 @@ export class SearchEngineSelectorOld {
|
||||
constructor(listener) {
|
||||
this.QueryInterface = ChromeUtils.generateQI(["nsIObserver"]);
|
||||
this._remoteConfig = lazy.RemoteSettings(lazy.SearchUtils.OLD_SETTINGS_KEY);
|
||||
this._remoteConfigOverrides = lazy.RemoteSettings(
|
||||
lazy.SearchUtils.OLD_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
this._listenerAdded = false;
|
||||
this._onConfigurationUpdated = this._onConfigurationUpdated.bind(this);
|
||||
this._onConfigurationOverridesUpdated =
|
||||
this._onConfigurationOverridesUpdated.bind(this);
|
||||
this._changeListener = listener;
|
||||
}
|
||||
|
||||
@ -86,8 +91,13 @@ export class SearchEngineSelectorOld {
|
||||
return this._getConfigurationPromise;
|
||||
}
|
||||
|
||||
this._configuration = await (this._getConfigurationPromise =
|
||||
this._getConfiguration());
|
||||
this._getConfigurationPromise = Promise.all([
|
||||
this._getConfiguration(),
|
||||
this._getConfigurationOverrides(),
|
||||
]);
|
||||
let remoteSettingsData = await this._getConfigurationPromise;
|
||||
this._configuration = remoteSettingsData[0];
|
||||
this._configurationOverrides = remoteSettingsData[1];
|
||||
delete this._getConfigurationPromise;
|
||||
|
||||
if (!this._configuration?.length) {
|
||||
@ -99,12 +109,24 @@ export class SearchEngineSelectorOld {
|
||||
|
||||
if (!this._listenerAdded) {
|
||||
this._remoteConfig.on("sync", this._onConfigurationUpdated);
|
||||
this._remoteConfigOverrides.on(
|
||||
"sync",
|
||||
this._onConfigurationOverridesUpdated
|
||||
);
|
||||
this._listenerAdded = true;
|
||||
}
|
||||
|
||||
return this._configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by tests to get the configuration overrides.
|
||||
*/
|
||||
async getEngineConfigurationOverrides() {
|
||||
await this.getEngineConfiguration();
|
||||
return this._configurationOverrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration from remote settings. This includes
|
||||
* verifying the signature of the record within the database.
|
||||
@ -164,6 +186,42 @@ export class SearchEngineSelectorOld {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles updating of the configuration. Note that the search service is
|
||||
* only updated after a period where the user is observed to be idle.
|
||||
*
|
||||
* @param {object} options
|
||||
* The options object
|
||||
* @param {object} options.data
|
||||
* The data to update
|
||||
* @param {Array} options.data.current
|
||||
* The new configuration object
|
||||
*/
|
||||
_onConfigurationOverridesUpdated({ data: { current } }) {
|
||||
this._configurationOverrides = current;
|
||||
lazy.logConsole.debug("Search configuration overrides updated remotely");
|
||||
if (this._changeListener) {
|
||||
this._changeListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration overrides from remote settings.
|
||||
*
|
||||
* @returns {Array}
|
||||
* An array of objects in the database, or an empty array if none
|
||||
* could be obtained.
|
||||
*/
|
||||
async _getConfigurationOverrides() {
|
||||
let result = [];
|
||||
try {
|
||||
result = await this._remoteConfigOverrides.get();
|
||||
} catch (ex) {
|
||||
// This data is remote only, so we just return an empty array if it fails.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
* The options object
|
||||
@ -314,6 +372,22 @@ export class SearchEngineSelectorOld {
|
||||
) {
|
||||
defaultEngine = engine;
|
||||
}
|
||||
if (engine.telemetryId) {
|
||||
for (let override of this._configurationOverrides) {
|
||||
if (override.telemetryId == engine.telemetryId) {
|
||||
engine.params = this._copyObject(
|
||||
engine.params || {},
|
||||
override.params
|
||||
);
|
||||
if (override.clickUrl) {
|
||||
engine.clickUrl = override.clickUrl;
|
||||
}
|
||||
if (override.telemetrySuffix) {
|
||||
engine.telemetryId += `-${override.telemetrySuffix}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
"defaultPrivate" in engine &&
|
||||
shouldPrefer(
|
||||
@ -387,7 +461,7 @@ export class SearchEngineSelectorOld {
|
||||
* Object.assign but ignore some keys
|
||||
*
|
||||
* @param {object} target - Object to copy to.
|
||||
* @param {object} source - Object top copy from.
|
||||
* @param {object} source - Object to copy from.
|
||||
* @returns {object} - The source object.
|
||||
*/
|
||||
_copyObject(target, source) {
|
||||
|
@ -139,6 +139,20 @@ export var SearchUtils = {
|
||||
*/
|
||||
NEW_SETTINGS_KEY: "search-config-v2",
|
||||
|
||||
/**
|
||||
* This is the Remote Settings key for getting the overrides for the
|
||||
* older search engine configuration. Tests may use `SETTINGS_OVERRIDES_KEY`
|
||||
* for the current configuration according to the preference.
|
||||
*/
|
||||
OLD_SETTINGS_OVERRIDES_KEY: "search-config-overrides",
|
||||
|
||||
/**
|
||||
* This is the Remote Settings key for getting the overrides for the
|
||||
* newer search engine configuration. Tests may use `SETTINGS_OVERRIDES_KEY`
|
||||
* for the current configuration according to the preference.
|
||||
*/
|
||||
NEW_SETTINGS_OVERRIDES_KEY: "search-config-overrides-v2",
|
||||
|
||||
/**
|
||||
* This is the Remote Settings key that we use to get the search engine
|
||||
* configurations.
|
||||
@ -151,6 +165,18 @@ export var SearchUtils = {
|
||||
: SearchUtils.OLD_SETTINGS_KEY;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is the Remote Settings key that we use to get the search engine
|
||||
* configuration overrides.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
get SETTINGS_OVERRIDES_KEY() {
|
||||
return SearchUtils.newSearchConfigEnabled
|
||||
? SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
: SearchUtils.OLD_SETTINGS_OVERRIDES_KEY;
|
||||
},
|
||||
|
||||
/**
|
||||
* Topic used for events involving the service itself.
|
||||
*/
|
||||
|
@ -199,12 +199,18 @@ interface nsISearchEngine : nsISupports
|
||||
readonly attribute boolean isGeneralPurposeEngine;
|
||||
|
||||
/**
|
||||
* The domain from which search results are returned for this engine.
|
||||
*
|
||||
* @return the domain of the the search URL.
|
||||
*/
|
||||
readonly attribute AString searchUrlDomain;
|
||||
* The domain from which search results are returned for this engine.
|
||||
*
|
||||
* @return the domain of the the search URL.
|
||||
*/
|
||||
readonly attribute AString searchUrlDomain;
|
||||
|
||||
/**
|
||||
* The URL to report the search to.
|
||||
*
|
||||
* @return the reporting URL.
|
||||
*/
|
||||
readonly attribute AString clickUrl;
|
||||
};
|
||||
|
||||
[scriptable, uuid(0dc93e51-a7bf-4a16-862d-4b3469ff6206)]
|
||||
|
@ -0,0 +1,64 @@
|
||||
{
|
||||
"title": "Search Engine Overrides Schema",
|
||||
"description": "This schema contains the details for overriding application provided search engines defined in search-config. The associated remote settings collection is search-config-overrides.",
|
||||
"type": "object",
|
||||
"required": ["telemetryId"],
|
||||
"properties": {
|
||||
"telemetryId": {
|
||||
"type": "string",
|
||||
"title": "Telemetry Id",
|
||||
"description": "The telemetry Id used to match the engine that this record will override.",
|
||||
"pattern": "^[a-zA-Z0-9-$_]{0,100}$"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/params"
|
||||
},
|
||||
"clickUrl": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "The url used to for reporting clicks."
|
||||
},
|
||||
"telemetrySuffix": {
|
||||
"type": "string",
|
||||
"title": "Telemetry Suffix",
|
||||
"description": "Suffix that is appended to the search engine identifier following a dash, i.e. `<identifier>-<suffix>`.",
|
||||
"pattern": "^[a-zA-Z0-9-]*$"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"searchUrlCodes": {
|
||||
"type": "array",
|
||||
"title": "Codes",
|
||||
"description": "A array of objects - map of parameter name to the parameter value.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name",
|
||||
"pattern": "^[a-zA-Z0-9.-]{0,100}$",
|
||||
"description": "Name of the parameter that will be used in the query"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"title": "Value",
|
||||
"pattern": "^[a-zA-Z0-9_{}:/.-]{0,100}$",
|
||||
"description": "The value of parameter (pref or purpose)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"type": "object",
|
||||
"title": "Parameters",
|
||||
"description": "Various parameters for the search engines",
|
||||
"properties": {
|
||||
"searchUrlGetParams": {
|
||||
"title": "Search URL GET Parameters",
|
||||
"description": "Extra parameters for search URLs (e.g. 'pc=foo').",
|
||||
"$ref": "#/definitions/searchUrlCodes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
{
|
||||
"title": "Search Engine Overrides Schema",
|
||||
"description": "This schema contains the details for overriding application provided search engines defined in search-config-v2. The associated remote settings collection is search-config-overrides-v2.",
|
||||
"definitions": {
|
||||
"partnerCode": {
|
||||
"title": "Partner Code",
|
||||
"description": "The partner code for the engine or variant. This will be inserted into parameters which include '{partnerCode}'",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-_]*$"
|
||||
},
|
||||
"urls": {
|
||||
"title": "URLs",
|
||||
"description": "The URLs associated with the search engine.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"search": {
|
||||
"title": "Search URL",
|
||||
"description": "The URL to use for searches",
|
||||
"$ref": "#/definitions/url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"base": {
|
||||
"title": "Base",
|
||||
"description": "The PrePath and FilePath of the URL. May include variables for engines which have a variable FilePath, e.g. {searchTerm} for when a search term is within the path of the url.",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"title": "Parameters",
|
||||
"description": "The parameters for this URL.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"title": "Parameter",
|
||||
"properties": {
|
||||
"name": {
|
||||
"title": "Name",
|
||||
"description": "The parameter name",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-_]*$"
|
||||
},
|
||||
"value": {
|
||||
"title": "Value",
|
||||
"description": "The parameter value, this may be a static value, or additionally contain a parameter replacement, e.g. {inputEncoding}. For the partner code parameter, this field should be {pc}.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-_{}]*$"
|
||||
}
|
||||
},
|
||||
"required": ["name", "value"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"title": "Identifier",
|
||||
"description": "This is the identifier of the search engine in search-config-v2 that this record will override. It may be extended by telemetrySuffix.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-_]*$"
|
||||
},
|
||||
"partnerCode": {
|
||||
"$ref": "#/definitions/partnerCode"
|
||||
},
|
||||
"telemetrySuffix": {
|
||||
"title": "Telemetry Suffix",
|
||||
"description": "Suffix that is appended to the search engine identifier following a dash, i.e. `<identifier>-<suffix>`. There should always be a suffix supplied if the partner code is different.",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z0-9-]*$"
|
||||
},
|
||||
"urls": {
|
||||
"$ref": "#/definitions/urls"
|
||||
}
|
||||
}
|
||||
}
|
@ -103,6 +103,29 @@ async function checkSearchConfigValidates(schema, searchConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
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_task(async function test_search_config_validates_to_schema_v1() {
|
||||
let selector = new SearchEngineSelectorOld(() => {});
|
||||
let searchConfig = await selector.getEngineConfiguration();
|
||||
@ -118,6 +141,19 @@ add_task(async function test_ui_schema_valid_v1() {
|
||||
await checkUISchemaValid(searchConfigSchemaV1, uiSchema);
|
||||
});
|
||||
|
||||
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
|
||||
);
|
||||
});
|
||||
|
||||
if (SearchUtils.newSearchConfigEnabled) {
|
||||
add_task(async function test_search_config_validates_to_schema() {
|
||||
delete SearchUtils.newSearchConfigEnabled;
|
||||
@ -136,4 +172,21 @@ if (SearchUtils.newSearchConfigEnabled) {
|
||||
|
||||
await checkUISchemaValid(searchConfigSchema, uiSchema);
|
||||
});
|
||||
|
||||
add_task(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
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ requesttimeoutfactor = 2
|
||||
|
||||
["test_searchconfig_validates.js"]
|
||||
support-files = [
|
||||
"../../../schema/search-config-overrides-schema.json",
|
||||
"../../../schema/search-config-overrides-v2-schema.json",
|
||||
"../../../schema/search-config-schema.json",
|
||||
"../../../schema/search-config-ui-schema.json",
|
||||
"../../../schema/search-config-v2-schema.json",
|
||||
|
@ -174,7 +174,9 @@ const CONFIG_DEFAULTS_OVERRIDE = [
|
||||
|
||||
const engineSelector = new SearchEngineSelector();
|
||||
let settings;
|
||||
let settingOverrides;
|
||||
let configStub;
|
||||
let overrideStub;
|
||||
|
||||
/**
|
||||
* This function asserts if the actual engine identifiers returned equals
|
||||
@ -222,6 +224,11 @@ async function assertActualEnginesEqualsExpected(
|
||||
add_setup(async function () {
|
||||
settings = await RemoteSettings(SearchUtils.NEW_SETTINGS_KEY);
|
||||
configStub = sinon.stub(settings, "get");
|
||||
settingOverrides = await RemoteSettings(
|
||||
SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
overrideStub = sinon.stub(settingOverrides, "get");
|
||||
overrideStub.returns([]);
|
||||
});
|
||||
|
||||
add_task(async function test_default_engines() {
|
||||
|
@ -225,7 +225,9 @@ const DEFAULTS_CONFIG = [
|
||||
|
||||
const engineSelector = new SearchEngineSelector();
|
||||
let settings;
|
||||
let settingOverrides;
|
||||
let configStub;
|
||||
let overrideStub;
|
||||
|
||||
/**
|
||||
* This function asserts if the actual engine identifiers returned equals
|
||||
@ -259,6 +261,11 @@ async function assertActualEnginesEqualsExpected(
|
||||
add_setup(async function () {
|
||||
settings = await RemoteSettings(SearchUtils.NEW_SETTINGS_KEY);
|
||||
configStub = sinon.stub(settings, "get");
|
||||
settingOverrides = await RemoteSettings(
|
||||
SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
overrideStub = sinon.stub(settingOverrides, "get");
|
||||
overrideStub.returns([]);
|
||||
});
|
||||
|
||||
add_task(async function test_selector_match_engine_orders() {
|
||||
|
@ -338,7 +338,9 @@ const CONFIG_VERSIONS = [
|
||||
|
||||
const engineSelector = new SearchEngineSelector();
|
||||
let settings;
|
||||
let settingOverrides;
|
||||
let configStub;
|
||||
let overrideStub;
|
||||
|
||||
/**
|
||||
* This function asserts if the actual engine identifiers returned equals
|
||||
@ -370,6 +372,11 @@ async function assertActualEnginesEqualsExpected(
|
||||
add_setup(async function () {
|
||||
settings = await RemoteSettings(SearchUtils.NEW_SETTINGS_KEY);
|
||||
configStub = sinon.stub(settings, "get");
|
||||
settingOverrides = await RemoteSettings(
|
||||
SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
overrideStub = sinon.stub(settingOverrides, "get");
|
||||
overrideStub.returns([]);
|
||||
});
|
||||
|
||||
add_task(async function test_selector_match_experiment() {
|
||||
|
@ -0,0 +1,135 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
SearchEngineSelectorOld:
|
||||
"resource://gre/modules/SearchEngineSelectorOld.sys.mjs",
|
||||
SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.sys.mjs",
|
||||
});
|
||||
|
||||
const TEST_CONFIG_OLD = [
|
||||
{
|
||||
engineName: "aol",
|
||||
telemetryId: "aol",
|
||||
appliesTo: [
|
||||
{
|
||||
included: { everywhere: true },
|
||||
},
|
||||
],
|
||||
params: {
|
||||
searchUrlGetParams: [
|
||||
{
|
||||
name: "original_param",
|
||||
value: "original_value",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_CONFIG_OVERRIDE_OLD = [
|
||||
{
|
||||
telemetryId: "aol",
|
||||
telemetrySuffix: "tsfx",
|
||||
params: {
|
||||
searchUrlGetParams: [
|
||||
{
|
||||
name: "new_param",
|
||||
value: "new_value",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_CONFIG = [
|
||||
{
|
||||
base: {
|
||||
urls: {
|
||||
search: {
|
||||
base: "https://www.bing.com/search",
|
||||
params: [
|
||||
{
|
||||
name: "old_param",
|
||||
value: "old_value",
|
||||
},
|
||||
],
|
||||
searchTermParamName: "q",
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: [
|
||||
{
|
||||
environment: {
|
||||
locales: ["en-US"],
|
||||
},
|
||||
},
|
||||
],
|
||||
identifier: "aol",
|
||||
recordType: "engine",
|
||||
},
|
||||
{
|
||||
recordType: "defaultEngines",
|
||||
globalDefault: "aol",
|
||||
specificDefaults: [],
|
||||
},
|
||||
{
|
||||
orders: [],
|
||||
recordType: "engineOrders",
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_CONFIG_OVERRIDE = [
|
||||
{
|
||||
identifier: "aol",
|
||||
urls: {
|
||||
search: {
|
||||
params: [{ name: "new_param", value: "new_value" }],
|
||||
},
|
||||
},
|
||||
telemetrySuffix: "tsfx",
|
||||
clickUrl: "https://aol.url",
|
||||
},
|
||||
];
|
||||
|
||||
const engineSelectorOld = new SearchEngineSelectorOld();
|
||||
const engineSelector = new SearchEngineSelector();
|
||||
|
||||
add_setup(async function () {
|
||||
const settingsOld = await RemoteSettings(SearchUtils.OLD_SETTINGS_KEY);
|
||||
sinon.stub(settingsOld, "get").returns(TEST_CONFIG_OLD);
|
||||
const overridesOld = await RemoteSettings(
|
||||
SearchUtils.OLD_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
sinon.stub(overridesOld, "get").returns(TEST_CONFIG_OVERRIDE_OLD);
|
||||
|
||||
const settings = await RemoteSettings(SearchUtils.NEW_SETTINGS_KEY);
|
||||
sinon.stub(settings, "get").returns(TEST_CONFIG);
|
||||
const overrides = await RemoteSettings(
|
||||
SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
|
||||
);
|
||||
sinon.stub(overrides, "get").returns(TEST_CONFIG_OVERRIDE);
|
||||
});
|
||||
|
||||
add_task(async function test_engine_selector_old() {
|
||||
let { engines } = await engineSelectorOld.fetchEngineConfiguration({
|
||||
locale: "en-US",
|
||||
region: "us",
|
||||
});
|
||||
Assert.equal(engines[0].telemetryId, "aol-tsfx");
|
||||
Assert.equal(engines[0].params.searchUrlGetParams[0].name, "new_param");
|
||||
Assert.equal(engines[0].params.searchUrlGetParams[0].value, "new_value");
|
||||
});
|
||||
|
||||
add_task(async function test_engine_selector() {
|
||||
let { engines } = await engineSelector.fetchEngineConfiguration({
|
||||
locale: "en-US",
|
||||
region: "us",
|
||||
});
|
||||
Assert.equal(engines[0].telemetrySuffix, "tsfx");
|
||||
Assert.equal(engines[0].clickUrl, "https://aol.url");
|
||||
Assert.equal(engines[0].urls.search.params[0].name, "new_param");
|
||||
Assert.equal(engines[0].urls.search.params[0].value, "new_value");
|
||||
});
|
@ -119,6 +119,8 @@ support-files = [
|
||||
["test_engine_selector_remote_settings.js"]
|
||||
tags = "remotesettings searchmain"
|
||||
|
||||
["test_engine_selector_remote_override.js"]
|
||||
|
||||
["test_engine_set_alias.js"]
|
||||
|
||||
["test_getSubmission_encoding.js"]
|
||||
|
Loading…
Reference in New Issue
Block a user