Bug 1589618 - Move the implementation of the region fetch to NetworkGeolocationProvider to have it close to the wifi scanning code. r=Standard8,garvan

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dale Harvey 2020-02-25 14:19:05 +00:00
parent 64d1a3665c
commit af0051aade
21 changed files with 272 additions and 258 deletions

View File

@ -14,28 +14,16 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
// GeolocationPositionError has no interface object, so we can't use that here.
const POSITION_UNAVAILABLE = 2;
var gLoggingEnabled = false;
/*
The gLocationRequestTimeout controls how long we wait on receiving an update
from the Wifi subsystem. If this timer fires, we believe the Wifi scan has
had a problem and we no longer can use Wifi to position the user this time
around (we will continue to be hopeful that Wifi will recover).
This timeout value is also used when Wifi scanning is disabled (see
gWifiScanningEnabled). In this case, we use this timer to collect cell/ip
data and xhr it to the location server.
*/
var gLocationRequestTimeout = 5000;
var gWifiScanningEnabled = true;
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gLoggingEnabled",
"geo.provider.network.logging.enabled",
false
);
function LOG(aMsg) {
if (gLoggingEnabled) {
aMsg = "*** WIFI GEO: " + aMsg + "\n";
Services.console.logStringMessage(aMsg);
dump(aMsg);
dump("*** WIFI GEO: " + aMsg + "\n");
}
}
@ -251,19 +239,38 @@ NetworkGeoPositionObject.prototype = {
};
function NetworkGeolocationProvider() {
gLoggingEnabled = Services.prefs.getBoolPref(
"geo.provider.network.logging.enabled",
false
);
gLocationRequestTimeout = Services.prefs.getIntPref(
this.mode = "provider";
/*
The _wifiMonitorTimeout controls how long we wait on receiving an update
from the Wifi subsystem. If this timer fires, we believe the Wifi scan has
had a problem and we no longer can use Wifi to position the user this time
around (we will continue to be hopeful that Wifi will recover).
This timeout value is also used when Wifi scanning is disabled (see
isWifiScanningEnabled). In this case, we use this timer to collect cell/ip
data and xhr it to the location server.
*/
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_wifiMonitorTimeout",
"geo.provider.network.timeToWaitBeforeSending",
5000
);
gWifiScanningEnabled = Services.prefs.getBoolPref(
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_wifiScanningEnabled",
"geo.provider.network.scan",
true
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_wifiScanningEnabledCountry",
"geo.provider-country.network.scan",
true
);
this.wifiService = null;
this.timer = null;
this.started = false;
@ -279,6 +286,12 @@ NetworkGeolocationProvider.prototype = {
]),
listener: null,
get isWifiScanningEnabled() {
return Cc["@mozilla.org/wifi/monitor;1"] && this.mode == "provider"
? this._wifiScanningEnabled
: this._wifiScanningEnabledCountry;
},
resetTimer() {
if (this.timer) {
this.timer.cancel();
@ -289,7 +302,7 @@ NetworkGeolocationProvider.prototype = {
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timer.initWithCallback(
this,
gLocationRequestTimeout,
this._wifiMonitorTimeout,
this.timer.TYPE_REPEATING_SLACK
);
},
@ -301,7 +314,7 @@ NetworkGeolocationProvider.prototype = {
this.started = true;
if (gWifiScanningEnabled && Cc["@mozilla.org/wifi/monitor;1"]) {
if (this.isWifiScanningEnabled) {
if (this.wifiService) {
this.wifiService.stopWatching(this);
}
@ -382,53 +395,142 @@ NetworkGeolocationProvider.prototype = {
this.sendLocationRequest(null);
},
onStatus(err, statusMessage) {
if (!this.listener) {
return;
}
LOG("onStatus called." + statusMessage);
if (statusMessage && this.listener.notifyStatus) {
this.listener.notifyStatus(statusMessage);
}
if (err && this.listener.notifyError) {
this.listener.notifyError(POSITION_UNAVAILABLE, statusMessage);
}
},
notify(timer) {
this.onStatus(false, "wifi-timeout");
this.sendLocationRequest(null);
},
/**
* One-shot country identifier fetch.
*
* @param {Function} statusCallback This method is called for each
* intermediate result with the current
* state of the request as argument.
* @return {Promise<String>} A promise that is resolved with a country code or
* rejected with an error.
*/
async getCountry(statusCallback) {
this.mode = "provider-country";
let self = this;
let promise = new Promise((resolve, reject) => {
this.watch({
update(country) {
resolve(country);
self.shutdown();
},
notifyError(code, message) {
reject(message);
self.shutdown();
},
notifyStatus(status) {
if (statusCallback) {
statusCallback(status);
}
},
});
}).finally(() => {
this.mode = "provider";
});
this.startup();
Services.tm.dispatchToMainThread(() => this.sendLocationRequest(null));
return promise;
},
/**
* After wifi (and possible cell tower) data has been gathered, this method is
* invoked to perform the request to network geolocation provider.
* The result of each request is sent to all registered listener (@see watch)
* by invoking its respective `update`, `notifyError` or `notifyStatus`
* callbacks.
* `update` is called upon a successful request with its response data; in the
* 'provider-country' mode this will be a country code string and in the
* 'provider' mode - the default mode of operation for this class - this will
* be a `NetworkGeoPositionObject` instance.
* `notifyError` is called whenever the request gets an error from the local
* network subsystem, the server or simply times out.
* `notifyStatus` is called for each status change of the request that may be
* of interest to the consumer of this class. Currently the following status
* changes are reported: 'xhr-start', 'xhr-timeout', 'xhr-error' and
* 'xhr-empty'.
*
* @param {Array} wifiData Optional set of publicly available wifi networks
* in the following structure:
* <code>
* [
* { macAddress: <mac1>, signalStrength: <signal1> },
* { macAddress: <mac2>, signalStrength: <signal2> }
* ]
* </code>
*/
sendLocationRequest(wifiData) {
let data = { cellTowers: undefined, wifiAccessPoints: undefined };
if (wifiData && wifiData.length >= 2) {
data.wifiAccessPoints = wifiData;
}
let useCached = isCachedRequestMoreAccurateThanServerRequest(
data.cellTowers,
data.wifiAccessPoints
);
// The 'provider' mode is the only one that supports response caching at the
// moment.
if (this.mode == "provider") {
let useCached = isCachedRequestMoreAccurateThanServerRequest(
data.cellTowers,
data.wifiAccessPoints
);
LOG("Use request cache:" + useCached + " reason:" + gDebugCacheReasoning);
LOG("Use request cache:" + useCached + " reason:" + gDebugCacheReasoning);
if (useCached) {
gCachedRequest.location.timestamp = Date.now();
if (this.listener) {
this.listener.update(gCachedRequest.location);
if (useCached) {
gCachedRequest.location.timestamp = Date.now();
if (this.listener) {
this.listener.update(gCachedRequest.location);
}
return;
}
return;
}
// From here on, do a network geolocation request //
let url = Services.urlFormatter.formatURLPref("geo.provider.network.url");
let url = Services.urlFormatter.formatURLPref(
"geo." + this.mode + ".network.url"
);
LOG("Sending request");
let xhr = new XMLHttpRequest();
this.onStatus(false, "xhr-start");
try {
xhr.open("POST", url, true);
xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
} catch (e) {
notifyPositionUnavailable(this.listener);
this.onStatus(true, "xhr-error");
return;
}
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
xhr.responseType = "json";
xhr.mozBackgroundRequest = true;
// The timeout value doesn't need to change in a different mode.
xhr.timeout = Services.prefs.getIntPref("geo.provider.network.timeout");
xhr.ontimeout = () => {
LOG("Location request XHR timed out.");
notifyPositionUnavailable(this.listener);
this.onStatus(true, "xhr-timeout");
};
xhr.onerror = () => {
notifyPositionUnavailable(this.listener);
this.onStatus(true, "xhr-error");
};
xhr.onload = () => {
LOG(
@ -439,38 +541,39 @@ NetworkGeolocationProvider.prototype = {
);
if (
(xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) ||
!xhr.response ||
!xhr.response.location
!xhr.response
) {
notifyPositionUnavailable(this.listener);
this.onStatus(true, !xhr.response ? "xhr-empty" : "xhr-error");
return;
}
let newLocation = new NetworkGeoPositionObject(
xhr.response.location.lat,
xhr.response.location.lng,
xhr.response.accuracy
);
let newLocation;
if (this.mode == "provider-country") {
newLocation = xhr.response && xhr.response.country_code;
} else {
newLocation = new NetworkGeoPositionObject(
xhr.response.location.lat,
xhr.response.location.lng,
xhr.response.accuracy
);
}
if (this.listener) {
this.listener.update(newLocation);
}
gCachedRequest = new CachedRequest(
newLocation,
data.cellTowers,
data.wifiAccessPoints
);
if (this.mode == "provider") {
gCachedRequest = new CachedRequest(
newLocation,
data.cellTowers,
data.wifiAccessPoints
);
}
};
var requestData = JSON.stringify(data);
LOG("sending " + requestData);
xhr.send(requestData);
function notifyPositionUnavailable(listener) {
if (listener) {
listener.notifyError(POSITION_UNAVAILABLE);
}
}
},
};

View File

@ -84,7 +84,7 @@ function check_geolocation(location) {
ok(location, "Check to see if this location is non-null");
const timestamp = location.timestamp;
dump(`timestamp=$timestamp}\n`);
dump(`timestamp=${timestamp}\n`);
ok(IsNumber(timestamp), "check timestamp type");
ok(timestamp > 0, "check timestamp range");

View File

@ -4051,6 +4051,10 @@ pref("network.psl.onUpdate_notify", false);
pref("geo.provider.network.url", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#endif
pref("geo.provider-country.network.url", "https://location.services.mozilla.com/v1/country?key=%MOZILLA_API_KEY%");
pref("geo.provider-country.network.scan", false);
// Timeout to wait before sending the location request.
pref("geo.provider.network.timeToWaitBeforeSending", 5000);
// Timeout for outbound network geolocation provider.
pref("geo.provider.network.timeout", 60000);
@ -4496,8 +4500,6 @@ pref("browser.search.update.interval", 21600);
pref("browser.search.suggest.enabled", true);
pref("browser.search.suggest.enabled.private", false);
pref("browser.search.geoSpecificDefaults", false);
pref("browser.search.geoip.url", "https://location.services.mozilla.com/v1/country?key=%MOZILLA_API_KEY%");
pref("browser.search.geoip.timeout", 3000);
pref("browser.search.modernConfig", false);
pref("browser.search.separatePrivateDefault", false);
pref("browser.search.separatePrivateDefault.ui.enabled", false);

View File

@ -29,7 +29,6 @@ user_pref("browser.safebrowsing.provider.google4.gethashURL", "http://127.0.0.1/
user_pref("browser.safebrowsing.provider.google4.updateURL", "http://127.0.0.1/safebrowsing4-dummy/update");
user_pref("browser.safebrowsing.provider.mozilla.gethashURL", "http://127.0.0.1/safebrowsing-dummy/gethash");
user_pref("browser.safebrowsing.provider.mozilla.updateURL", "http://127.0.0.1/safebrowsing-dummy/update");
user_pref("browser.search.geoip.url", "");
user_pref("browser.shell.checkDefaultBrowser", false);
user_pref("browser.tabs.remote.autostart", true);
user_pref("browser.warnOnQuit", false);

View File

@ -3,7 +3,7 @@
/* eslint quotes: 0 */
user_pref("app.normandy.api_url", "https://%(server)s/selfsupport-dummy/");
user_pref("browser.safebrowsing.downloads.remote.url", "https://%(server)s/safebrowsing-dummy");
user_pref("browser.search.geoip.url", "https://%(server)s/geoip-dummy");
user_pref("browser.search.geoSpecificDefaults", false);
user_pref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
// Treat WebExtension API/schema warnings as errors.
user_pref("extensions.webextensions.warnings-as-errors", true);

View File

@ -18,8 +18,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
ExtensionParent: "resource://gre/modules/ExtensionParent.jsm",
getVerificationHash: "resource://gre/modules/SearchEngine.jsm",
OS: "resource://gre/modules/osfile.jsm",
IgnoreLists: "resource://gre/modules/IgnoreLists.jsm",
NetworkGeolocationProvider:
"resource://gre/modules/NetworkGeolocationProvider.jsm",
OS: "resource://gre/modules/osfile.jsm",
SearchEngine: "resource://gre/modules/SearchEngine.jsm",
SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.jsm",
SearchStaticData: "resource://gre/modules/SearchStaticData.jsm",
@ -127,7 +129,7 @@ var ensureKnownRegion = async function(ss, awaitRegionCheck) {
// If we have a region already stored in our prefs we trust it.
let region = Services.prefs.getCharPref("browser.search.region", "");
try {
if (!region) {
if (gGeoSpecificDefaultsEnabled && !region) {
// We don't have it cached, so fetch it. fetchRegion() will call
// storeRegion if it gets a result (even if that happens after the
// promise resolves) and fetchRegionDefault.
@ -148,7 +150,7 @@ var ensureKnownRegion = async function(ss, awaitRegionCheck) {
if (expired || !hasValidHashes) {
await new Promise(resolve => {
let timeoutMS = Services.prefs.getIntPref(
"browser.search.geoip.timeout"
"geo.provider.network.timeToWaitBeforeSending"
);
let timerId = setTimeout(() => {
timerId = null;
@ -246,134 +248,87 @@ async function storeRegion(region) {
}
// Get the region we are in via a XHR geoip request.
function fetchRegion(ss, awaitRegionCheck) {
async function fetchRegion(ss, awaitRegionCheck) {
// values for the SEARCH_SERVICE_COUNTRY_FETCH_RESULT 'enum' telemetry probe.
const TELEMETRY_RESULT_ENUM = {
SUCCESS: 0,
SUCCESS_WITHOUT_DATA: 1,
XHRTIMEOUT: 2,
ERROR: 3,
success: 0,
"xhr-empty": 1,
"xhr-timeout": 2,
"xhr-error": 3,
// Note that we expect to add finer-grained error types here later (eg,
// dns error, network error, ssl error, etc) with .ERROR remaining as the
// generic catch-all that doesn't fit into other categories.
};
let endpoint = Services.urlFormatter.formatURLPref(
"browser.search.geoip.url"
);
SearchUtils.log("_fetchRegion starting with endpoint " + endpoint);
// As an escape hatch, no endpoint means no geoip.
if (!endpoint) {
return Promise.resolve();
}
let startTime = Date.now();
return new Promise(resolve => {
// Instead of using a timeout on the xhr object itself, we simulate one
// using a timer and let the XHR request complete. This allows us to
// capture reliable telemetry on what timeout value should actually be
// used to ensure most users don't see one while not making it so large
// that many users end up doing a sync init of the search service and thus
// would see the jank that implies.
// (Note we do actually use a timeout on the XHR, but that's set to be a
// large value just incase the request never completes - we don't want the
// XHR object to live forever)
let timeoutMS = Services.prefs.getIntPref("browser.search.geoip.timeout");
let geoipTimeoutPossible = true;
let timerId = setTimeout(() => {
SearchUtils.log("_fetchRegion: timeout fetching region information");
if (geoipTimeoutPossible) {
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT")
.add(1);
}
timerId = null;
resolve();
}, timeoutMS);
let resolveAndReportSuccess = (result, reason) => {
// Even if we timed out, we want to save the region and everything
// related so next startup sees the value and doesn't retry this dance.
if (result) {
storeRegion(result).catch(Cu.reportError);
}
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_RESULT")
.add(reason);
let statusCallback = status => {
switch (status) {
case "xhr-start":
// This notification is just for tests...
Services.obs.notifyObservers(
null,
SearchUtils.TOPIC_SEARCH_SERVICE,
"geoip-lookup-xhr-starting"
);
break;
case "wifi-timeout":
SearchUtils.log("_fetchRegion: timeout fetching wifi information");
// Do nothing for now.
break;
}
};
// This notification is just for tests...
Services.obs.notifyObservers(
null,
SearchUtils.TOPIC_SEARCH_SERVICE,
"geoip-lookup-xhr-complete"
);
let networkGeo = new NetworkGeolocationProvider();
let result, errorResult;
try {
result = await networkGeo.getCountry(statusCallback);
} catch (ex) {
errorResult = ex;
Cu.reportError(ex);
}
if (timerId) {
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_TIMEOUT")
.add(0);
geoipTimeoutPossible = false;
}
let took = Date.now() - startTime;
// Even if we timed out, we want to save the region and everything
// related so next startup sees the value and doesn't retry this dance.
if (result) {
// As long as the asynchronous codepath in `storeRegion` is only used for
// telemetry, we don't need to await its completion.
storeRegion(result).catch(Cu.reportError);
}
SearchUtils.log(
"_fetchRegion got success response in " + took + "ms: " + result
);
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS")
.add(took);
let callback = () => {
// If we've already timed out then we've already resolved the promise,
// so there's nothing else to do.
if (timerId == null) {
return;
}
clearTimeout(timerId);
resolve();
};
// This notification is just for tests...
Services.obs.notifyObservers(
null,
SearchUtils.TOPIC_SEARCH_SERVICE,
"geoip-lookup-xhr-complete"
);
if (result && gGeoSpecificDefaultsEnabled && gModernConfig) {
ss._maybeReloadEngines(awaitRegionCheck).then(callback);
} else if (result && gGeoSpecificDefaultsEnabled && !gModernConfig) {
fetchRegionDefault(ss, awaitRegionCheck)
.then(callback)
.catch(err => {
Cu.reportError(err);
callback();
});
} else {
callback();
}
};
// Now that we know the current region, it's possible to fetch defaults,
// which we couldn't do before in `ensureKnownRegion`.
try {
if (result && gModernConfig) {
await ss._maybeReloadEngines(awaitRegionCheck);
} else if (result && !gModernConfig) {
await fetchRegionDefault(ss, awaitRegionCheck);
}
} catch (ex) {
Cu.reportError(ex);
}
let request = new XMLHttpRequest();
// This notification is just for tests...
Services.obs.notifyObservers(
request,
SearchUtils.TOPIC_SEARCH_SERVICE,
"geoip-lookup-xhr-starting"
);
request.timeout = 100000; // 100 seconds as the last-chance fallback
request.onload = function(event) {
let took = Date.now() - startTime;
let region = event.target.response && event.target.response.country_code;
SearchUtils.log(
"_fetchRegion got success response in " + took + "ms: " + region
);
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS")
.add(took);
let reason = region
? TELEMETRY_RESULT_ENUM.SUCCESS
: TELEMETRY_RESULT_ENUM.SUCCESS_WITHOUT_DATA;
resolveAndReportSuccess(region, reason);
};
request.ontimeout = function(event) {
SearchUtils.log(
"_fetchRegion: XHR finally timed-out fetching region information"
);
resolveAndReportSuccess(null, TELEMETRY_RESULT_ENUM.XHRTIMEOUT);
};
request.onerror = function(event) {
SearchUtils.log("_fetchRegion: failed to retrieve region information");
resolveAndReportSuccess(null, TELEMETRY_RESULT_ENUM.ERROR);
};
request.open("POST", endpoint, true);
request.setRequestHeader("Content-Type", "application/json");
request.responseType = "json";
request.send("{}");
});
let telemetryResult = TELEMETRY_RESULT_ENUM.success;
if (errorResult) {
telemetryResult =
TELEMETRY_RESULT_ENUM[errorResult] || TELEMETRY_RESULT_ENUM["xhr-error"];
}
Services.telemetry
.getHistogramById("SEARCH_SERVICE_COUNTRY_FETCH_RESULT")
.add(telemetryResult);
}
// This converts our legacy google engines to the
@ -1498,7 +1453,7 @@ SearchService.prototype = {
},
_reInit(origin, awaitRegionCheck = false) {
SearchUtils.log("_reInit");
SearchUtils.log("_reInit: " + awaitRegionCheck);
// Re-entrance guard, because we're using an async lambda below.
if (gReinitializing) {
SearchUtils.log("_reInit: already re-initializing, bailing out.");

View File

@ -43,17 +43,6 @@ var XULRuntime = Cc["@mozilla.org/xre/runtime;1"].getService(Ci.nsIXULRuntime);
// Expand the amount of information available in error logs
Services.prefs.setBoolPref("browser.search.log", true);
// The geo-specific search tests assume certain prefs are already setup, which
// might not be true when run in comm-central etc. So create them here.
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
Services.prefs.setIntPref("browser.search.geoip.timeout", 3000);
// But still disable geoip lookups - tests that need it will re-configure this.
Services.prefs.setCharPref("browser.search.geoip.url", "");
// Also disable region defaults - tests using it will also re-configure it.
Services.prefs
.getDefaultBranch(SearchUtils.BROWSER_SEARCH_PREF)
.setCharPref("geoSpecificDefaults.url", "");
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gModernConfig",
@ -449,7 +438,7 @@ async function withGeoServer(
let geoLookupUrl = geoLookupData
? `http://localhost:${srv.identity.primaryPort}/lookup_geoip`
: 'data:application/json,{"country_code": "FR"}';
Services.prefs.setCharPref("browser.search.geoip.url", geoLookupUrl);
Services.prefs.setCharPref("geo.provider-country.network.url", geoLookupUrl);
try {
await testFn(gRequests);
@ -459,7 +448,7 @@ async function withGeoServer(
Services.prefs.clearUserPref(
SearchUtils.BROWSER_SEARCH_PREF + PREF_SEARCH_URL
);
Services.prefs.clearUserPref("browser.search.geoip.url");
Services.prefs.clearUserPref("geo.provider-country.network.url");
}
}

View File

@ -102,7 +102,6 @@ class SearchConfigTest {
// Disable region checks.
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", false);
Services.prefs.setCharPref("browser.search.geoip.url", "");
// Enable separatePrivateDefault testing. We test with this on, as we have
// separate tests for ensuring the normal = private when this is off.

View File

@ -44,8 +44,6 @@ add_task(async function should_get_geo_defaults_only_once() {
// (Re)initializing the search service should trigger a request,
// and set the default engine based on it.
// Due to the previous initialization, we expect the region to already be set.
Assert.ok(Services.prefs.prefHasUserValue("browser.search.region"));
Assert.equal(Services.prefs.getCharPref("browser.search.region"), "FR");
await Promise.all([
asyncReInit({ awaitRegionFetch: true }),
promiseAfterCache(),

View File

@ -5,10 +5,9 @@ const kUrlPref = "geoSpecificDefaults.url";
add_task(async function setup() {
await useTestEngines("simple-engines");
// Geo specific defaults won't be fetched if there's no country code.
Services.prefs.setCharPref(
"browser.search.geoip.url",
"geo.provider-country.network.url",
'data:application/json,{"country_code": "US"}'
);
@ -22,6 +21,7 @@ add_task(async function setup() {
visibleDefaultEngines: ["hidden"],
},
});
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
Services.prefs
.getDefaultBranch(SearchUtils.BROWSER_SEARCH_PREF)
.setCharPref(kUrlPref, url);

View File

@ -7,6 +7,7 @@ const SEARCH_SERVICE_TOPIC = "browser-search-service";
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
add_task(async function setup() {
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
await AddonTestUtils.promiseStartupManager();
});

View File

@ -3,11 +3,15 @@
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
Services.prefs
.getDefaultBranch(SearchUtils.BROWSER_SEARCH_PREF)
.setCharPref("geoSpecificDefaults.url", "");
});
add_task(async function test_location() {
Services.prefs.setCharPref(
"browser.search.geoip.url",
"geo.provider-country.network.url",
'data:application/json,{"country_code": "AU"}'
);
await Services.search.init(true);
@ -18,12 +22,6 @@ add_task(async function test_location() {
);
// check we have "success" recorded in telemetry
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS);
// a false value for SEARCH_SERVICE_COUNTRY_TIMEOUT
let histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_TIMEOUT"
);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, { 0: 1, 1: 0 }); // boolean probe so 3 buckets, expect 1 result for |0|.
// simple checks for our platform-specific telemetry. We can't influence
// what they return (as we can't influence the countryCode the platform
@ -62,8 +60,8 @@ add_task(async function test_location() {
countryCode == "AU" ? { 0: 1, 1: 0 } : { 0: 0, 1: 1, 2: 0 };
}
histogram = Services.telemetry.getHistogramById(hid);
snapshot = histogram.snapshot();
let histogram = Services.telemetry.getHistogramById(hid);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, expectedResult);
}
});

View File

@ -3,13 +3,14 @@
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
});
add_task(async function test_location_error() {
// We use an invalid port that parses but won't open
let url = "http://localhost:0";
Services.prefs.setCharPref("browser.search.geoip.url", url);
Services.prefs.setCharPref("geo.provider-country.network.url", url);
await Services.search.init();
try {
Services.prefs.getCharPref("browser.search.region");
@ -17,10 +18,4 @@ add_task(async function test_location_error() {
} catch (ex) {}
// should have an error recorded.
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.ERROR);
// but false values for timeout
let histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_TIMEOUT"
);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, { 0: 1, 1: 0 }); // boolean probe so 3 buckets, expect 1 result for |0|.
});

View File

@ -23,12 +23,13 @@ function promiseTimezoneMessage() {
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
});
add_task(async function test_location_malformed_json() {
// Here we have malformed JSON
Services.prefs.setCharPref(
"browser.search.geoip.url",
"geo.provider-country.network.url",
'data:application/json,{"country_code"'
);
await Services.search.init();
@ -44,10 +45,4 @@ add_task(async function test_location_malformed_json() {
);
// should have recorded SUCCESS_WITHOUT_DATA
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS_WITHOUT_DATA);
// and false values for timeout.
let histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_TIMEOUT"
);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, { 0: 1, 1: 0 }); // boolean probe so 3 buckets, expect 1 result for |0|.
});

View File

@ -29,6 +29,7 @@ function getProbeSum(probe, sum) {
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
});
add_task(async function test_location_timeout() {
@ -40,8 +41,8 @@ add_task(async function test_location_timeout() {
let server = startServer(continuePromise);
let url =
"http://localhost:" + server.identity.primaryPort + "/lookup_country";
Services.prefs.setCharPref("browser.search.geoip.url", url);
Services.prefs.setIntPref("browser.search.geoip.timeout", 50);
Services.prefs.setCharPref("geo.provider-country.network.url", url);
Services.prefs.setIntPref("geo.provider.network.timeout", 3000);
await Services.search.init();
ok(
!Services.prefs.prefHasUserValue("browser.search.region"),
@ -50,12 +51,6 @@ add_task(async function test_location_timeout() {
// should be no result recorded at all.
checkCountryResultTelemetry(null);
// should have set the flag indicating we saw a timeout.
let histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_TIMEOUT"
);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, { 0: 0, 1: 1, 2: 0 });
// should not yet have SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS recorded as our
// test server is still blocked on our promise.
equal(getProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS"), 0);
@ -72,8 +67,8 @@ add_task(async function test_location_timeout() {
// it timed out.
// The telemetry "sum" will be the actual time in ms - just check it's non-zero.
ok(getProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS") != 0);
// should have reported the fetch ended up being successful
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.SUCCESS);
// should have reported the fetch ended up being successful.
checkCountryResultTelemetry(TELEMETRY_RESULT_ENUM.success);
// and should have the result of the response that finally came in, and
// everything dependent should also be updated.
@ -81,9 +76,7 @@ add_task(async function test_location_timeout() {
await SearchTestUtils.promiseSearchNotification("engines-reloaded");
await (() => {
return new Promise(resolve => {
server.stop(resolve);
});
})();
await new Promise(resolve => {
server.stop(resolve);
});
});

View File

@ -56,13 +56,6 @@ add_task(async function test_location_timeout_xhr() {
// should be no result recorded at all.
checkCountryResultTelemetry(null);
// should have set the flag indicating we saw a timeout.
let histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_TIMEOUT"
);
let snapshot = histogram.snapshot();
deepEqual(snapshot.values, { 0: 0, 1: 1, 2: 0 });
// should not have SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS recorded as our
// test server is still blocked on our promise.
verifyProbeSum("SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS", 0);

View File

@ -8,6 +8,7 @@ const SEARCH_SERVICE_TOPIC = "browser-search-service";
add_task(async function setup() {
await AddonTestUtils.promiseStartupManager();
await useTestEngines("data", "geolookup-extensions");
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
});
add_task(async function test_maybereloadengine_update() {

View File

@ -17,6 +17,7 @@ add_task(async function setup() {
installDistributionEngine();
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
await AddonTestUtils.promiseStartupManager();
});

View File

@ -58,6 +58,7 @@ function listenFor(name, key) {
add_task(async function setup() {
Services.prefs.setBoolPref("browser.search.separatePrivateDefault", true);
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
await useTestEngines("data", null, CONFIG);
await AddonTestUtils.promiseStartupManager();
@ -66,7 +67,7 @@ add_task(async function setup() {
add_task(async function test_regular_init() {
let reloadObserved = listenFor(SEARCH_SERVICE_TOPIC, "engines-reloaded");
let geoUrl = `data:application/json,{"country_code": "FR"}`;
Services.prefs.setCharPref("browser.search.geoip.url", geoUrl);
Services.prefs.setCharPref("geo.provider-country.network.url", geoUrl);
await Promise.all([
Services.search.init(true),
@ -103,7 +104,7 @@ add_task(async function test_init_with_slow_region_lookup() {
});
Services.prefs.setCharPref(
"browser.search.geoip.url",
"geo.provider-country.network.url",
`http://localhost:${srv.identity.primaryPort}/fetch_region`
);

View File

@ -8968,14 +8968,6 @@
"n_values": 8,
"description": "Result of XHR request fetching the country-code. 0=SUCCESS, 1=SUCCESS_WITHOUT_DATA, 2=XHRTIMEOUT, 3=ERROR (rest reserved for finer-grained error codes later)"
},
"SEARCH_SERVICE_COUNTRY_TIMEOUT": {
"record_in_processes": ["main", "content"],
"products": ["firefox", "fennec", "geckoview", "thunderbird"],
"alert_emails": ["mdeboer@mozilla.com", "fx-search@mozilla.com"],
"expires_in_version": "never",
"kind": "boolean",
"description": "True if we stopped waiting for the XHR response before it completed"
},
"SEARCH_SERVICE_US_COUNTRY_MISMATCHED_TIMEZONE": {
"record_in_processes": ["main", "content"],
"products": ["firefox", "fennec", "geckoview"],

View File

@ -815,7 +815,6 @@
"SAFE_MODE_USAGE",
"SEARCH_SERVICE_COUNTRY_FETCH_RESULT",
"SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS",
"SEARCH_SERVICE_COUNTRY_TIMEOUT",
"SEARCH_SERVICE_NONUS_COUNTRY_MISMATCHED_PLATFORM_OSX",
"SEARCH_SERVICE_NONUS_COUNTRY_MISMATCHED_PLATFORM_WIN",
"SEARCH_SERVICE_US_COUNTRY_MISMATCHED_PLATFORM_OSX",