tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 67267688fa300c5ee156601b5384fa1996ca0fc9
parent 49b44d2094f6391e8cc2664b40a489d60e9f66a1
Author: Drew Willcoxon <adw@mozilla.com>
Date:   Tue, 25 Nov 2025 07:44:47 +0000

Bug 2002141 - Remove support for unmanaged Merino suggestions. r=daisuke

This is an alternative to D273910.

@nanj pointed out it might be too soon to remove support for the `top_picks`
provider. On second thought I agree, and regardless, I'd like to uplift this
patch so that it's in the same release as the other major Suggest changes in
Firefox 146. The point of this bug is only to disable the unmanaged suggestions
ability, not to remove support for `top_picks`, so this patch only does the
former. This patch is much smaller as a result.

Differential Revision: https://phabricator.services.mozilla.com/D273945

Diffstat:
Mbrowser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs | 12+++++-------
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js | 49+++++++++++++++++++++++++++++++++++++++----------
Mbrowser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_scoreMap.js | 21++++++++++++---------
3 files changed, 56 insertions(+), 26 deletions(-)

diff --git a/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs b/browser/components/urlbar/UrlbarProviderQuickSuggest.sys.mjs @@ -422,11 +422,9 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider { * Returns a new result for an unmanaged suggestion. An "unmanaged" suggestion * is a suggestion without a feature. * - * Merino is the only backend allowed to serve unmanaged suggestions, for a - * couple of reasons: (1) Some suggestion types aren't that complicated and - * can be handled in a default manner, for example "top_picks". (2) It allows - * us to experiment with new suggestion types without requiring any changes to - * Firefox. + * Merino is the only backend allowed to serve unmanaged suggestions, and its + * "top_picks" provider is the only Merino provider recognized by this method. + * For everything else, the method returns null. * * @param {UrlbarQueryContext} queryContext * The query context. @@ -434,10 +432,10 @@ export class UrlbarProviderQuickSuggest extends UrlbarProvider { * The suggestion. * @returns {UrlbarResult|null} * A new result for the suggestion or null if the suggestion is not from - * Merino. + * the Merino "top_picks" provider. */ #makeUnmanagedResult(queryContext, suggestion) { - if (suggestion.source != "merino") { + if (suggestion.source != "merino" || suggestion.provider != "top_picks") { return null; } diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_merino.js @@ -398,7 +398,9 @@ add_task(async function dismissals_unmanaged_1() { UrlbarPrefs.set("quicksuggest.online.available", true); UrlbarPrefs.set("quicksuggest.online.enabled", true); - let provider = "some-unknown-merino-provider"; + // The "top_picks" provider is the only supported unmanaged suggestion. + let provider = "top_picks"; + let tests = [ { suggestion: { @@ -545,7 +547,8 @@ add_task(async function dismissals_unmanaged_2() { UrlbarPrefs.set("quicksuggest.online.available", true); UrlbarPrefs.set("quicksuggest.online.enabled", true); - let provider = "some-unknown-merino-provider"; + // The "top_picks" provider is the only supported unmanaged suggestion. + let provider = "top_picks"; MerinoTestUtils.server.response = MerinoTestUtils.server.makeDefaultResponse(); @@ -726,12 +729,13 @@ add_task(async function bestMatch() { UrlbarPrefs.set("quicksuggest.online.available", true); UrlbarPrefs.set("quicksuggest.online.enabled", true); - // Set up a suggestion with `is_top_pick` and an unknown provider so that + // Set up a suggestion with `is_top_pick` and the "top_picks" provider so that // UrlbarProviderQuickSuggest will make a default result for it. + let provider = "top_picks"; MerinoTestUtils.server.response.body.suggestions = [ { is_top_pick: true, - provider: "some_top_pick_provider", + provider, full_keyword: "full_keyword", title: "title", url: "url", @@ -753,7 +757,7 @@ add_task(async function bestMatch() { source: UrlbarUtils.RESULT_SOURCE.SEARCH, heuristic: false, payload: { - telemetryType: "some_top_pick_provider", + telemetryType: provider, title: "title", url: "url", icon: null, @@ -763,7 +767,7 @@ add_task(async function bestMatch() { isManageable: true, displayUrl: "url", source: "merino", - provider: "some_top_pick_provider", + provider, }, }, ], @@ -785,7 +789,6 @@ add_task(async function unmanaged_sponsored_allDisabled() { suggestion: { title: "Sponsored without feature", url: "https://example.com/sponsored-without-feature", - provider: "sponsored-unrecognized-provider", is_sponsored: true, }, shouldBeAdded: false, @@ -800,7 +803,6 @@ add_task(async function unmanaged_sponsored_sponsoredDisabled() { suggestion: { title: "Sponsored without feature", url: "https://example.com/sponsored-without-feature", - provider: "sponsored-unrecognized-provider", is_sponsored: true, }, shouldBeAdded: false, @@ -815,7 +817,6 @@ add_task(async function unmanaged_nonsponsored_allDisabled() { suggestion: { title: "Nonsponsored without feature", url: "https://example.com/nonsponsored-without-feature", - provider: "nonsponsored-unrecognized-provider", // no is_sponsored }, shouldBeAdded: false, @@ -831,7 +832,6 @@ add_task(async function unmanaged_nonsponsored_sponsoredDisabled() { suggestion: { title: "Nonsponsored without feature", url: "https://example.com/nonsponsored-without-feature", - provider: "nonsponsored-unrecognized-provider", // no is_sponsored }, shouldBeAdded: true, @@ -839,6 +839,9 @@ add_task(async function unmanaged_nonsponsored_sponsoredDisabled() { }); async function doUnmanagedTest({ pref, suggestion, shouldBeAdded }) { + // The "top_picks" provider is the only supported unmanaged suggestion. + suggestion.provider = "top_picks"; + UrlbarPrefs.set("suggest.quicksuggest.all", true); UrlbarPrefs.set("suggest.quicksuggest.sponsored", true); await QuickSuggestTestUtils.forceSync(); @@ -930,6 +933,32 @@ async function doUnmanagedTest({ pref, suggestion, shouldBeAdded }) { merinoClient().resetSession(); } +// An unmanaged suggestion with an unrecognized Merino provider (i.e., not +// "top_picks") should not be added. +add_task(async function unmanaged_unrecognized() { + UrlbarPrefs.set("suggest.quicksuggest.all", true); + UrlbarPrefs.set("suggest.quicksuggest.sponsored", true); + await QuickSuggestTestUtils.forceSync(); + + UrlbarPrefs.set("quicksuggest.online.available", true); + UrlbarPrefs.set("quicksuggest.online.enabled", true); + MerinoTestUtils.server.response.body.suggestions = [ + { + title: "Some unrecognized suggestion", + url: "https://example.com/unmanaged_unrecognized", + provider: "unmanaged-unrecognized-provider", + }, + ]; + + await check_results({ + context: createContext("test", { + providers: [UrlbarProviderQuickSuggest.name], + isPrivate: false, + }), + matches: [], + }); +}); + function merinoClient() { return QuickSuggest.getFeature("SuggestBackendMerino")?.client; } diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_scoreMap.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest_scoreMap.js @@ -142,8 +142,11 @@ const MERINO_ADDON_SUGGESTION = { }, }; -const MERINO_UNKNOWN_SUGGESTION = { - provider: "some_unknown_provider", +// A unmanaged Merino suggestion is a suggestion that isn't managed by a +// `SuggestFeature`. Suggestions from the "top_picks" Merino provider are the +// only recognized unmanaged suggestions. +const MERINO_UNMANAGED_SUGGESTION = { + provider: "top_picks", score: DEFAULT_SUGGESTION_SCORE, keywords: ["test"], url: "https://example.com/merino-unknown", @@ -468,12 +471,12 @@ add_task(async function merino_sponsored_addon_addonWins() { await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS); }); -add_task(async function merino_sponsored_unknown_sponsoredWins() { +add_task(async function merino_sponsored_unmanaged_sponsoredWins() { await QuickSuggestTestUtils.setRemoteSettingsRecords([]); MerinoTestUtils.server.response.body.suggestions = [ MERINO_SPONSORED_SUGGESTION, - MERINO_UNKNOWN_SUGGESTION, + MERINO_UNMANAGED_SUGGESTION, ]; let score = 10 * DEFAULT_SUGGESTION_SCORE; @@ -496,24 +499,24 @@ add_task(async function merino_sponsored_unknown_sponsoredWins() { await QuickSuggestTestUtils.setRemoteSettingsRecords(REMOTE_SETTINGS_RECORDS); }); -add_task(async function merino_sponsored_unknown_unknownWins() { +add_task(async function merino_sponsored_unmanaged_unmanagedWins() { await QuickSuggestTestUtils.setRemoteSettingsRecords([]); MerinoTestUtils.server.response.body.suggestions = [ MERINO_SPONSORED_SUGGESTION, - MERINO_UNKNOWN_SUGGESTION, + MERINO_UNMANAGED_SUGGESTION, ]; let score = 10 * DEFAULT_SUGGESTION_SCORE; await doTest({ keyword: "test", scoreMap: { - [MERINO_UNKNOWN_SUGGESTION.provider]: score, + [MERINO_UNMANAGED_SUGGESTION.provider]: score, }, expectedFeatureName: null, expectedScore: score, expectedResult: makeExpectedDefaultMerinoResult({ - suggestion: MERINO_UNKNOWN_SUGGESTION, + suggestion: MERINO_UNMANAGED_SUGGESTION, }), }); @@ -551,7 +554,7 @@ add_task(async function stringValue() { * @param {string} options.expectedFeatureName * The name of the `BaseFeature` instance that is expected to create the * `UrlbarResult` that's shown. If the suggestion is intentionally from an - * unknown Merino provider and therefore the quick suggest provider is + * unmanaged Merino provider and therefore the quick suggest provider is * expected to create a default result for it, set this to null. * @param {UrlbarResultstring} options.expectedResult * The `UrlbarResult` that's expected to be shown.