368 lines
11 KiB
JavaScript
368 lines
11 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 { 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"
|
|
);
|
|
await Region._fetchRegion();
|
|
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"'
|
|
);
|
|
await Region._fetchRegion();
|
|
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();
|
|
});
|
|
});
|
|
|
|
await Region._fetchRegion();
|
|
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"
|
|
);
|
|
}
|