Bug 1352539 - Move default search engine to list.json. r?florian draft
authorMichael Kaply <mozilla@kaply.com>
Fri, 20 Apr 2018 12:48:02 -0500
changeset 785824 98e11458e001f0e73b63719b3e31c5a682ecf75b
parent 785586 cc0d7de218cb0c260c8ba0cf6637845ad2222f49
push id107324
push usermozilla@kaply.com
push dateFri, 20 Apr 2018 17:48:24 +0000
reviewersflorian
bugs1352539
milestone61.0a1
Bug 1352539 - Move default search engine to list.json. r?florian MozReview-Commit-ID: Kpz4Xb7nZ16
browser/app/profile/firefox.js
browser/locales/en-US/chrome/browser-region/region.properties
browser/locales/search/list.json
mobile/locales/en-US/chrome/region.properties
mobile/locales/search/list.json
python/mozbuild/mozbuild/action/generate_searchjson.py
python/mozbuild/mozbuild/action/output_searchplugins_list.py
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/data/list.json
toolkit/components/search/tests/xpcshell/head_search.js
toolkit/components/search/tests/xpcshell/test_list_json_searchdefault.js
toolkit/components/search/tests/xpcshell/xpcshell.ini
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -381,30 +381,26 @@ pref("browser.download.autohideButton", 
 
 #ifndef XP_MACOSX
 pref("browser.helperApps.deleteTempFileOnExit", true);
 #endif
 
 // search engines URL
 pref("browser.search.searchEnginesURL",      "https://addons.mozilla.org/%LOCALE%/firefox/search-engines/");
 
-// pointer to the default engine name
-pref("browser.search.defaultenginename",      "chrome://browser-region/locale/region.properties");
-
 // Ordering of Search Engines in the Engine list.
 pref("browser.search.order.1",                "chrome://browser-region/locale/region.properties");
 pref("browser.search.order.2",                "chrome://browser-region/locale/region.properties");
 pref("browser.search.order.3",                "chrome://browser-region/locale/region.properties");
 
 // Market-specific search defaults
 pref("browser.search.geoSpecificDefaults", true);
 pref("browser.search.geoSpecificDefaults.url", "https://search.services.mozilla.com/1/%APP%/%VERSION%/%CHANNEL%/%LOCALE%/%REGION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%");
 
-// US specific default (used as a fallback if the geoSpecificDefaults request fails).
-pref("browser.search.defaultenginename.US",      "data:text/plain,browser.search.defaultenginename.US=Google");
+// US specific default
 pref("browser.search.order.US.1",                "data:text/plain,browser.search.order.US.1=Google");
 pref("browser.search.order.US.2",                "data:text/plain,browser.search.order.US.2=Bing");
 
 // search bar results always open in a new tab
 pref("browser.search.openintab", false);
 
 // context menu searches open in the foreground
 pref("browser.search.context.loadInBackground", false);
--- a/browser/locales/en-US/chrome/browser-region/region.properties
+++ b/browser/locales/en-US/chrome/browser-region/region.properties
@@ -1,15 +1,12 @@
 # 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/.
 
-# Default search engine
-browser.search.defaultenginename=Google
-
 # Search engine order (order displayed in the search bar dropdown)s
 browser.search.order.1=Google
 browser.search.order.2=Bing
 
 # This is the default set of web based feed handlers shown in the reader
 # selection UI
 browser.contentHandlers.types.0.title=My Yahoo!
 browser.contentHandlers.types.0.uri=https://add.my.yahoo.com/rss?url=%s
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -1,10 +1,11 @@
 {
   "default": {
+    "searchDefault": "Google",
     "visibleDefaultEngines": [
       "google", "amazondotcom", "bing", "ddg", "ebay", "twitter", "wikipedia"
     ]
   },
   "regionOverrides": {
     "US": {
       "google": "google-2018"
     },
@@ -117,16 +118,28 @@
         ]
       }
     },
     "be": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-by", "google", "ddg", "wikipedia-be", "wikipedia-be-tarask"
         ]
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "bg": {
       "default": {
         "visibleDefaultEngines": [
           "google", "amazondotcom", "ddg", "portalbgdict", "wikipedia-bg"
         ]
       }
@@ -468,16 +481,28 @@
         ]
       }
     },
     "kk": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-kk", "google", "ddg", "flip", "kaz-kk", "twitter", "wikipedia-kk"
         ]
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "km": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "amazondotcom", "ddg", "twitter", "wikipedia-km"
         ]
       }
