Bug 1929411 - Add home region telemetry to Glean. r=scunnane

Differential Revision: https://phabricator.services.mozilla.com/D244155
This commit is contained in:
Mark Banner
2025-04-10 11:24:43 +00:00
parent ad72571435
commit 49a98cf418
3 changed files with 121 additions and 14 deletions

View File

@@ -124,7 +124,10 @@ class RegionDetector {
// Keep track of how many times we have tried to fetch // Keep track of how many times we have tried to fetch
// the users region during failure. // the users region during failure.
_retryCount = 0; _retryCount = 0;
// Let tests wait for init to complete. /**
* @type {Promise}
* Allow tests to wait for init to be complete.
*/
_initPromise = null; _initPromise = null;
// Topic for Observer events fired by Region.sys.mjs. // Topic for Observer events fired by Region.sys.mjs.
REGION_TOPIC = "browser-region-updated"; REGION_TOPIC = "browser-region-updated";
@@ -140,11 +143,18 @@ class RegionDetector {
* Read currently stored region data and if needed trigger background * Read currently stored region data and if needed trigger background
* region detection. * region detection.
*/ */
async init() { init() {
// If we're running in the child process, then all `Region` does is act
// as a proxy for the browser.search.region preference.
if (inChildProcess) {
this._home = Services.prefs.getCharPref(REGION_PREF, null);
return Promise.resolve();
}
if (this._initPromise) { if (this._initPromise) {
return this._initPromise; return this._initPromise;
} }
if (lazy.cacheBustEnabled && !inChildProcess) { if (lazy.cacheBustEnabled) {
Services.tm.idleDispatchToMainThread(() => { Services.tm.idleDispatchToMainThread(() => {
lazy.timerManager.registerTimer( lazy.timerManager.registerTimer(
UPDATE_CHECK_NAME, UPDATE_CHECK_NAME,
@@ -155,10 +165,13 @@ class RegionDetector {
} }
let promises = []; let promises = [];
this._home = Services.prefs.getCharPref(REGION_PREF, null); this._home = Services.prefs.getCharPref(REGION_PREF, null);
if (!this._home && !inChildProcess) { if (this._home) {
// On startup, ensure the Glean probe knows the home region from preferences.
Glean.region.homeRegion.set(this._home);
} else {
promises.push(this._idleDispatch(() => this._fetchRegion())); promises.push(this._idleDispatch(() => this._fetchRegion()));
} }
if (lazy.localGeocodingEnabled && !inChildProcess) { if (lazy.localGeocodingEnabled) {
promises.push(this._idleDispatch(() => this._setupRemoteSettings())); promises.push(this._idleDispatch(() => this._setupRemoteSettings()));
} }
return (this._initPromise = Promise.all(promises)); return (this._initPromise = Promise.all(promises));
@@ -167,7 +180,7 @@ class RegionDetector {
/** /**
* Get the region we currently consider the users home. * Get the region we currently consider the users home.
* *
* @returns {string} * @returns {?string}
* The users current home region. * The users current home region.
*/ */
get home() { get home() {
@@ -314,6 +327,7 @@ class RegionDetector {
log.info("Updating home region:", region); log.info("Updating home region:", region);
this._home = region; this._home = region;
Services.prefs.setCharPref("browser.search.region", region); Services.prefs.setCharPref("browser.search.region", region);
Glean.region.homeRegion.set(region);
if (notify) { if (notify) {
Services.obs.notifyObservers( Services.obs.notifyObservers(
this._createSupportsString(region), this._createSupportsString(region),

View File

@@ -71,6 +71,30 @@ region:
no_lint: no_lint:
- COMMON_PREFIX - COMMON_PREFIX
home_region:
type: string
lifetime: application
description: >
Records the detected home region of the user. This is the general region
of the user's machine.
If a machine moves location, there is a minimum 2-week delay before this
will be updated.
See the [Region documentation](https://firefox-source-docs.mozilla.org/toolkit/modules/toolkit_modules/Region.html)
for more information about updates.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1419788
- https://bugzilla.mozilla.org/show_bug.cgi?id=1929411
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1419788
- https://bugzilla.mozilla.org/show_bug.cgi?id=1929411
notification_emails:
- fx-search-telemetry@mozilla.com
data_sensitivity:
- interaction
expires: never
store_region_result: store_region_result:
type: labeled_counter type: labeled_counter
description: > description: >

View File

@@ -3,9 +3,6 @@
const { HttpServer } = ChromeUtils.importESModule( const { HttpServer } = ChromeUtils.importESModule(
"resource://testing-common/httpd.sys.mjs" "resource://testing-common/httpd.sys.mjs"
); );
const { Region } = ChromeUtils.importESModule(
"resource://gre/modules/Region.sys.mjs"
);
const { setTimeout } = ChromeUtils.importESModule( const { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs" "resource://gre/modules/Timer.sys.mjs"
); );
@@ -17,6 +14,7 @@ const { sinon } = ChromeUtils.importESModule(
); );
ChromeUtils.defineESModuleGetters(this, { ChromeUtils.defineESModuleGetters(this, {
Region: "resource://gre/modules/Region.sys.mjs",
RegionTestUtils: "resource://testing-common/RegionTestUtils.sys.mjs", RegionTestUtils: "resource://testing-common/RegionTestUtils.sys.mjs",
}); });
@@ -29,15 +27,52 @@ const histogram = Services.telemetry.getHistogramById(
"SEARCH_SERVICE_COUNTRY_FETCH_RESULT" "SEARCH_SERVICE_COUNTRY_FETCH_RESULT"
); );
add_setup(async () => {
Services.prefs.setBoolPref("browser.region.log", true);
});
// Region.sys.mjs will call init() on being loaded and set a background // Region.sys.mjs will call init() on being loaded and set a background
// task to fetch the region, ensure we have completed this before // task to fetch the region, ensure we have completed this before
// running the rest of the tests. // running the rest of the tests.
add_task(async function test_startup() { add_task(async function test_startup_with_no_pref() {
RegionTestUtils.setNetworkRegion("UK"); Services.fog.testResetFOG();
RegionTestUtils.setNetworkRegion("AT");
// Region.sys.mjs is lazily loaded, so referencing `Region.` here will load
// it and automatically call the `Region.init()` function.
await checkTelemetry(Region.TELEMETRY.SUCCESS); await checkTelemetry(Region.TELEMETRY.SUCCESS);
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"AT",
"Should have correctly stored the region in home region after getting it"
);
await cleanup(); await cleanup();
}); });
add_task(async function test_startup_with_pref() {
Services.fog.testResetFOG();
Services.prefs.setCharPref("browser.search.region", "GB");
// If we failed to read the pref, we'd kick off a network connection. So set
// up the network to return a different region here so that we'd be able to
// detect that case.
RegionTestUtils.setNetworkRegion("DE");
// Use a different instance of region for testing this.
let region = Region.newInstance();
await region.init();
Assert.equal(region.home, "GB", "Should have loaded the correct region");
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"GB",
"Should have correctly stored the region in home region after getting it"
);
});
add_task(async function test_basic() { add_task(async function test_basic() {
Services.fog.testResetFOG(); Services.fog.testResetFOG();
@@ -61,6 +96,12 @@ add_task(async function test_basic() {
assertStoredResultTelemetry({ restOfWorld: 1 }); assertStoredResultTelemetry({ restOfWorld: 1 });
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"UK",
"Should have correctly set the region in home region after getting it"
);
await cleanup(srv); await cleanup(srv);
}); });
@@ -123,23 +164,45 @@ add_task(async function test_location() {
}); });
add_task(async function test_update() { add_task(async function test_update() {
Region._home = null;
RegionTestUtils.setNetworkRegion("FR"); RegionTestUtils.setNetworkRegion("FR");
await Region._fetchRegion(); await Region._fetchRegion();
Assert.equal(Region.home, "FR", "Should have correct region"); Assert.equal(Region.home, "FR", "Should have correct region");
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"FR",
"Should have correctly set the region in home region after getting it"
);
RegionTestUtils.setNetworkRegion("DE"); RegionTestUtils.setNetworkRegion("DE");
await Region._fetchRegion(); await Region._fetchRegion();
Assert.equal(Region.home, "FR", "Shouldnt have changed yet"); Assert.equal(Region.home, "FR", "Shouldnt have changed yet");
// Thie first fetchRegion will set the prefs to determine when Assert.equal(
Glean.region.homeRegion.testGetValue(),
"FR",
"Should not have updated the home region telemetry yet"
);
// The first fetchRegion will set the prefs to determine when
// to update the home region, we need to do 2 fetchRegions to test // to update the home region, we need to do 2 fetchRegions to test
// it isnt updating when it shouldnt. // it isnt updating when it shouldnt.
await Region._fetchRegion(); await Region._fetchRegion();
Assert.equal(Region.home, "FR", "Shouldnt have changed yet again"); Assert.equal(Region.home, "FR", "Shouldnt have changed yet again");
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"FR",
"Should not have updated the home region telemetry yet (again)"
);
Services.prefs.setIntPref(INTERVAL_PREF, 1); Services.prefs.setIntPref(INTERVAL_PREF, 1);
/* eslint-disable mozilla/no-arbitrary-setTimeout */ /* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise(resolve => setTimeout(resolve, 1100)); await new Promise(resolve => setTimeout(resolve, 1100));
await Region._fetchRegion(); await Region._fetchRegion();
Assert.equal(Region.home, "DE", "Should have updated now"); Assert.equal(Region.home, "DE", "Should have updated now");
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"DE",
"Should have correctly set the home region telemetry"
);
await cleanup(); await cleanup();
}); });
@@ -155,6 +218,11 @@ add_task(async function test_update_us() {
assertStoredResultTelemetry({ unitedStates: 1 }); assertStoredResultTelemetry({ unitedStates: 1 });
Assert.equal(Region.home, "US", "Should have correct region"); Assert.equal(Region.home, "US", "Should have correct region");
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"US",
"Should have correctly set the home region telemetry"
);
Services.fog.testResetFOG(); Services.fog.testResetFOG();
@@ -268,6 +336,7 @@ function send(res, json) {
async function cleanup(srv = null) { async function cleanup(srv = null) {
Services.prefs.clearUserPref("browser.search.region"); Services.prefs.clearUserPref("browser.search.region");
Region._home = null;
if (srv) { if (srv) {
await new Promise(r => srv.stop(r)); await new Promise(r => srv.stop(r));
} }
@@ -277,7 +346,7 @@ async function checkTelemetry(aExpectedValue) {
// Wait until there is 1 result. // Wait until there is 1 result.
await TestUtils.waitForCondition(() => { await TestUtils.waitForCondition(() => {
let snapshot = histogram.snapshot(); let snapshot = histogram.snapshot();
return Object.values(snapshot.values).reduce((a, b) => a + b) == 1; return Object.values(snapshot.values).reduce((a, b) => a + b, 0) == 1;
}); });
let snapshot = histogram.snapshot(); let snapshot = histogram.snapshot();
Assert.equal(snapshot.values[aExpectedValue], 1); Assert.equal(snapshot.values[aExpectedValue], 1);