mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
Bug 1690105 - Implement RemoteSettings client in DoHConfig.jsm for provider and config data collections. r=dragana,preferences-reviewers,Gijs
Differential Revision: https://phabricator.services.mozilla.com/D103714
This commit is contained in:
parent
71eae32383
commit
475c6ea29c
@ -5,72 +5,287 @@
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* This module provides an interface to acces DoH config settings - e.g. whether
|
||||
* DoH is enabled, whether capabilities are enabled, etc. Currently this just
|
||||
* provides getters for prefs, but imminently will be extended to read config
|
||||
* from a Remote Settings collection and filter by client region etc.
|
||||
* This module provides an interface to access DoH configuration - e.g. whether
|
||||
* DoH is enabled, whether capabilities are enabled, etc. The configuration is
|
||||
* sourced from either Remote Settings or pref values, with Remote Settings
|
||||
* being preferred.
|
||||
*/
|
||||
var EXPORTED_SYMBOLS = ["Config"];
|
||||
var EXPORTED_SYMBOLS = ["DoHConfigController"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Preferences",
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const kEnabledPref = "doh-rollout.enabled";
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Preferences: "resource://gre/modules/Preferences.jsm",
|
||||
Region: "resource://gre/modules/Region.jsm",
|
||||
RemoteSettings: "resource://services-settings/remote-settings.js",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
});
|
||||
|
||||
const kTRRSelectionEnabledPref = "doh-rollout.trr-selection.enabled";
|
||||
const kTRRSelectionCommitResultPref = "doh-rollout.trr-selection.commit-result";
|
||||
const kGlobalPrefBranch = "doh-rollout";
|
||||
var kRegionPrefBranch;
|
||||
|
||||
const kProviderSteeringEnabledPref = "doh-rollout.provider-steering.enabled";
|
||||
const kProviderSteeringListPref = "doh-rollout.provider-steering.provider-list";
|
||||
const kEnabledPref = "enabled";
|
||||
|
||||
const kProvidersPref = "provider-list";
|
||||
|
||||
const kTRRSelectionEnabledPref = "trr-selection.enabled";
|
||||
const kTRRSelectionProvidersPref = "trr-selection.provider-list";
|
||||
const kTRRSelectionCommitResultPref = "trr-selection.commit-result";
|
||||
|
||||
const kProviderSteeringEnabledPref = "provider-steering.enabled";
|
||||
const kProviderSteeringListPref = "provider-steering.provider-list";
|
||||
|
||||
const kPrefChangedTopic = "nsPref:changed";
|
||||
|
||||
const Config = {
|
||||
init() {
|
||||
Preferences.observe(kEnabledPref, this);
|
||||
const gProvidersCollection = RemoteSettings("doh-providers");
|
||||
const gConfigCollection = RemoteSettings("doh-config");
|
||||
|
||||
function getPrefValueRegionFirst(prefName, defaultValue) {
|
||||
return (
|
||||
Preferences.get(`${kRegionPrefBranch}.${prefName}`) ||
|
||||
Preferences.get(`${kGlobalPrefBranch}.${prefName}`, defaultValue)
|
||||
);
|
||||
}
|
||||
|
||||
function getProviderListFromPref(prefName) {
|
||||
try {
|
||||
return JSON.parse(getPrefValueRegionFirst(prefName, "[]"));
|
||||
} catch (e) {
|
||||
Cu.reportError(`DoH provider list not a valid JSON array: ${prefName}`);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Generate a base config object with getters that return pref values. When
|
||||
// Remote Settings values become available, a new config object will be
|
||||
// generated from this and specific fields will be replaced by the RS value.
|
||||
// If we use a class to store base config and instantiate new config objects
|
||||
// from it, we lose the ability to override getters because they are defined
|
||||
// as non-configureable properties on class instances. So just use a function.
|
||||
function makeBaseConfigObject() {
|
||||
return {
|
||||
get enabled() {
|
||||
return getPrefValueRegionFirst(kEnabledPref, false);
|
||||
},
|
||||
|
||||
get providerList() {
|
||||
return getProviderListFromPref(kProvidersPref);
|
||||
},
|
||||
|
||||
get fallbackProviderURI() {
|
||||
return this.providerList[0]?.uri;
|
||||
},
|
||||
|
||||
trrSelection: {
|
||||
get enabled() {
|
||||
return getPrefValueRegionFirst(kTRRSelectionEnabledPref, false);
|
||||
},
|
||||
|
||||
get commitResult() {
|
||||
return getPrefValueRegionFirst(kTRRSelectionCommitResultPref, false);
|
||||
},
|
||||
|
||||
get providerList() {
|
||||
return getProviderListFromPref(kTRRSelectionProvidersPref);
|
||||
},
|
||||
},
|
||||
|
||||
providerSteering: {
|
||||
get enabled() {
|
||||
return getPrefValueRegionFirst(kProviderSteeringEnabledPref, false);
|
||||
},
|
||||
|
||||
get providerList() {
|
||||
return getProviderListFromPref(kProviderSteeringListPref);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const DoHConfigController = {
|
||||
initComplete: null,
|
||||
_resolveInitComplete: null,
|
||||
|
||||
// This field always contains the current config state, for
|
||||
// consumer use.
|
||||
currentConfig: makeBaseConfigObject(),
|
||||
|
||||
// Loads the client's region via Region.jsm. This might mean waiting
|
||||
// until the region is available.
|
||||
async loadRegion() {
|
||||
await new Promise(resolve => {
|
||||
let homeRegion = Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
if (homeRegion) {
|
||||
kRegionPrefBranch = `${kGlobalPrefBranch}.${homeRegion.toLowerCase()}`;
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
let updateRegionAndResolve = () => {
|
||||
kRegionPrefBranch = `${kGlobalPrefBranch}.${Region.home.toLowerCase()}`;
|
||||
Preferences.set(`${kGlobalPrefBranch}.home-region`, Region.home);
|
||||
resolve();
|
||||
};
|
||||
|
||||
if (Region.home) {
|
||||
updateRegionAndResolve();
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(function obs(sub, top, data) {
|
||||
Services.obs.removeObserver(obs, Region.REGION_TOPIC);
|
||||
updateRegionAndResolve();
|
||||
}, Region.REGION_TOPIC);
|
||||
});
|
||||
|
||||
// Finally, reload config.
|
||||
await this.updateFromRemoteSettings();
|
||||
},
|
||||
|
||||
async init() {
|
||||
await this.loadRegion();
|
||||
|
||||
Services.prefs.addObserver(`${kGlobalPrefBranch}.`, this, true);
|
||||
|
||||
gProvidersCollection.on("sync", this.updateFromRemoteSettings);
|
||||
gConfigCollection.on("sync", this.updateFromRemoteSettings);
|
||||
|
||||
this._resolveInitComplete();
|
||||
},
|
||||
|
||||
// Useful for tests to set prior state before init()
|
||||
async _uninit() {
|
||||
await this.initComplete;
|
||||
|
||||
Services.prefs.removeObserver(`${kGlobalPrefBranch}`, this);
|
||||
|
||||
gProvidersCollection.off("sync", this.updateFromRemoteSettings);
|
||||
gConfigCollection.off("sync", this.updateFromRemoteSettings);
|
||||
|
||||
this.initComplete = new Promise(resolve => {
|
||||
this._resolveInitComplete = resolve;
|
||||
});
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case kPrefChangedTopic:
|
||||
if (
|
||||
!data.startsWith(kRegionPrefBranch) &&
|
||||
data != `${kGlobalPrefBranch}.${kEnabledPref}` &&
|
||||
data != `${kGlobalPrefBranch}.${kProvidersPref}`
|
||||
) {
|
||||
break;
|
||||
}
|
||||
this.notifyNewConfig();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIObserver",
|
||||
"nsISupportsWeakReference",
|
||||
]),
|
||||
|
||||
// Creates new config object from currently available
|
||||
// Remote Settings values.
|
||||
async updateFromRemoteSettings() {
|
||||
let providers = await gProvidersCollection.get();
|
||||
let config = await gConfigCollection.get();
|
||||
|
||||
let providersById = new Map();
|
||||
providers.forEach(p => providersById.set(p.id, p));
|
||||
|
||||
let configByRegion = new Map();
|
||||
config.forEach(c => {
|
||||
c.id = c.id.toLowerCase();
|
||||
configByRegion.set(c.id, c);
|
||||
});
|
||||
|
||||
let homeRegion = Preferences.get(`${kGlobalPrefBranch}.home-region`);
|
||||
let localConfig =
|
||||
configByRegion.get(homeRegion?.toLowerCase()) ||
|
||||
configByRegion.get("global");
|
||||
|
||||
// Make a new config object first, mutate it as needed, then synchronously
|
||||
// replace the currentConfig object at the end to ensure atomicity.
|
||||
let newConfig = makeBaseConfigObject();
|
||||
|
||||
if (!localConfig) {
|
||||
DoHConfigController.currentConfig = newConfig;
|
||||
DoHConfigController.notifyNewConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if (localConfig.rolloutEnabled) {
|
||||
delete newConfig.enabled;
|
||||
newConfig.enabled = true;
|
||||
}
|
||||
|
||||
let parseProviderList = (list, checkFn) => {
|
||||
let parsedList = [];
|
||||
list?.split(",")?.forEach(p => {
|
||||
p = p.trim();
|
||||
if (!p.length) {
|
||||
return;
|
||||
}
|
||||
p = providersById.get(p);
|
||||
if (!p || (checkFn && !checkFn(p))) {
|
||||
return;
|
||||
}
|
||||
parsedList.push(p);
|
||||
});
|
||||
return parsedList;
|
||||
};
|
||||
|
||||
let regionalProviders = parseProviderList(localConfig.providers);
|
||||
if (regionalProviders?.length) {
|
||||
delete newConfig.providerList;
|
||||
newConfig.providerList = regionalProviders;
|
||||
}
|
||||
|
||||
if (localConfig.steeringEnabled) {
|
||||
let steeringProviders = parseProviderList(
|
||||
localConfig.steeringProviders,
|
||||
p => p.canonicalName?.length
|
||||
);
|
||||
if (steeringProviders?.length) {
|
||||
delete newConfig.providerSteering.providerList;
|
||||
newConfig.providerSteering.providerList = steeringProviders;
|
||||
|
||||
delete newConfig.providerSteering.enabled;
|
||||
newConfig.providerSteering.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (localConfig.autoDefaultEnabled) {
|
||||
let defaultProviders = parseProviderList(
|
||||
localConfig.autoDefaultProviders
|
||||
);
|
||||
if (defaultProviders?.length) {
|
||||
delete newConfig.trrSelection.providerList;
|
||||
newConfig.trrSelection.providerList = defaultProviders;
|
||||
|
||||
delete newConfig.trrSelection.enabled;
|
||||
newConfig.trrSelection.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, update the currentConfig object synchronously.
|
||||
DoHConfigController.currentConfig = newConfig;
|
||||
|
||||
DoHConfigController.notifyNewConfig();
|
||||
},
|
||||
|
||||
kConfigUpdateTopic: "doh-config-updated",
|
||||
notifyNewConfig() {
|
||||
Services.obs.notifyObservers(null, this.kConfigUpdateTopic);
|
||||
},
|
||||
|
||||
get enabled() {
|
||||
return Preferences.get(kEnabledPref, false);
|
||||
},
|
||||
|
||||
trrSelection: {
|
||||
get enabled() {
|
||||
return Preferences.get(kTRRSelectionEnabledPref, false);
|
||||
},
|
||||
|
||||
get commitResult() {
|
||||
return Preferences.get(kTRRSelectionCommitResultPref, false);
|
||||
},
|
||||
},
|
||||
|
||||
providerSteering: {
|
||||
get enabled() {
|
||||
return Preferences.get(kProviderSteeringEnabledPref, false);
|
||||
},
|
||||
|
||||
get providerList() {
|
||||
return Preferences.get(kProviderSteeringListPref, "[]");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Config.init();
|
||||
DoHConfigController.initComplete = new Promise(resolve => {
|
||||
DoHConfigController._resolveInitComplete = resolve;
|
||||
});
|
||||
DoHConfigController.init();
|
||||
|
@ -20,7 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
|
||||
ClientID: "resource://gre/modules/ClientID.jsm",
|
||||
ExtensionStorageIDB: "resource://gre/modules/ExtensionStorageIDB.jsm",
|
||||
Config: "resource:///modules/DoHConfig.jsm",
|
||||
DoHConfigController: "resource:///modules/DoHConfig.jsm",
|
||||
Heuristics: "resource:///modules/DoHHeuristics.jsm",
|
||||
Preferences: "resource://gre/modules/Preferences.jsm",
|
||||
setTimeout: "resource://gre/modules/Timer.jsm",
|
||||
@ -114,8 +114,6 @@ const BREADCRUMB_PREF = "doh-rollout.self-enabled";
|
||||
const NETWORK_TRR_MODE_PREF = "network.trr.mode";
|
||||
const NETWORK_TRR_URI_PREF = "network.trr.uri";
|
||||
|
||||
const TRR_LIST_PREF = "network.trr.resolvers";
|
||||
|
||||
const ROLLOUT_MODE_PREF = "doh-rollout.mode";
|
||||
const ROLLOUT_URI_PREF = "doh-rollout.uri";
|
||||
|
||||
@ -168,11 +166,13 @@ const DoHController = {
|
||||
true
|
||||
);
|
||||
|
||||
Services.obs.addObserver(this, Config.kConfigUpdateTopic);
|
||||
await DoHConfigController.initComplete;
|
||||
|
||||
Services.obs.addObserver(this, DoHConfigController.kConfigUpdateTopic);
|
||||
Preferences.observe(NETWORK_TRR_MODE_PREF, this);
|
||||
Preferences.observe(NETWORK_TRR_URI_PREF, this);
|
||||
|
||||
if (Config.enabled) {
|
||||
if (DoHConfigController.currentConfig.enabled) {
|
||||
await this.maybeEnableHeuristics();
|
||||
} else if (Preferences.get(FIRST_RUN_PREF, false)) {
|
||||
await this.rollback();
|
||||
@ -193,7 +193,7 @@ const DoHController = {
|
||||
// Also used by tests to reset DoHController state (prefs are not cleared
|
||||
// here - tests do that when needed between _uninit and init).
|
||||
async _uninit() {
|
||||
Services.obs.removeObserver(this, Config.kConfigUpdateTopic);
|
||||
Services.obs.removeObserver(this, DoHConfigController.kConfigUpdateTopic);
|
||||
Preferences.ignore(NETWORK_TRR_MODE_PREF, this);
|
||||
Preferences.ignore(NETWORK_TRR_URI_PREF, this);
|
||||
AsyncShutdown.profileBeforeChange.removeBlocker(this._asyncShutdownBlocker);
|
||||
@ -201,9 +201,15 @@ const DoHController = {
|
||||
},
|
||||
|
||||
// Called to reset state when a new config is available.
|
||||
resetPromise: Promise.resolve(),
|
||||
async reset() {
|
||||
await this._uninit();
|
||||
await this.init();
|
||||
this.resetPromise = this.resetPromise.then(async () => {
|
||||
await this._uninit();
|
||||
await this.init();
|
||||
Services.obs.notifyObservers(null, "doh:controller-reloaded");
|
||||
});
|
||||
|
||||
return this.resetPromise;
|
||||
},
|
||||
|
||||
async migrateLocalStoragePrefs() {
|
||||
@ -328,6 +334,14 @@ const DoHController = {
|
||||
}
|
||||
|
||||
await this.runTRRSelection();
|
||||
// If we enter this branch it means that no automatic selection was possible.
|
||||
// In this case, we try to set a fallback (as defined by DoHConfigController).
|
||||
if (!Preferences.isSet(ROLLOUT_URI_PREF)) {
|
||||
Preferences.set(
|
||||
ROLLOUT_URI_PREF,
|
||||
DoHConfigController.currentConfig.fallbackProviderURI
|
||||
);
|
||||
}
|
||||
this.runHeuristicsThrottled("startup");
|
||||
Services.obs.addObserver(this, kLinkStatusChangedTopic);
|
||||
Services.obs.addObserver(this, kConnectivityTopic);
|
||||
@ -560,22 +574,26 @@ const DoHController = {
|
||||
async runTRRSelection() {
|
||||
// If persisting the selection is disabled, clear the existing
|
||||
// selection.
|
||||
if (!Config.trrSelection.commitResult) {
|
||||
if (!DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
Preferences.reset(ROLLOUT_URI_PREF);
|
||||
}
|
||||
|
||||
if (!Config.trrSelection.enabled) {
|
||||
if (!DoHConfigController.currentConfig.trrSelection.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences.isSet(ROLLOUT_URI_PREF)) {
|
||||
if (
|
||||
Preferences.isSet(ROLLOUT_URI_PREF) &&
|
||||
Preferences.get(ROLLOUT_URI_PREF) ==
|
||||
Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.runTRRSelectionDryRun();
|
||||
|
||||
// If persisting the selection is disabled, don't commit the value.
|
||||
if (!Config.trrSelection.commitResult) {
|
||||
if (!DoHConfigController.currentConfig.trrSelection.commitResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -590,31 +608,28 @@ const DoHController = {
|
||||
// Check whether the existing dry-run-result is in the default
|
||||
// list of TRRs. If it is, all good. Else, run the dry run again.
|
||||
let dryRunResult = Preferences.get(TRR_SELECT_DRY_RUN_RESULT_PREF);
|
||||
let defaultTRRs = JSON.parse(
|
||||
Services.prefs.getDefaultBranch("").getCharPref(TRR_LIST_PREF)
|
||||
);
|
||||
let dryRunResultIsValid = defaultTRRs.some(
|
||||
trr => trr.url == dryRunResult
|
||||
let dryRunResultIsValid = DoHConfigController.currentConfig.providerList.some(
|
||||
trr => trr.uri == dryRunResult
|
||||
);
|
||||
if (dryRunResultIsValid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let setDryRunResultAndRecordTelemetry = trr => {
|
||||
Preferences.set(TRR_SELECT_DRY_RUN_RESULT_PREF, trr);
|
||||
let setDryRunResultAndRecordTelemetry = trrUri => {
|
||||
Preferences.set(TRR_SELECT_DRY_RUN_RESULT_PREF, trrUri);
|
||||
Services.telemetry.recordEvent(
|
||||
TRRSELECT_TELEMETRY_CATEGORY,
|
||||
"trrselect",
|
||||
"dryrunresult",
|
||||
trr.substring(0, 40) // Telemetry payload max length
|
||||
trrUri.substring(0, 40) // Telemetry payload max length
|
||||
);
|
||||
};
|
||||
|
||||
if (kIsInAutomation) {
|
||||
// For mochitests, just record telemetry with a dummy result.
|
||||
// TRRPerformance.jsm is tested in xpcshell.
|
||||
setDryRunResultAndRecordTelemetry("https://dummytrr.com/query");
|
||||
setDryRunResultAndRecordTelemetry("https://example.com/dns-query");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -624,10 +639,13 @@ const DoHController = {
|
||||
"resource:///modules/TRRPerformance.jsm"
|
||||
);
|
||||
await new Promise(resolve => {
|
||||
let trrList = DoHConfigController.currentConfig.trrSelection.providerList.map(
|
||||
trr => trr.uri
|
||||
);
|
||||
let racer = new TRRRacer(() => {
|
||||
setDryRunResultAndRecordTelemetry(racer.getFastestTRR(true));
|
||||
resolve();
|
||||
});
|
||||
}, trrList);
|
||||
racer.run();
|
||||
});
|
||||
},
|
||||
@ -643,7 +661,7 @@ const DoHController = {
|
||||
case kPrefChangedTopic:
|
||||
this.onPrefChanged(data);
|
||||
break;
|
||||
case Config.kConfigUpdateTopic:
|
||||
case DoHConfigController.kConfigUpdateTopic:
|
||||
this.reset();
|
||||
break;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ XPCOMUtils.defineLazyServiceGetter(
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Config",
|
||||
"DoHConfigController",
|
||||
"resource:///modules/DoHConfig.jsm"
|
||||
);
|
||||
|
||||
@ -363,7 +363,7 @@ async function platform() {
|
||||
// provider if the check is successful, else null. Currently we only support
|
||||
// this for Comcast networks.
|
||||
async function providerSteering() {
|
||||
if (!Config.providerSteering.enabled) {
|
||||
if (!DoHConfigController.currentConfig.providerSteering.enabled) {
|
||||
return null;
|
||||
}
|
||||
const TEST_DOMAIN = "doh.test.";
|
||||
@ -371,13 +371,8 @@ async function providerSteering() {
|
||||
// Array of { name, canonicalName, uri } where name is an identifier for
|
||||
// telemetry, canonicalName is the expected CNAME when looking up doh.test,
|
||||
// and uri is the provider's DoH endpoint.
|
||||
let steeredProviders = Config.providerSteering.providerList;
|
||||
try {
|
||||
steeredProviders = JSON.parse(steeredProviders);
|
||||
} catch (e) {
|
||||
console.log("Provider list is invalid JSON, moving on.");
|
||||
return null;
|
||||
}
|
||||
let steeredProviders =
|
||||
DoHConfigController.currentConfig.providerSteering.providerList;
|
||||
|
||||
if (!steeredProviders || !steeredProviders.length) {
|
||||
return null;
|
||||
|
142
browser/components/doh/DoHTestUtils.jsm
Normal file
142
browser/components/doh/DoHTestUtils.jsm
Normal file
@ -0,0 +1,142 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["DoHTestUtils"];
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"RemoteSettings",
|
||||
"resource://services-settings/remote-settings.js"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"TestUtils",
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
const kConfigCollectionKey = "doh-config";
|
||||
const kProviderCollectionKey = "doh-providers";
|
||||
|
||||
const kConfigUpdateTopic = "doh-config-updated";
|
||||
const kControllerReloadedTopic = "doh:controller-reloaded";
|
||||
|
||||
/*
|
||||
* Some helpers for loading and modifying DoH config in
|
||||
* Remote Settings. Call resetRemoteSettingsConfig to set up
|
||||
* basic default config that omits external URLs. Use
|
||||
* waitForConfigFlush to wait for DoH actors to pick up changes.
|
||||
*
|
||||
* Some tests need to load/reset config while DoH actors are
|
||||
* uninitialized. Pass waitForConfigFlushes = false in these cases.
|
||||
*/
|
||||
const DoHTestUtils = {
|
||||
providers: [
|
||||
{
|
||||
uri: "https://example.com/1",
|
||||
UIName: "Example 1",
|
||||
autoDefault: false,
|
||||
canonicalName: "",
|
||||
id: "example-1",
|
||||
},
|
||||
{
|
||||
uri: "https://example.com/2",
|
||||
UIName: "Example 2",
|
||||
autoDefault: false,
|
||||
canonicalName: "",
|
||||
id: "example-2",
|
||||
},
|
||||
],
|
||||
|
||||
async loadRemoteSettingsProviders(providers, waitForConfigFlushes = true) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
|
||||
let providerRS = RemoteSettings(kProviderCollectionKey);
|
||||
let db = await providerRS.db;
|
||||
await db.importChanges({}, Date.now(), providers, { clear: true });
|
||||
|
||||
// Trigger a sync.
|
||||
await this.triggerSync(providerRS);
|
||||
|
||||
await configFlushedPromise;
|
||||
},
|
||||
|
||||
async loadRemoteSettingsConfig(config, waitForConfigFlushes = true) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
|
||||
let configRS = RemoteSettings(kConfigCollectionKey);
|
||||
let db = await configRS.db;
|
||||
await db.importChanges({}, Date.now(), [config]);
|
||||
|
||||
// Trigger a sync.
|
||||
await this.triggerSync(configRS);
|
||||
|
||||
await configFlushedPromise;
|
||||
},
|
||||
|
||||
// Loads default config for testing without clearing existing entries.
|
||||
async loadDefaultRemoteSettingsConfig(waitForConfigFlushes = true) {
|
||||
await this.loadRemoteSettingsProviders(
|
||||
this.providers,
|
||||
waitForConfigFlushes
|
||||
);
|
||||
|
||||
await this.loadRemoteSettingsConfig(
|
||||
{
|
||||
providers: "example-1, example-2",
|
||||
rolloutEnabled: false,
|
||||
steeringEnabled: false,
|
||||
steeringProviders: "",
|
||||
autoDefaultEnabled: false,
|
||||
autoDefaultProviders: "",
|
||||
id: "global",
|
||||
},
|
||||
waitForConfigFlushes
|
||||
);
|
||||
},
|
||||
|
||||
// Clears existing config AND loads defaults.
|
||||
async resetRemoteSettingsConfig(waitForConfigFlushes = true) {
|
||||
let providerRS = RemoteSettings(kProviderCollectionKey);
|
||||
let configRS = RemoteSettings(kConfigCollectionKey);
|
||||
for (let rs of [providerRS, configRS]) {
|
||||
let configFlushedPromise = this.waitForConfigFlush(waitForConfigFlushes);
|
||||
await rs.db.importChanges({}, Date.now(), [], { clear: true });
|
||||
// Trigger a sync to clear.
|
||||
await this.triggerSync(rs);
|
||||
await configFlushedPromise;
|
||||
}
|
||||
|
||||
await this.loadDefaultRemoteSettingsConfig(waitForConfigFlushes);
|
||||
},
|
||||
|
||||
triggerSync(rs) {
|
||||
return rs.emit("sync", {
|
||||
data: {
|
||||
current: [],
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
waitForConfigUpdate() {
|
||||
return TestUtils.topicObserved(kConfigUpdateTopic);
|
||||
},
|
||||
|
||||
waitForControllerReload() {
|
||||
return TestUtils.topicObserved(kControllerReloadedTopic);
|
||||
},
|
||||
|
||||
waitForConfigFlush(shouldWait = true) {
|
||||
if (!shouldWait) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
this.waitForConfigUpdate(),
|
||||
this.waitForControllerReload(),
|
||||
]);
|
||||
},
|
||||
};
|
@ -58,11 +58,6 @@ XPCOMUtils.defineLazyServiceGetter(
|
||||
"nsIUUIDGenerator"
|
||||
);
|
||||
|
||||
// The list of participating TRRs.
|
||||
const kTRRs = JSON.parse(
|
||||
Services.prefs.getDefaultBranch("").getCharPref("network.trr.resolvers")
|
||||
).map(trr => trr.url);
|
||||
|
||||
// The canonical domain whose subdomains we will be resolving.
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
@ -154,8 +149,9 @@ DNSLookup.prototype.QueryInterface = ChromeUtils.generateQI(["nsIDNSListener"]);
|
||||
// triggered and the results aggregated before telemetry is sent. If aborted,
|
||||
// any aggregated results are discarded.
|
||||
class LookupAggregator {
|
||||
constructor(onCompleteCallback) {
|
||||
constructor(onCompleteCallback, trrList) {
|
||||
this.onCompleteCallback = onCompleteCallback;
|
||||
this.trrList = trrList;
|
||||
this.aborted = false;
|
||||
this.networkUnstable = false;
|
||||
this.captivePortal = false;
|
||||
@ -166,7 +162,7 @@ class LookupAggregator {
|
||||
this.domains.push(null);
|
||||
}
|
||||
this.domains.push(...kPopularDomains);
|
||||
this.totalLookups = kTRRs.length * this.domains.length;
|
||||
this.totalLookups = this.trrList.length * this.domains.length;
|
||||
this.completedLookups = 0;
|
||||
this.results = [];
|
||||
}
|
||||
@ -178,7 +174,7 @@ class LookupAggregator {
|
||||
}
|
||||
|
||||
this._ran = true;
|
||||
for (let trr of kTRRs) {
|
||||
for (let trr of this.trrList) {
|
||||
for (let domain of this.domains) {
|
||||
new DNSLookup(
|
||||
domain,
|
||||
@ -256,11 +252,12 @@ class LookupAggregator {
|
||||
// spawned next time we get a link, up to 5 times. On the fifth time, we just
|
||||
// let the aggegator complete and mark it as tainted.
|
||||
class TRRRacer {
|
||||
constructor(onCompleteCallback) {
|
||||
constructor(onCompleteCallback, trrList) {
|
||||
this._aggregator = null;
|
||||
this._retryCount = 0;
|
||||
this._complete = false;
|
||||
this._onCompleteCallback = onCompleteCallback;
|
||||
this._trrList = trrList;
|
||||
}
|
||||
|
||||
run() {
|
||||
@ -365,7 +362,10 @@ class TRRRacer {
|
||||
}
|
||||
|
||||
_runNewAggregator() {
|
||||
this._aggregator = new LookupAggregator(() => this.onComplete());
|
||||
this._aggregator = new LookupAggregator(
|
||||
() => this.onComplete(),
|
||||
this._trrList
|
||||
);
|
||||
this._aggregator.run();
|
||||
this._retryCount++;
|
||||
}
|
||||
|
@ -14,5 +14,9 @@ EXTRA_JS_MODULES += [
|
||||
"TRRPerformance.jsm",
|
||||
]
|
||||
|
||||
TESTING_JS_MODULES += [
|
||||
"DoHTestUtils.jsm",
|
||||
]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ["test/unit/xpcshell.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"]
|
||||
|
@ -8,6 +8,10 @@ head = head.js
|
||||
[browser_NextDNSMigration.js]
|
||||
[browser_policyOverride.js]
|
||||
[browser_providerSteering.js]
|
||||
[browser_remoteSettings_newProfile.js]
|
||||
skip-if = os == 'win' && bits == 32 # Bug 1713464
|
||||
[browser_remoteSettings_rollout.js]
|
||||
skip-if = os == 'win' && bits == 32 # Bug 1713464
|
||||
[browser_rollback.js]
|
||||
[browser_trrMode_migration.js]
|
||||
[browser_trrSelect.js]
|
||||
|
@ -17,7 +17,7 @@ add_task(async function testCleanFlow() {
|
||||
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
await checkTRRSelectionTelemetry();
|
||||
|
@ -17,7 +17,7 @@ add_task(async function testDoorhangerUserReject() {
|
||||
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
await checkTRRSelectionTelemetry();
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const TEST_DOMAIN = "doh.test.";
|
||||
const AUTO_TRR_URI = "https://dummytrr.com/query";
|
||||
const AUTO_TRR_URI = "https://example.com/dns-query";
|
||||
|
||||
add_task(setup);
|
||||
|
||||
|
@ -0,0 +1,94 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(setup);
|
||||
add_task(setupRegion);
|
||||
|
||||
add_task(async function testNewProfile() {
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
false,
|
||||
"Rollout should not be enabled"
|
||||
);
|
||||
|
||||
let provider1 = {
|
||||
id: "provider1",
|
||||
uri: "https://example.org/1",
|
||||
autoDefault: true,
|
||||
};
|
||||
let provider2 = {
|
||||
id: "provider2",
|
||||
uri: "https://example.org/2",
|
||||
canonicalName: "https://example.org/cname",
|
||||
};
|
||||
let provider3 = {
|
||||
id: "provider3",
|
||||
uri: "https://example.org/3",
|
||||
autoDefault: true,
|
||||
};
|
||||
|
||||
await DoHTestUtils.loadRemoteSettingsProviders([
|
||||
provider1,
|
||||
provider2,
|
||||
provider3,
|
||||
]);
|
||||
|
||||
await DoHTestUtils.loadRemoteSettingsConfig({
|
||||
id: kTestRegion.toLowerCase(),
|
||||
rolloutEnabled: true,
|
||||
providers: "provider1, provider3",
|
||||
steeringEnabled: true,
|
||||
steeringProviders: "provider2",
|
||||
autoDefaultEnabled: true,
|
||||
autoDefaultProviders: "provider1, provider3",
|
||||
});
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
true,
|
||||
"Rollout should be enabled"
|
||||
);
|
||||
await ensureTRRMode(2);
|
||||
Assert.deepEqual(
|
||||
DoHConfigController.currentConfig.providerList,
|
||||
[provider1, provider3],
|
||||
"Provider list should be loaded"
|
||||
);
|
||||
is(
|
||||
DoHConfigController.currentConfig.providerSteering.enabled,
|
||||
true,
|
||||
"Steering should be enabled"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
DoHConfigController.currentConfig.providerSteering.providerList,
|
||||
[provider2],
|
||||
"Steering provider list should be loaded"
|
||||
);
|
||||
is(
|
||||
DoHConfigController.currentConfig.trrSelection.enabled,
|
||||
true,
|
||||
"TRR Selection should be enabled"
|
||||
);
|
||||
Assert.deepEqual(
|
||||
DoHConfigController.currentConfig.trrSelection.providerList,
|
||||
[provider1, provider3],
|
||||
"TRR Selection provider list should be loaded"
|
||||
);
|
||||
is(
|
||||
DoHConfigController.currentConfig.fallbackProviderURI,
|
||||
provider1.uri,
|
||||
"Fallback provider URI should be that of the first one"
|
||||
);
|
||||
|
||||
await DoHTestUtils.resetRemoteSettingsConfig();
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
false,
|
||||
"Rollout should be disabled"
|
||||
);
|
||||
await ensureTRRMode(undefined);
|
||||
});
|
@ -0,0 +1,69 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(setup);
|
||||
add_task(setupRegion);
|
||||
|
||||
add_task(async function testPrefFirstRollout() {
|
||||
setPassingHeuristics();
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
false,
|
||||
"Rollout should not be enabled"
|
||||
);
|
||||
|
||||
let configFlushedPromise = DoHTestUtils.waitForConfigFlush();
|
||||
Preferences.set(`${kRegionalPrefNamespace}.enabled`, true);
|
||||
await configFlushedPromise;
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
true,
|
||||
"Rollout should be enabled"
|
||||
);
|
||||
await ensureTRRMode(2);
|
||||
|
||||
await DoHTestUtils.loadRemoteSettingsProviders([
|
||||
{
|
||||
id: "provider1",
|
||||
uri: "https://example.org/1",
|
||||
autoDefault: true,
|
||||
},
|
||||
]);
|
||||
|
||||
await DoHTestUtils.loadRemoteSettingsConfig({
|
||||
id: kTestRegion.toLowerCase(),
|
||||
rolloutEnabled: true,
|
||||
providers: "provider1",
|
||||
});
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
true,
|
||||
"Rollout should still be enabled"
|
||||
);
|
||||
|
||||
let configUpdatedPromise = DoHTestUtils.waitForConfigUpdate();
|
||||
Preferences.reset(`${kRegionalPrefNamespace}.enabled`);
|
||||
await configUpdatedPromise;
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
true,
|
||||
"Rollout should still be enabled"
|
||||
);
|
||||
await ensureTRRMode(2);
|
||||
|
||||
await DoHTestUtils.resetRemoteSettingsConfig();
|
||||
|
||||
is(
|
||||
DoHConfigController.currentConfig.enabled,
|
||||
false,
|
||||
"Rollout should not be enabled"
|
||||
);
|
||||
await ensureTRRMode(undefined);
|
||||
});
|
@ -19,7 +19,7 @@ add_task(async function testRollback() {
|
||||
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
await checkTRRSelectionTelemetry();
|
||||
|
@ -7,20 +7,6 @@
|
||||
add_task(setup);
|
||||
|
||||
add_task(async function testTRRSelect() {
|
||||
// Set up the resolver lists in the default and user pref branches.
|
||||
// dummyTRR3 which only exists in the user-branch value should be ignored.
|
||||
let oldResolverList = Services.prefs.getCharPref("network.trr.resolvers");
|
||||
Services.prefs
|
||||
.getDefaultBranch("")
|
||||
.setCharPref(
|
||||
"network.trr.resolvers",
|
||||
`[{"url": "https://dummytrr.com/query"}, {"url": "https://dummytrr2.com/query"}]`
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.resolvers",
|
||||
`[{"url": "https://dummytrr.com/query"}, {"url": "https://dummytrr2.com/query"}, {"url": "https://dummytrr3.com/query"}]`
|
||||
);
|
||||
|
||||
// Clean start: doh-rollout.uri should be set after init.
|
||||
setPassingHeuristics();
|
||||
let prefPromise = TestUtils.waitForPrefChange(prefs.BREADCRUMB_PREF);
|
||||
@ -29,7 +15,7 @@ add_task(async function testTRRSelect() {
|
||||
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
|
||||
@ -46,7 +32,7 @@ add_task(async function testTRRSelect() {
|
||||
await prefPromise;
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
|
||||
@ -54,13 +40,17 @@ add_task(async function testTRRSelect() {
|
||||
await ensureTRRMode(2);
|
||||
await checkHeuristicsTelemetry("enable_doh", "startup");
|
||||
|
||||
// Disable committing and reset. The committed URI should be cleared but the
|
||||
// dry-run-result should persist.
|
||||
// Disable committing and reset. The committed URI should be reset to the
|
||||
// default provider and the dry-run-result should persist.
|
||||
Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, false);
|
||||
prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF);
|
||||
await restartDoHController();
|
||||
await prefPromise;
|
||||
ok(!Preferences.isSet(prefs.TRR_SELECT_URI_PREF), "TRR selection cleared.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://example.com/1",
|
||||
"Default TRR selected."
|
||||
);
|
||||
try {
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return !Preferences.isSet(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF);
|
||||
@ -71,7 +61,7 @@ add_task(async function testTRRSelect() {
|
||||
}
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"dry-run result has the correct value."
|
||||
);
|
||||
|
||||
@ -86,15 +76,23 @@ add_task(async function testTRRSelect() {
|
||||
await restartDoHController();
|
||||
try {
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return Preferences.get(prefs.TRR_SELECT_URI_PREF);
|
||||
return (
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF) ==
|
||||
"https://example.com/dns-query"
|
||||
);
|
||||
});
|
||||
ok(false, "Dry run result got committed, fail!");
|
||||
} catch (e) {
|
||||
ok(true, "Dry run result did not get committed");
|
||||
}
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://example.com/1",
|
||||
"Default TRR selected."
|
||||
);
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_DRY_RUN_RESULT_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete, dry-run result recorded."
|
||||
);
|
||||
Preferences.set(prefs.TRR_SELECT_COMMIT_PREF, true);
|
||||
@ -108,14 +106,17 @@ add_task(async function testTRRSelect() {
|
||||
Preferences.reset(prefs.TRR_SELECT_URI_PREF);
|
||||
Preferences.set(
|
||||
prefs.TRR_SELECT_DRY_RUN_RESULT_PREF,
|
||||
"https://dummytrr2.com/query"
|
||||
"https://example.com/2"
|
||||
);
|
||||
prefPromise = TestUtils.waitForPrefChange(
|
||||
prefs.TRR_SELECT_URI_PREF,
|
||||
newVal => newVal == "https://example.com/2"
|
||||
);
|
||||
prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF);
|
||||
await restartDoHController();
|
||||
await prefPromise;
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr2.com/query",
|
||||
"https://example.com/2",
|
||||
"TRR selection complete, existing dry-run-result committed."
|
||||
);
|
||||
|
||||
@ -128,23 +129,18 @@ add_task(async function testTRRSelect() {
|
||||
Preferences.reset(prefs.TRR_SELECT_URI_PREF);
|
||||
Preferences.set(
|
||||
prefs.TRR_SELECT_DRY_RUN_RESULT_PREF,
|
||||
"https://dummytrr3.com/query"
|
||||
"https://example.com/4"
|
||||
);
|
||||
prefPromise = TestUtils.waitForPrefChange(prefs.TRR_SELECT_URI_PREF);
|
||||
await restartDoHController();
|
||||
await prefPromise;
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete, existing dry-run-result discarded and refreshed."
|
||||
);
|
||||
|
||||
// Wait for heuristics to complete.
|
||||
await ensureTRRMode(2);
|
||||
await checkHeuristicsTelemetry("enable_doh", "startup");
|
||||
|
||||
Services.prefs
|
||||
.getDefaultBranch("")
|
||||
.setCharPref("network.trr.resolvers", oldResolverList);
|
||||
Services.prefs.clearUserPref("network.trr.resolvers");
|
||||
});
|
||||
|
@ -23,8 +23,8 @@ add_task(async function testTrrSelectionDisable() {
|
||||
);
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
undefined,
|
||||
"doh-rollout.uri remained unset."
|
||||
"https://example.com/1",
|
||||
"doh-rollout.uri set to first provider in the list."
|
||||
);
|
||||
ensureNoTRRSelectionTelemetry();
|
||||
|
||||
@ -62,8 +62,8 @@ add_task(async function testTrrSelectionDisable() {
|
||||
);
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
undefined,
|
||||
"doh-rollout.uri remained unset."
|
||||
"https://example.com/1",
|
||||
"doh-rollout.uri set to first provider in the list."
|
||||
);
|
||||
await ensureTRRMode(2);
|
||||
await checkHeuristicsTelemetry("enable_doh", "startup");
|
||||
|
@ -17,7 +17,7 @@ add_task(async function testUserInterference() {
|
||||
is(Preferences.get(prefs.BREADCRUMB_PREF), true, "Breadcrumb saved.");
|
||||
is(
|
||||
Preferences.get(prefs.TRR_SELECT_URI_PREF),
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"TRR selection complete."
|
||||
);
|
||||
await checkTRRSelectionTelemetry();
|
||||
|
@ -1,22 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ASRouter",
|
||||
"resource://activity-stream/lib/ASRouter.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"DoHController",
|
||||
"resource:///modules/DoHController.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Preferences",
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ASRouter: "resource://activity-stream/lib/ASRouter.jsm",
|
||||
DoHController: "resource:///modules/DoHController.jsm",
|
||||
DoHConfigController: "resource:///modules/DoHConfig.jsm",
|
||||
DoHTestUtils: "resource://testing-common/DoHTestUtils.jsm",
|
||||
Preferences: "resource://gre/modules/Preferences.jsm",
|
||||
Region: "resource://gre/modules/Region.jsm",
|
||||
RegionTestUtils: "resource://testing-common/RegionTestUtils.jsm",
|
||||
RemoteSettings: "resource://services-settings/remote-settings.js",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
@ -52,6 +45,7 @@ const prefs = {
|
||||
FIRST_RUN_PREF: "doh-rollout.doneFirstRun",
|
||||
BALROG_MIGRATION_PREF: "doh-rollout.balrog-migration-done",
|
||||
PREVIOUS_TRR_MODE_PREF: "doh-rollout.previous.trr.mode",
|
||||
PROVIDER_LIST_PREF: "doh-rollout.provider-list",
|
||||
TRR_SELECT_ENABLED_PREF: "doh-rollout.trr-selection.enabled",
|
||||
TRR_SELECT_URI_PREF: "doh-rollout.uri",
|
||||
TRR_SELECT_COMMIT_PREF: "doh-rollout.trr-selection.commit-result",
|
||||
@ -74,6 +68,8 @@ const CFR_JSON = {
|
||||
};
|
||||
|
||||
async function setup() {
|
||||
await DoHController._uninit();
|
||||
await DoHConfigController._uninit();
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["security.notification_enable_delay", 0]],
|
||||
});
|
||||
@ -128,6 +124,13 @@ async function setup() {
|
||||
// Global canary
|
||||
gDNSOverride.addIPOverride("use-application-dns.net.", "4.1.1.1");
|
||||
|
||||
await DoHTestUtils.resetRemoteSettingsConfig(false);
|
||||
|
||||
await DoHConfigController.init();
|
||||
await DoHController.init();
|
||||
|
||||
await waitForStateTelemetry(["rollback"]);
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
Services.telemetry.clearEvents();
|
||||
@ -141,10 +144,23 @@ async function setup() {
|
||||
await DoHController._uninit();
|
||||
Services.telemetry.clearEvents();
|
||||
Preferences.reset(Object.values(prefs));
|
||||
await DoHTestUtils.resetRemoteSettingsConfig(false);
|
||||
await DoHController.init();
|
||||
});
|
||||
}
|
||||
|
||||
const kTestRegion = "DE";
|
||||
const kRegionalPrefNamespace = `doh-rollout.${kTestRegion.toLowerCase()}`;
|
||||
|
||||
async function setupRegion() {
|
||||
Region._home = null;
|
||||
RegionTestUtils.setNetworkRegion(kTestRegion);
|
||||
await Region._fetchRegion();
|
||||
is(Region.home, kTestRegion, "Should have correct region");
|
||||
Preferences.reset("doh-rollout.home-region");
|
||||
await DoHConfigController.loadRegion();
|
||||
}
|
||||
|
||||
async function checkTRRSelectionTelemetry() {
|
||||
let events;
|
||||
await TestUtils.waitForCondition(() => {
|
||||
@ -162,7 +178,7 @@ async function checkTRRSelectionTelemetry() {
|
||||
is(events.length, 1, "Found the expected trrselect event.");
|
||||
is(
|
||||
events[0][4],
|
||||
"https://dummytrr.com/query",
|
||||
"https://example.com/dns-query",
|
||||
"The event records the expected decision"
|
||||
);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ const { TestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/TestUtils.jsm"
|
||||
);
|
||||
|
||||
let h2Port, trrServer1, trrServer2;
|
||||
let h2Port, trrServer1, trrServer2, trrList;
|
||||
let DNSLookup, LookupAggregator, TRRRacer;
|
||||
|
||||
function readFile(file) {
|
||||
@ -63,6 +63,7 @@ function setup() {
|
||||
// use the h2 server as DOH provider
|
||||
trrServer1 = `https://foo.example.com:${h2Port}/doh?responseIP=1.1.1.1`;
|
||||
trrServer2 = `https://foo.example.com:${h2Port}/doh?responseIP=2.2.2.2`;
|
||||
trrList = [trrServer1, trrServer2];
|
||||
// make all native resolve calls "secretly" resolve localhost instead
|
||||
Services.prefs.setBoolPref("network.dns.native-is-localhost", true);
|
||||
|
||||
@ -85,16 +86,6 @@ function setup() {
|
||||
"firefox-dns-perf-test.net."
|
||||
);
|
||||
|
||||
let defaultPrefBranch = Services.prefs.getDefaultBranch("");
|
||||
let origResolverList = defaultPrefBranch.getCharPref("network.trr.resolvers");
|
||||
|
||||
Services.prefs
|
||||
.getDefaultBranch("")
|
||||
.setCharPref(
|
||||
"network.trr.resolvers",
|
||||
`[{"url": "${trrServer1}"}, {"url": "${trrServer2}"}]`
|
||||
);
|
||||
|
||||
let TRRPerformance = ChromeUtils.import(
|
||||
"resource:///modules/TRRPerformance.jsm"
|
||||
);
|
||||
@ -110,7 +101,6 @@ function setup() {
|
||||
Services.prefs.clearUserPref("network.http.spdy.enabled");
|
||||
Services.prefs.clearUserPref("network.http.spdy.enabled.http2");
|
||||
Services.prefs.clearUserPref("network.dns.native-is-localhost");
|
||||
defaultPrefBranch.setCharPref("network.trr.resolvers", origResolverList);
|
||||
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
});
|
||||
|
@ -13,7 +13,7 @@ async function helper_SuccessfulLookupAggregator(
|
||||
captivePortal = false
|
||||
) {
|
||||
let deferred = PromiseUtils.defer();
|
||||
let aggregator = new LookupAggregator(() => deferred.resolve());
|
||||
let aggregator = new LookupAggregator(() => deferred.resolve(), trrList);
|
||||
// The aggregator's domain list should correctly reflect our set
|
||||
// prefs for number of random subdomains (2) and the list of
|
||||
// popular domains.
|
||||
@ -124,7 +124,7 @@ add_task(async function test_SuccessfulLookupAggregator() {
|
||||
|
||||
add_task(async function test_AbortedLookupAggregator() {
|
||||
let deferred = PromiseUtils.defer();
|
||||
let aggregator = new LookupAggregator(() => deferred.resolve());
|
||||
let aggregator = new LookupAggregator(() => deferred.resolve(), trrList);
|
||||
// The aggregator's domain list should correctly reflect our set
|
||||
// prefs for number of random subdomains (2) and the list of
|
||||
// popular domains.
|
||||
|
@ -11,7 +11,7 @@ add_task(async function test_TRRRacer_cleanRun() {
|
||||
let racer = new TRRRacer(() => {
|
||||
deferred.resolve();
|
||||
deferred.resolved = true;
|
||||
});
|
||||
}, trrList);
|
||||
racer.run();
|
||||
|
||||
await deferred.promise;
|
||||
@ -60,7 +60,7 @@ async function test_TRRRacer_networkFlux_helper(captivePortal = false) {
|
||||
let racer = new TRRRacer(() => {
|
||||
deferred.resolve();
|
||||
deferred.resolved = true;
|
||||
});
|
||||
}, trrList);
|
||||
racer.run();
|
||||
|
||||
if (captivePortal) {
|
||||
@ -109,7 +109,7 @@ async function test_TRRRacer_maxRetries_helper(captivePortal = false) {
|
||||
let racer = new TRRRacer(() => {
|
||||
deferred.resolve();
|
||||
deferred.resolved = true;
|
||||
});
|
||||
}, trrList);
|
||||
racer.run();
|
||||
info("ran new racer");
|
||||
// Start at i = 1 since we're already at retry #1.
|
||||
@ -179,7 +179,7 @@ add_task(async function test_TRRRacer_getFastestTRRFromResults() {
|
||||
{ trr: "trr5", time: 20 },
|
||||
{ trr: "trr5", time: 1000 },
|
||||
];
|
||||
let racer = new TRRRacer();
|
||||
let racer = new TRRRacer(undefined, trrList);
|
||||
let fastest = racer._getFastestTRRFromResults(results);
|
||||
// trr1's geometric mean is 100
|
||||
// trr2's geometric mean is 110
|
||||
|
Loading…
Reference in New Issue
Block a user