@@ -667,16 +692,28 @@
         ]
       }
     },
     "ru": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-ru", "google", "ddg", "ozonru", "priceru", "wikipedia-ru", "mailru"
         ]
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "si": {
       "default": {
         "visibleDefaultEngines": [
           "google", "amazondotcom", "ddg", "wikipedia-si"
         ]
       }
@@ -751,16 +788,28 @@
         ]
       }
     },
     "tr": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-tr", "google", "ddg", "twitter", "wikipedia-tr"
         ]
+      },
+      "TR": {
+        "searchDefault": "Yandex"
+      },
+      "BY": {
+        "searchDefault": "Yandex"
+      },
+      "KZ": {
+        "searchDefault": "Yandex"
+      },
+      "RU": {
+        "searchDefault": "Yandex"
       }
     },
     "uk": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "meta-ua", "ddg", "wikipedia-uk", "metamarket"
         ]
       }
@@ -800,16 +849,19 @@
         ]
       }
     },
     "zh-CN": {
       "default": {
         "visibleDefaultEngines": [
           "baidu", "google", "bing", "ddg", "wikipedia-zh-CN", "amazondotcn"
         ]
+      },
+      "CN": {
+        "searchDefault": "百度"
       }
     },
     "zh-TW": {
       "default": {
         "visibleDefaultEngines": [
           "google", "ddg", "readmoo", "wikipedia-zh-TW"
         ]
       }
--- a/mobile/locales/en-US/chrome/region.properties
+++ b/mobile/locales/en-US/chrome/region.properties
@@ -1,22 +1,18 @@
 # 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/.
 
-# Default search engine
-browser.search.defaultenginename=Google
-
 # Search engine order (order displayed in the search bar dropdown).
 browser.search.order.1=Google
 browser.search.order.2=Bing
 
 # These override the equivalents above when the client detects that it is in
 # US market only.
-browser.search.defaultenginename.US=Google
 browser.search.order.US.1=Google
 browser.search.order.US.2=Bing
 
 # increment this number when anything gets changed in the list below.  This will
 # cause Firefox to re-read these prefs and inject any new handlers into the
 # profile database.  Note that "new" is defined as "has a different URL"; this
 # means that it's not possible to update the name of existing handler, so
 # don't make any spelling errors here.
--- a/mobile/locales/search/list.json
+++ b/mobile/locales/search/list.json
@@ -1,10 +1,11 @@
 {
   "default": {
+    "searchDefault": "Google",
     "visibleDefaultEngines": [
       "google", "bing", "amazondotcom", "ddg", "twitter", "wikipedia"
     ]
   },
   "regionOverrides": {
     "US": {
       "google": "google-2018"
     },
@@ -70,16 +71,28 @@
         ]
       }
     },
     "be": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "ddg", "wikipedia-be", "yandex.by"
         ]
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "bg": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "wikipedia-bg"
         ]
       }
@@ -424,16 +437,28 @@
         ]
       }
     },
     "kk": {
       "default": {
         "visibleDefaultEngines": [
           "yandex", "google", "bing", "twitter", "wikipedia-kk"
         ]
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "km": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "amazondotcom", "twitter", "wikipedia-km"
         ]
       }
