Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1938924 - Add support for search-config-overrides-v2 to the Rust… #6614

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions components/search/src/configuration_overrides_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* 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/. */

//! This module defines the structures that we use for serde_json to parse
//! the search configuration overrides.

use crate::JSONEngineUrls;
use serde::Deserialize;

/// Represents search configuration overrides record.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct JSONOverridesRecord {
/// This is the identifier of the search engine in search-config-v2 that this
/// record will override. It may be extended by telemetry_suffix.
pub identifier: String,

/// The partner code for the engine or variant. This will be inserted into
/// parameters which include '{partnerCode}
pub partner_code: String,

/// 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.
pub telemetry_suffix: Option<String>,

/// The url used for reporting clicks.
pub click_url: String,

/// The URLs associated with the search engine.
//pub urls: JSONOverrideEngineUrls,
pub urls: JSONEngineUrls,
}

/// Represents the search configuration overrides as received from remote settings.
#[derive(Debug, Deserialize)]
pub(crate) struct JSONSearchConfigurationOverrides {
pub data: Vec<JSONOverridesRecord>,
}
2 changes: 2 additions & 0 deletions components/search/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use remote_settings::RemoteSettingsError;
pub enum Error {
#[error("Search configuration not specified")]
SearchConfigNotSpecified,
#[error("Search configuration overrides not specified")]
SearchConfigOverridesNotSpecified,
#[error("No records received from remote settings")]
SearchConfigNoRecords,
#[error("JSON error: {0}")]
Expand Down
49 changes: 43 additions & 6 deletions components/search/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

//! This module defines the functions for managing the filtering of the configuration.

use crate::configuration_overrides_types::JSONOverridesRecord;
use crate::environment_matching::matches_user_environment;
use crate::{
error::Error, JSONDefaultEnginesRecord, JSONEngineBase, JSONEngineRecord, JSONEngineUrl,
Expand Down Expand Up @@ -94,6 +95,17 @@ impl SearchEngineDefinition {
}
}

fn merge_override(&mut self, override_record: &JSONOverridesRecord) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice to add a unit test for this - something fairly simple that checks we merge the parameters correctly (and don't change the telemetry suffix if none is supplied).

self.partner_code = override_record.partner_code.clone();
self.urls.merge(&override_record.urls);
if let Some(telemetry_suffix) = &override_record.telemetry_suffix {
self.telemetry_suffix = telemetry_suffix.clone();
}
if self.click_url.is_none() {
self.click_url = Some(override_record.click_url.clone());
}
}

pub(crate) fn from_configuration_details(
identifier: &str,
base: JSONEngineBase,
Expand All @@ -111,6 +123,7 @@ impl SearchEngineDefinition {
partner_code: base.partner_code.unwrap_or_default(),
telemetry_suffix: String::new(),
urls: base.urls.into(),
click_url: None,
};

engine_definition.merge_variant(variant);
Expand All @@ -132,13 +145,15 @@ pub(crate) trait Filter {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error>;
}

impl Filter for Vec<RemoteSettingsRecord> {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
_overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error> {
let mut engines = Vec::new();
let mut default_engines_record = None;
Expand Down Expand Up @@ -183,6 +198,7 @@ impl Filter for Vec<JSONSearchConfigurationRecords> {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error> {
let mut engines = Vec::new();
let mut default_engines_record = None;
Expand All @@ -191,7 +207,10 @@ impl Filter for Vec<JSONSearchConfigurationRecords> {
for record in self {
match record {
JSONSearchConfigurationRecords::Engine(engine) => {
let result = maybe_extract_engine_config(user_environment, engine.clone());
let mut result = maybe_extract_engine_config(user_environment, engine.clone());
if let Some(overrides_data) = &overrides {
apply_overrides(&mut result, overrides_data);
}
engines.extend(result);
}
JSONSearchConfigurationRecords::DefaultEngines(default_engines) => {
Expand All @@ -214,16 +233,30 @@ impl Filter for Vec<JSONSearchConfigurationRecords> {
}
}

fn apply_overrides(
engines: &mut Option<SearchEngineDefinition>,
overrides: &[JSONOverridesRecord],
) {
for override_record in overrides {
if let Some(engine) = engines
.iter_mut()
.find(|e| e.identifier == override_record.identifier)
{
engine.merge_override(override_record);
}
}
}
pub(crate) fn filter_engine_configuration_impl(
user_environment: SearchUserEnvironment,
configuration: &impl Filter,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<RefinedSearchConfig, Error> {
let mut user_environment = user_environment.clone();
user_environment.locale = user_environment.locale.to_lowercase();
user_environment.region = user_environment.region.to_lowercase();
user_environment.version = user_environment.version.to_lowercase();

let filtered_result = configuration.filter_records(&user_environment);
let filtered_result = configuration.filter_records(&user_environment, overrides);

filtered_result.map(|result| {
let (default_engine_id, default_private_engine_id) = determine_default_engines(
Expand Down Expand Up @@ -442,7 +475,8 @@ mod tests {
suggestions: None,
trending: None,
search_form: None
}
},
click_url: None
}
)
}
Expand Down Expand Up @@ -593,7 +627,8 @@ mod tests {
}],
search_term_param_name: None,
}),
}
},
click_url: None
}
)
}
Expand Down Expand Up @@ -719,7 +754,8 @@ mod tests {
}],
search_term_param_name: None,
}),
}
},
click_url: None
}
)
}
Expand Down Expand Up @@ -904,7 +940,8 @@ mod tests {
}],
search_term_param_name: None,
}),
}
},
click_url: None
}
)
}
Expand Down
1 change: 1 addition & 0 deletions components/search/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* 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/. */

mod configuration_overrides_types;
mod configuration_types;
mod environment_matching;
mod error;
Expand Down
Loading