Files
tubestation/toolkit/modules/tests/xpcshell/test_Region.js
Stanca Serban 4f0eb0f875 Backed out 8 changesets (bug 1963014) for causing mochitests failures in browser_UsageTelemetry.js. CLOSED TREE
Backed out changeset 10cd387da114 (bug 1963014)
Backed out changeset db1cc23f2502 (bug 1963014)
Backed out changeset 076cbc895e0c (bug 1963014)
Backed out changeset 4df46947d96f (bug 1963014)
Backed out changeset 8692782e408c (bug 1963014)
Backed out changeset ddbecd248a02 (bug 1963014)
Backed out changeset f25d7077fec6 (bug 1963014)
Backed out changeset 96e088ca29d2 (bug 1963014)
2025-04-28 23:08:13 +03:00

376 lines
12 KiB
JavaScript

"use strict";
const { HttpServer } = ChromeUtils.importESModule(
"resource://testing-common/httpd.sys.mjs"
);
const { setTimeout } = ChromeUtils.importESModule(
"resource://gre/modules/Timer.sys.mjs"
);
const { TestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TestUtils.sys.mjs"
);
const { sinon } = ChromeUtils.importESModule(
"resource://testing-common/Sinon.sys.mjs"
);
ChromeUtils.defineESModuleGetters(this, {
Region: "resource://gre/modules/Region.sys.mjs",
RegionTestUtils: "resource://testing-common/RegionTestUtils.sys.mjs",
});
const INTERVAL_PREF = "browser.region.update.interval";
const RESPONSE_DELAY = 500;
const RESPONSE_TIMEOUT = 100;
const histogram = Services.telemetry.getHistogramById(
"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
// task to fetch the region, ensure we have completed this before
// running the rest of the tests.
add_task(async function test_startup_with_no_pref() {
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);
Assert.equal(
Glean.region.homeRegion.testGetValue(),
"AT",
"Should have correctly stored the region in home region after getting it"
);
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() {
Services.fog.testResetFOG();
let srv = useHttpServer(RegionTestUtils.REGION_URL_PREF);
srv.registerPathHandler("/", (req, res) => {
res.setStatusLine("1.1", 200, "OK");
send(res, { country_code: "UK" });
});
// start to listen the notification
let updateRegion = TestUtils.topicObserved("browser-region-updated");
await Region._fetchRegion();
let [subject] = await updateRegion;
Assert.ok(true, "Region fetch should succeed");
Assert.equal(Region.home, "UK", "Region fetch should return correct result");
Assert.equal(
subject,
Region.home,
"Notification should be sent with the correct region"
);
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);
});
add_task(async function test_invalid_url() {
histogram.clear();
Services.prefs.setIntPref("browser.region.retry-timeout", 0);
Services.prefs.setCharPref(
RegionTestUtils.REGION_URL_PREF,
"http://localhost:0"
);
let result = await Region._fetchRegion();
Assert.ok(!result, "Should return no result");
await checkTelemetry(Region.TELEMETRY.NO_RESULT);
});
add_task(async function test_invalid_json() {
histogram.clear();
Services.prefs.setCharPref(
RegionTestUtils.REGION_URL_PREF,
'data:application/json,{"country_code"'
);
let result = await Region._fetchRegion();
Assert.ok(!result, "Should return no result");
await checkTelemetry(Region.TELEMETRY.NO_RESULT);
});
add_task(async function test_timeout() {
histogram.clear();
Services.prefs.setIntPref("browser.region.retry-timeout", 0);
Services.prefs.setIntPref("browser.region.timeout", RESPONSE_TIMEOUT);
let srv = useHttpServer(RegionTestUtils.REGION_URL_PREF);
srv.registerPathHandler("/", (req, res) => {
res.processAsync();
do_timeout(RESPONSE_DELAY, () => {
send(res, { country_code: "UK" });
res.finish();
});
});
let result = await Region._fetchRegion();
Assert.equal(result, null, "Region fetch should return null");
await checkTelemetry(Region.TELEMETRY.TIMEOUT);
await cleanup(srv);
});
add_task(async function test_location() {
let location = { location: { lat: -1, lng: 1 }, accuracy: 100 };
let srv = useHttpServer("geo.provider.network.url");
srv.registerPathHandler("/", (req, res) => {
res.setStatusLine("1.1", 200, "OK");
send(res, location);
});
let result = await Region._getLocation();
Assert.ok(true, "Region fetch should succeed");
Assert.deepEqual(result, location, "Location is returned");
await cleanup(srv);
});
add_task(async function test_update() {
RegionTestUtils.setNetworkRegion("FR");
await Region._fetchRegion();
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");
await Region._fetchRegion();
Assert.equal(Region.home, "FR", "Shouldnt have changed yet");
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
// it isnt updating when it shouldnt.
await Region._fetchRegion();
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);
/* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise(resolve => setTimeout(resolve, 1100));
await Region._fetchRegion();
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();
});
add_task(async function test_update_us() {
Services.fog.testResetFOG();
// Setting the region to US whilst within a US timezone should work.
let stub = sinon.stub(Region, "_isUSTimezone").returns(true);
Region._home = null;
RegionTestUtils.setNetworkRegion("US");
await Region._fetchRegion();
assertStoredResultTelemetry({ unitedStates: 1 });
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();
// Setting the region to US whilst not within a US timezone should not work.
stub.returns(false);
Region._home = null;
RegionTestUtils.setNetworkRegion("US");
await Region._fetchRegion();
assertStoredResultTelemetry({ ignoredUnitedStates: 1 });
Assert.equal(Region.home, null, "Should have not set the region");
sinon.restore();
});
add_task(async function test_max_retry() {
Region._home = null;
let requestsSeen = 0;
Services.prefs.setIntPref("browser.region.retry-timeout", RESPONSE_TIMEOUT);
Services.prefs.setIntPref("browser.region.timeout", RESPONSE_TIMEOUT);
let srv = useHttpServer(RegionTestUtils.REGION_URL_PREF);
srv.registerPathHandler("/", (req, res) => {
requestsSeen++;
res.setStatusLine("1.1", 200, "OK");
res.processAsync();
do_timeout(RESPONSE_DELAY, res.finish.bind(res));
});
Region._fetchRegion();
await TestUtils.waitForCondition(() => requestsSeen === 3);
/* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise(resolve => setTimeout(resolve, RESPONSE_DELAY));
Assert.equal(Region.home, null, "failed to fetch region");
Assert.equal(requestsSeen, 3, "Retried 4 times");
Region._retryCount = 0;
await cleanup(srv);
});
add_task(async function test_retry() {
Region._home = null;
let requestsSeen = 0;
Services.prefs.setIntPref("browser.region.retry-timeout", RESPONSE_TIMEOUT);
Services.prefs.setIntPref("browser.region.timeout", RESPONSE_TIMEOUT);
let srv = useHttpServer(RegionTestUtils.REGION_URL_PREF);
srv.registerPathHandler("/", (req, res) => {
res.setStatusLine("1.1", 200, "OK");
if (++requestsSeen == 2) {
res.setStatusLine("1.1", 200, "OK");
send(res, { country_code: "UK" });
} else {
res.processAsync();
do_timeout(RESPONSE_DELAY, res.finish.bind(res));
}
});
Region._fetchRegion();
await TestUtils.waitForCondition(() => requestsSeen === 2);
/* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise(resolve => setTimeout(resolve, RESPONSE_DELAY));
Assert.equal(Region.home, "UK", "failed to fetch region");
Assert.equal(requestsSeen, 2, "Retried 2 times");
await cleanup(srv);
});
add_task(async function test_timerManager() {
RegionTestUtils.setNetworkRegion("FR");
// Ensure the home region updates immediately, but the update
// check will only happen once per second.
Services.prefs.setIntPref("browser.region.update.interval", 0);
Services.prefs.setIntPref("browser.region.update.debounce", 1);
let region = Region.newInstance();
await region.init();
Assert.equal(region.home, "FR", "Should have correct initial region");
// Updates are being debounced, these should be ignored.
RegionTestUtils.setNetworkRegion("DE");
await region._updateTimer();
await region._updateTimer();
Assert.equal(region.home, "FR", "Ignored updates to region");
// Set the debounce interval to 0 so these updates are used.
Services.prefs.setIntPref("browser.region.update.debounce", 0);
RegionTestUtils.setNetworkRegion("AU");
await region._updateTimer();
await region._updateTimer();
Assert.equal(region.home, "AU", "region has been updated");
await cleanup();
});
function useHttpServer(pref) {
let server = new HttpServer();
server.start(-1);
Services.prefs.setCharPref(
pref,
`http://localhost:${server.identity.primaryPort}/`
);
return server;
}
function send(res, json) {
res.setStatusLine("1.1", 200, "OK");
res.setHeader("content-type", "application/json", true);
res.write(JSON.stringify(json));
}
async function cleanup(srv = null) {
Services.prefs.clearUserPref("browser.search.region");
Region._home = null;
if (srv) {
await new Promise(r => srv.stop(r));
}
}
async function checkTelemetry(aExpectedValue) {
// Wait until there is 1 result.
await TestUtils.waitForCondition(() => {
let snapshot = histogram.snapshot();
return Object.values(snapshot.values).reduce((a, b) => a + b, 0) == 1;
});
let snapshot = histogram.snapshot();
Assert.equal(snapshot.values[aExpectedValue], 1);
}
function assertStoredResultTelemetry({
restOfWorld = null,
unitedStates = null,
ignoredUnitedStates = null,
}) {
Assert.equal(
Glean.region.storeRegionResult.ignoredUnitedStatesIncorrectTimezone.testGetValue(),
ignoredUnitedStates,
"Should have the expected count for ignoring setting the region when US but not in the correct timezone"
);
Assert.equal(
Glean.region.storeRegionResult.setForUnitedStates.testGetValue(),
unitedStates,
"Should have the expected count for setting the region for the US"
);
Assert.equal(
Glean.region.storeRegionResult.setForRestOfWorld.testGetValue(),
restOfWorld,
"Should have the expected count for setting the region for the rest of the world"
);
}