@@ -623,16 +648,28 @@
         ]
       }
     },
     "ru": {
       "default": {
         "visibleDefaultEngines": [
           "google", "yandex-ru", "twitter", "wikipedia-ru"
         ]
+      },
+      "RU": {
+        "searchDefault": "Яндекс"
+      },
+      "BY": {
+        "searchDefault": "Яндекс"
+      },
+      "KZ": {
+        "searchDefault": "Яндекс"
+      },
+      "TR": {
+        "searchDefault": "Яндекс"
       }
     },
     "sk": {
       "default": {
         "visibleDefaultEngines": [
           "google", "azet-sk", "slovnik-sk", "twitter", "wikipedia-sk"
         ]
       }
@@ -700,21 +737,32 @@
         ]
       }
     },
     "tr": {
       "default": {
         "visibleDefaultEngines": [
           "yandex-tr", "google", "twitter", "wikipedia-tr"
         ]
+      },
+      "TR": {
+        "searchDefault": "Yandex"
+      },
+      "BY": {
+        "searchDefault": "Yandex"
+      },
+      "KZ": {
+        "searchDefault": "Yandex"
+      },
+      "RU": {
+        "searchDefault": "Yandex"
       }
     },
     "trs": {
       "default": {
-        "searchDefault": "Google",
         "visibleDefaultEngines": [
           "amazondotcom", "bing", "google", "twitter", "wikipedia-es"
         ]
       }
     },
     "uk": {
       "default": {
         "visibleDefaultEngines": [
@@ -764,16 +812,19 @@
         ]
       }
     },
     "zh-CN": {
       "default": {
         "visibleDefaultEngines": [
           "google", "baidu", "bing", "taobao", "wikipedia-zh-CN"
         ]
+      },
+      "CN": {
+        "searchDefault": "百度"
       }
     },
     "zh-TW": {
       "default": {
         "visibleDefaultEngines": [
           "google", "bing", "ddg", "wikipedia-zh-TW"
         ]
       },
--- a/python/mozbuild/mozbuild/action/generate_searchjson.py
+++ b/python/mozbuild/mozbuild/action/generate_searchjson.py
@@ -11,33 +11,51 @@ engines = []
 locale = sys.argv[2]
 output_file = sys.argv[3]
 
 output = open(output_file, 'w')
 
 with open(sys.argv[1]) as f:
   searchinfo = json.load(f)
 
+# If we have a locale, use it, otherwise use the default
 if locale in searchinfo["locales"]:
   localeSearchInfo = searchinfo["locales"][locale]
 else:
   localeSearchInfo = {}
   localeSearchInfo["default"] = searchinfo["default"]
 
+def validateDefault(key):
+  if (not key in searchinfo["default"]):
+    print >>sys.stderr, "Error: Missing default %s in list.json" % (key)
+    sys.exit(1)
+
+validateDefault("searchDefault");
+validateDefault("visibleDefaultEngines");
+
+# If the selected locale doesn't have a searchDefault,
+# use the global one.
+if not "searchDefault" in localeSearchInfo["default"]:
+  localeSearchInfo["default"]["searchDefault"] = searchinfo["default"]["searchDefault"]
+
 # If we have region overrides, enumerate through them
 # and add the additional regions to the locale information.
 if "regionOverrides" in searchinfo:
   regionOverrides = searchinfo["regionOverrides"]
 
   for region in regionOverrides:
-    if not region in localeSearchInfo:
-      # Only add the region if it has engines that need to be overridden
-      if set(localeSearchInfo["default"]["visibleDefaultEngines"]) & set(regionOverrides[region].keys()):
-        localeSearchInfo[region] = copy.deepcopy(localeSearchInfo["default"])
-      else:
-        continue
-    for i, engine in enumerate(localeSearchInfo[region]["visibleDefaultEngines"]):
-      if engine in regionOverrides[region]:
-        localeSearchInfo[region]["visibleDefaultEngines"][i] = regionOverrides[region][engine]
+    # Only add a new engine list if there is an engine that is overridden
+    enginesToOverride = set(regionOverrides[region].keys())
+    if region in localeSearchInfo and "visibleDefaultEngines" in localeSearchInfo[region]:
+       visibleDefaultEngines = localeSearchInfo[region]["visibleDefaultEngines"]
+    else:
+       visibleDefaultEngines = localeSearchInfo["default"]["visibleDefaultEngines"]
+    if set(visibleDefaultEngines) & enginesToOverride:
+      if region not in localeSearchInfo:
+        localeSearchInfo[region] = {}
+      localeSearchInfo[region]["visibleDefaultEngines"] = copy.deepcopy(visibleDefaultEngines)
+      for i, engine in enumerate(localeSearchInfo[region]["visibleDefaultEngines"]):
+        if engine in regionOverrides[region]:
+          localeSearchInfo[region]["visibleDefaultEngines"][i] = regionOverrides[region][engine]
 
-output.write(json.dumps(localeSearchInfo))
+output.write(json.dumps(localeSearchInfo, ensure_ascii=False).encode('utf8'))
 
 output.close();
--- a/python/mozbuild/mozbuild/action/output_searchplugins_list.py
+++ b/python/mozbuild/mozbuild/action/output_searchplugins_list.py
@@ -11,18 +11,20 @@ locale = sys.argv[2]
 
 with open(sys.argv[1]) as f:
   searchinfo = json.load(f)
 
 # Get a list of the engines from the locale or the default
 engines = set()
 if locale in searchinfo["locales"]:
   for region, table in searchinfo["locales"][locale].iteritems():
-    engines.update(table["visibleDefaultEngines"])
-else:
+    if "visibleDefaultEngines" in table:
+      engines.update(table["visibleDefaultEngines"])
+
+if not engines:
   engines.update(searchinfo["default"]["visibleDefaultEngines"])
 
 # Get additional engines from regionOverrides
 for region, overrides in searchinfo["regionOverrides"].iteritems():
   for originalengine, replacement in overrides.iteritems():
     if originalengine in engines:
       # We add the engine because we still need the original
       engines.add(replacement)
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2776,36 +2776,48 @@ SearchService.prototype = {
       return "";
     }
     return val;
   },
 
   _engines: { },
   __sortedEngines: null,
   _visibleDefaultEngines: [],
+  _searchDefault: null,
   get _sortedEngines() {
     if (!this.__sortedEngines)
       return this._buildSortedEngineList();
     return this.__sortedEngines;
   },
 
   // Get the original Engine object that is the default for this region,
   // ignoring changes the user may have subsequently made.
   get originalDefaultEngine() {
     let defaultEngine = this.getVerifiedGlobalAttr("searchDefault");
     if (!defaultEngine) {
-      let defaultPrefB = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF);
-      let nsIPLS = Ci.nsIPrefLocalizedString;
-
-      let defPref = getGeoSpecificPrefName("defaultenginename");
-      try {
-        defaultEngine = defaultPrefB.getComplexValue(defPref, nsIPLS).data;
-      } catch (ex) {
-        // If the default pref is invalid (e.g. an add-on set it to a bogus value)
-        // getEngineByName will just return null, which is the best we can do.
+      // We only allow the old defaultenginename pref for distributions
+      // We can't use isPartnerBuild because we need to allow reading
+      // of the defaultengine name pref for funnelcakes.
+      if (Services.prefs.getCharPref("distribution.id", "")) {
+        let defaultPrefB = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF);
+        let nsIPLS = Ci.nsIPrefLocalizedString;
+
+        let defPref = getGeoSpecificPrefName("defaultenginename");
+        try {
+          defaultEngine = defaultPrefB.getComplexValue(defPref, nsIPLS).data;
+        } catch (ex) {
+          // If the default pref is invalid (e.g. an add-on set it to a bogus value)
+          // use the default engine from the list.json.
+          // This should eventually be the common case. We should only have the
+          // defaultenginename pref for distributions.
+          // Worst case, getEngineByName will just return null, which is the best we can do.
+          defaultEngine = this._searchDefault;
+        }
+      } else {
+        defaultEngine = this._searchDefault;
       }
     }
 
     return this.getEngineByName(defaultEngine);
   },
 
   resetToOriginalDefaultEngine: function SRCH_SVC__resetToOriginalDefaultEngine() {
     let originalDefaultEngine = this.originalDefaultEngine;
@@ -3007,16 +3019,17 @@ SearchService.prototype = {
           await task.finalize();
         }
 
         // Clear the engines, too, so we don't stick with the stale ones.
         this._engines = {};
         this.__sortedEngines = null;
         this._currentEngine = null;
         this._visibleDefaultEngines = [];
+        this._searchDefault = null;
         this._metaData = {};
         this._cacheFileJSON = null;
 
         // Tests that want to force a synchronous re-initialization need to
         // be notified when we are done uninitializing.
         Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC,
                                      "uninit-complete");
 
@@ -3481,26 +3494,27 @@ SearchService.prototype = {
           LOG("_parseListJSON: ignoring visibleDefaultEngines value because " +
               engineName + " is not in the jar engines we have found");
           engineNames = null;
           break;
         }
       }
     }
 
+    let searchRegion;
+    if (Services.prefs.prefHasUserValue("browser.search.region")) {
+      searchRegion = Services.prefs.getCharPref("browser.search.region");
+    }
+    if (!searchRegion || !(searchRegion in searchSettings)) {
+      searchRegion = "default";
+    }
+
     // Fallback to building a list based on the regions in the JSON
     if (!engineNames || !engineNames.length) {
-      let region;
-      if (Services.prefs.prefHasUserValue("browser.search.region")) {
-        region = Services.prefs.getCharPref("browser.search.region");
-      }
-      if (!region || !(region in searchSettings)) {
-        region = "default";
-      }
-      engineNames = searchSettings[region].visibleDefaultEngines;
+      engineNames = searchSettings[searchRegion].visibleDefaultEngines;
     }
 
     // Remove any engine names that are supposed to be ignored.
     // This pref is only allows in a partner distribution.
     let branch = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF);
     if (isPartnerBuild() &&
         branch.getPrefType("ignoredJAREngines") == branch.PREF_STRING) {
       let ignoredJAREngines = branch.getCharPref("ignoredJAREngines")
@@ -3513,16 +3527,22 @@ SearchService.prototype = {
     }
 
     for (let name of engineNames) {
       uris.push(APP_SEARCH_PREFIX + name + ".xml");
     }
 
     // Store this so that it can be used while writing the cache file.
     this._visibleDefaultEngines = engineNames;
+
+    if ("searchDefault" in searchSettings[searchRegion]) {
+      this._searchDefault = searchSettings[searchRegion].searchDefault;
+    } else {
+      this._searchDefault = searchSettings.default.searchDefault;
+    }
   },
 
   _parseListTxt: function SRCH_SVC_parseListTxt(list, uris) {
     let names = list.split("\n").filter(n => !!n);
     // This maps the names of our built-in engines to a boolean
     // indicating whether it should be hidden by default.
     let jarNames = new Map();
     for (let name of names) {
--- a/toolkit/components/search/tests/xpcshell/data/list.json
+++ b/toolkit/components/search/tests/xpcshell/data/list.json
@@ -1,7 +1,8 @@
 {
   "default": {
+    "searchDefault": "Test search engine",
     "visibleDefaultEngines": [
       "engine", "engine-pref", "engine-rel-searchform-purpose", "engine-system-purpose", "engine-chromeicon", "engine-resourceicon"
     ]
   }
 }
--- a/toolkit/components/search/tests/xpcshell/head_search.js
+++ b/toolkit/components/search/tests/xpcshell/head_search.js
@@ -230,25 +230,31 @@ function isUSTimezone() {
   return UTCOffset >= 150 && UTCOffset <= 600;
 }
 
 const kDefaultenginenamePref = "browser.search.defaultenginename";
 const kTestEngineName = "Test search engine";
 const REQ_LOCALES_CHANGED_TOPIC = "intl:requested-locales-changed";
 
 function getDefaultEngineName(isUS) {
-  const nsIPLS = Ci.nsIPrefLocalizedString;
-  // Copy the logic from nsSearchService
-  let pref = kDefaultenginenamePref;
+  // The list of visibleDefaultEngines needs to match or the cache will be ignored.
+  let chan = NetUtil.newChannel({
+    uri: "resource://search-plugins/list.json",
+    loadUsingSystemPrincipal: true
+  });
+  let searchSettings = parseJsonFromStream(chan.open2());
+  let defaultEngineName = searchSettings.default.searchDefault;
+
   if (isUS === undefined)
     isUS = Services.locale.getRequestedLocale() == "en-US" && isUSTimezone();
-  if (isUS) {
-    pref += ".US";
+
+  if (isUS && ("searchDefault" in searchSettings.US)) {
+    defaultEngineName = searchSettings.US.searchDefault;
   }
-  return Services.prefs.getComplexValue(pref, nsIPLS).data;
+  return defaultEngineName;
 }
 
 /**
  * Waits for the cache file to be saved.
  * @return {Promise} Resolved when the cache file is saved.
  */
 function promiseAfterCache() {
   return waitForSearchNotification("write-cache-to-disk-complete");
@@ -401,17 +407,16 @@ function installTestEngine() {
  *        The name of the pref to set.
  */
 function setLocalizedDefaultPref(aPrefName, aValue) {
   let value = "data:text/plain," + BROWSER_SEARCH_PREF + aPrefName + "=" + aValue;
   Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF)
           .setCharPref(aPrefName, value);
 }
 
-
 /**
  * Installs two test engines, sets them as default for US vs. general.
  */
 function setUpGeoDefaults() {
   const kSecondTestEngineName = "A second test engine";
 
   setLocalizedDefaultPref("defaultenginename", "Test search engine");
   setLocalizedDefaultPref("defaultenginename.US", "A second test engine");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_list_json_searchdefault.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* Check default search engine is picked from list.json searchDefault */
+
+"use strict";
+
+function run_test() {
+  Assert.ok(!Services.search.isInitialized, "search isn't initialized yet");
+
+  run_next_test();
+}
+
+// Check that current engine matches with US searchDefault from list.json
+add_task(async function test_searchDefaultEngineUS() {
+  Services.prefs.setCharPref("browser.search.region", "US");
+
+  await asyncInit();
+
+  Assert.ok(Services.search.isInitialized, "search initialized");
+
+  Assert.equal(Services.search.currentEngine.name,
+               getDefaultEngineName(true), "expected US default search engine");
+
+  Services.prefs.clearUserPref("browser.search.region");
+});
+
+// Giving defaultenginename prefs a user value for partner build
+// shouldn't change the default engine assigned from list.json
+add_task(async function test_defaultEngineNamePref() {
+  let defaultEngineName = getDefaultEngineName();
+
+  Services.prefs.setCharPref("distribution.id", "partner-test");
+
+  // Set the browser.search.defaultenginename pref.
+  Services.prefs.setCharPref(kDefaultenginenamePref, "Bing");
+
+  await asyncReInit();
+  Assert.equal(Services.search.currentEngine.name,
+               defaultEngineName, "expected default search engine after pref set");
+
+  Services.prefs.clearUserPref(kDefaultenginenamePref);
+  Services.prefs.clearUserPref("distribution.id");
+});
+
+// Giving defaultenginename prefs a user value with region US
+// shouldn't change the default engine assigned from list.json
+add_task(async function test_defaultEngineNameUserPrefUS() {
+  let defaultEngineName = getDefaultEngineName(true);
+
+  Services.prefs.setCharPref("distribution.id", "partner-test");
+  Services.prefs.setCharPref("browser.search.region", "US");
+
+  // Set the browser.search.defaultenginename pref.
+  Services.prefs.setCharPref(kDefaultenginenamePref, "Bing");
+
+  await asyncReInit();
+  Assert.equal(Services.search.currentEngine.name,
+               defaultEngineName, "expected US default search engine after pref set");
+
+  Services.prefs.clearUserPref(kDefaultenginenamePref);
+  Services.prefs.clearUserPref("browser.search.region");
+  Services.prefs.clearUserPref("distribution.id");
+});
+
+// Giving defaultenginename prefs a default value with region US
+// should change the default engine assigned from list.json
+// This needs to be the last test involving the defaultenengename prefs
+// because it changes a default value that can't be unset
+add_task(async function test_defaultEngineNameDefaultPrefUS() {
+  Services.prefs.setCharPref("distribution.id", "partner-test");
+  Services.prefs.setCharPref("browser.search.region", "US");
+
+  // Set the browser.search.defaultenginename pref.
+  let defaultBranch = Services.prefs.getDefaultBranch(null);
+  defaultBranch.setCharPref(kDefaultenginenamePref,
+                            "data:text/plain,browser.search.defaultenginename=Bing");
+
+  await asyncReInit();
+  Assert.equal(Services.search.currentEngine.name,
+               "Bing", "expected new default search engine after pref set");
+
+  Services.prefs.clearUserPref("browser.search.region");
+  Services.prefs.clearUserPref("distribution.id");
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -35,16 +35,17 @@ support-files =
 [test_bug930456_child.js]
 [test_engine_set_alias.js]
 [test_hasEngineWithURL.js]
 [test_identifiers.js]
 [test_invalid_engine_from_dir.js]
 [test_init_async_multiple.js]
 [test_init_async_multiple_then_sync.js]
 [test_json_cache.js]
+[test_list_json_searchdefault.js]
 [test_location.js]
 [test_location_error.js]
 [test_location_malformed_json.js]
 [test_location_migrate_countrycode_isUS.js]
 [test_location_migrate_no_countrycode_isUS.js]
 [test_location_migrate_no_countrycode_notUS.js]
 [test_location_partner.js]
 [test_location_funnelcake.js]