Backed out 4 changesets (bug 1600109, bug 1609037, bug 1608320) for turning bug 1605297 into permafail.

Backed out changeset ca3381ffade1 (bug 1609037)
Backed out changeset 6f3358db89c7 (bug 1608320)
Backed out changeset 0614bbf65c82 (bug 1600109)
Backed out changeset ea650c48ddcb (bug 1600109)
This commit is contained in:
Cosmin Sabou 2020-01-23 00:12:00 +02:00
Родитель f15a6c8a03
Коммит 158024baa6
11 изменённых файлов: 99 добавлений и 318 удалений

Просмотреть файл

@ -1825,12 +1825,6 @@ pref("extensions.screenshots.disabled", false);
// disable uploading to the server.
pref("extensions.screenshots.upload-disabled", false);
// DoH Rollout: the earliest date of profile creation for which we don't need
// to show the doorhanger. This is when the version of the privacy statement
// that includes DoH went live - Oct 31, 2019. This has to be a string because
// the number is outside the signed 32-bit integer range.
pref("doh-rollout.profileCreationThreshold", "1572476400000");
// URL for Learn More link for browser error logging in preferences
pref("browser.chrome.errorReporter.infoURL",
"https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/nightly-error-collection");

Просмотреть файл

@ -189,10 +189,16 @@ const stateManager = {
return !doorhangerShown;
},
async showDoorhanger() {
rollout.addDoorhangerListeners();
async showDoorHangerAndEnableDoH() {
browser.experiments.doorhanger.onDoorhangerAccept.addListener(
rollout.doorhangerAcceptListener
);
let doorhangerShown = await browser.experiments.doorhanger.show({
browser.experiments.doorhanger.onDoorhangerDecline.addListener(
rollout.doorhangerDeclineListener
);
await browser.experiments.doorhanger.show({
name: browser.i18n.getMessage("doorhangerName"),
text: "<> " + browser.i18n.getMessage("doorhangerBody"),
okLabel: browser.i18n.getMessage("doorhangerButtonOk"),
@ -203,15 +209,9 @@ const stateManager = {
),
});
if (!doorhangerShown) {
// The profile was created after the go-live date of the privacy statement
// that included DoH. Treat it as accepted.
log("Profile is new, doorhanger not shown.");
await stateManager.setState("UIOk");
await stateManager.rememberDoorhangerDecision("NewProfile");
await stateManager.rememberDoorhangerShown();
rollout.removeDoorhangerListeners();
}
// By default, enable DoH when showing the doorhanger,
// if heuristics returned no reason to not run.
await stateManager.setState("enabled");
},
};
@ -227,32 +227,11 @@ const rollout = {
return this._isTesting;
},
addDoorhangerListeners() {
browser.experiments.doorhanger.onDoorhangerAccept.addListener(
rollout.doorhangerAcceptListener
);
browser.experiments.doorhanger.onDoorhangerDecline.addListener(
rollout.doorhangerDeclineListener
);
},
removeDoorhangerListeners() {
browser.experiments.doorhanger.onDoorhangerAccept.removeListener(
rollout.doorhangerAcceptListener
);
browser.experiments.doorhanger.onDoorhangerDecline.removeListener(
rollout.doorhangerDeclineListener
);
},
async doorhangerAcceptListener(tabId) {
log("Doorhanger accepted on tab", tabId);
await stateManager.setState("UIOk");
await stateManager.rememberDoorhangerDecision("UIOk");
await stateManager.rememberDoorhangerShown();
rollout.removeDoorhangerListeners();
},
async doorhangerDeclineListener(tabId) {
@ -264,23 +243,16 @@ const rollout = {
browser.experiments.heuristics.sendHeuristicsPing("disable_doh", results);
await stateManager.rememberDisableHeuristics();
await stateManager.rememberDoorhangerShown();
rollout.removeDoorhangerListeners();
},
async heuristics(evaluateReason) {
let shouldRunHeuristics = await stateManager.shouldRunHeuristics();
if (!shouldRunHeuristics) {
return;
}
// Run heuristics defined in heuristics.js and experiments/heuristics/api.js
let results;
if (await rollout.isTesting()) {
results = await browser.experiments.preferences.getCharPref(
MOCK_HEURISTICS_PREF,
`{ "test": "disable_doh" }`
"disable_doh"
);
results = JSON.parse(results);
} else {
@ -298,14 +270,7 @@ const rollout = {
results.evaluateReason = evaluateReason;
browser.experiments.heuristics.sendHeuristicsPing(decision, results);
if (decision === "disable_doh") {
await stateManager.setState("disabled");
} else {
await stateManager.setState("enabled");
if (await stateManager.shouldShowDoorhanger()) {
await stateManager.showDoorhanger();
}
}
return decision;
},
async getSetting(name, defaultValue) {
@ -507,67 +472,81 @@ const rollout = {
await this.enterprisePolicyCheck("startup", results);
}
if (!(await stateManager.shouldRunHeuristics())) {
return;
}
let networkStatus = (await browser.networkStatus.getLinkInfo()).status;
let captiveState = "unknown";
try {
captiveState = await browser.captivePortal.getState();
} catch (e) {
// Captive Portal Service is disabled.
}
if (networkStatus == "up" && captiveState != "locked_portal") {
await rollout.heuristics("startup");
if (await stateManager.shouldRunHeuristics()) {
await this.runStartupHeuristics();
}
// Listen for network change events to run heuristics again
browser.networkStatus.onConnectionChanged.addListener(
rollout.onConnectionChanged
);
browser.networkStatus.onConnectionChanged.addListener(async () => {
log("onConnectionChanged");
let linkInfo = await browser.networkStatus.getLinkInfo();
if (linkInfo.status !== "up") {
log("Link down.");
if (rollout.networkSettledTimeout) {
log("Canceling queued heuristics run.");
clearTimeout(rollout.networkSettledTimeout);
rollout.networkSettledTimeout = null;
}
return;
}
log("Queing a heuristics run in 60s, will cancel if network fluctuates.");
let gracePeriod = (await rollout.isTesting()) ? 0 : 60000;
rollout.networkSettledTimeout = setTimeout(async () => {
log("No network fluctuation for 60 seconds, running heuristics.");
// Only run the heuristics if user hasn't explicitly enabled/disabled DoH
let shouldRunHeuristics = await stateManager.shouldRunHeuristics();
let shouldShowDoorhanger = await stateManager.shouldShowDoorhanger();
if (!shouldRunHeuristics) {
return;
}
const netChangeDecision = await rollout.heuristics("netChange");
if (netChangeDecision === "disable_doh") {
await stateManager.setState("disabled");
} else if (shouldShowDoorhanger) {
await stateManager.showDoorHangerAndEnableDoH();
} else {
await stateManager.setState("enabled");
}
}, gracePeriod);
});
// Listen to the captive portal when it unlocks
try {
browser.captivePortal.onStateChange.addListener(
rollout.onCaptiveStateChanged
);
} catch (e) {
// Captive Portal Service is disabled.
}
browser.captivePortal.onConnectivityAvailable.addListener(async () => {
log("Captive portal onConnectivityAvailable, running heuristics.");
if (rollout.networkSettledTimeout) {
log("Canceling queued heuristics run.");
clearTimeout(rollout.networkSettledTimeout);
rollout.networkSettledTimeout = null;
}
let shouldRunHeuristics = await stateManager.shouldRunHeuristics();
if (!shouldRunHeuristics) {
return;
}
await this.runStartupHeuristics();
});
},
async onConnectionChanged({ status }) {
log("onConnectionChanged", status);
async runStartupHeuristics() {
let decision = await this.heuristics("startup");
let shouldShowDoorhanger = await stateManager.shouldShowDoorhanger();
if (decision === "disable_doh") {
await stateManager.setState("disabled");
if (status != "up") {
return;
}
let captiveState = "unknown";
try {
captiveState = await browser.captivePortal.getState();
} catch (e) {
// Captive Portal Service is disabled.
}
if (captiveState == "locked_portal") {
return;
}
// The network is up and we don't know that we're in a locked portal.
// Run heuristics. If we detect a portal later, we'll run heuristics again
// when it's unlocked. In that case, this run will likely have failed.
await rollout.heuristics("netchange");
},
async onCaptiveStateChanged({ state }) {
log("onCaptiveStateChanged", state);
// unlocked_portal means we were previously in a locked portal and then
// network access was granted.
if (state == "unlocked_portal") {
await rollout.heuristics("netchange");
// If the heuristics say to enable DoH, determine if the doorhanger
// should be shown
} else if (shouldShowDoorhanger) {
await stateManager.showDoorHangerAndEnableDoH();
} else {
// Doorhanger has been shown before and did not opt-out
await stateManager.setState("enabled");
}
},
};

Просмотреть файл

@ -7,8 +7,6 @@
/* global BrowserWindowTracker, ExtensionCommon, ExtensionAPI */
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
ChromeUtils.import("resource:///modules/EveryWindow.jsm", this);
var { EventManager, EventEmitter } = ExtensionCommon;
const {
@ -99,65 +97,7 @@ this.doorhanger = class doorhanger extends ExtensionAPI {
experiments: {
doorhanger: {
async show(properties) {
let profileAge = await ChromeUtils.import(
"resource://gre/modules/ProfileAge.jsm",
{}
).ProfileAge();
let creationDate = await profileAge.created;
let firstUse = await profileAge.firstUse;
let resetDate = await profileAge.reset;
let profileDate = resetDate || firstUse || creationDate;
// We only need to show the doorhanger to users who have not been
// shown a version of the privacy statement that includes DoH at
// first-run.
let profileCreationThreshold = parseInt(
Preferences.get("doh-rollout.profileCreationThreshold")
);
if (
!isNaN(profileCreationThreshold) &&
profileDate > profileCreationThreshold
) {
return false;
}
// Show the doorhanger next time there's a top-level location change.
let tabsProgressListener = {
onLocationChange(
aBrowser,
aWebProgress,
aRequest,
aLocationURI,
aFlags
) {
let topWindow = getMostRecentBrowserWindow();
// Filter out history.push/pop and subframes.
if (
aBrowser != topWindow.gBrowser.selectedBrowser ||
aFlags &
Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT ||
!aWebProgress.isTopLevel
) {
return;
}
doorhangerEventEmitter.emitShow(properties);
EveryWindow.unregisterCallback("doh-rollout");
},
};
EveryWindow.registerCallback(
"doh-rollout",
win => {
win.gBrowser.addTabsProgressListener(tabsProgressListener);
},
(win, closing) => {
if (closing) {
return;
}
win.gBrowser.removeTabsProgressListener(tabsProgressListener);
}
);
return true;
await doorhangerEventEmitter.emitShow(properties);
},
onDoorhangerAccept: new EventManager({
context,

Просмотреть файл

@ -5,7 +5,6 @@ skip-if = debug # Bug 1548006 - reloading an addon upsets the leak checker.
[browser_cleanFlow.js]
[browser_dirtyEnable.js]
[browser_doorhangerUserReject.js]
[browser_doorhanger_newProfile.js]
[browser_policyOverride.js]
skip-if = (!debug && bits == 64) #Bug 1605297
[browser_userInterference.js]

Просмотреть файл

@ -1,7 +1,5 @@
"use strict";
add_task(setup);
add_task(async function testCleanFlow() {
// Set up a passing environment and enable DoH.
setPassingHeuristics();
@ -13,7 +11,6 @@ add_task(async function testCleanFlow() {
});
is(Preferences.get(prefs.DOH_SELF_ENABLED_PREF), true, "Breadcrumb saved.");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, EXAMPLE_URL);
let panel = await promise;
is(
Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF),
@ -28,7 +25,6 @@ add_task(async function testCleanFlow() {
await promise;
await ensureTRRMode(2);
await checkHeuristicsTelemetry("enable_doh", "startup");
await BrowserTestUtils.waitForCondition(() => {
return Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF);
@ -49,32 +45,28 @@ add_task(async function testCleanFlow() {
"Breadcrumb not cleared."
);
BrowserTestUtils.removeTab(tab);
// Change the environment to failing and simulate a network change.
setFailingHeuristics();
simulateNetworkChange();
await ensureTRRMode(0);
await checkHeuristicsTelemetry("disable_doh", "netchange");
// Trigger another network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
await checkHeuristicsTelemetry("disable_doh", "netchange");
// Restart the add-on for good measure.
await restartAddon();
await ensureNoTRRModeChange(0);
await checkHeuristicsTelemetry("disable_doh", "startup");
// Set a passing environment and simulate a network change.
setPassingHeuristics();
simulateNetworkChange();
await ensureTRRMode(2);
await checkHeuristicsTelemetry("enable_doh", "netchange");
// Again, repeat and check nothing changed.
simulateNetworkChange();
await ensureNoTRRModeChange(2);
await checkHeuristicsTelemetry("enable_doh", "netchange");
// Clean up.
await resetPrefsAndRestartAddon();
});

Просмотреть файл

@ -1,7 +1,5 @@
"use strict";
add_task(setup);
add_task(async function testDirtyEnable() {
// Set up a failing environment, pre-set DoH to enabled, and verify that
// when the add-on is enabled, it doesn't do anything - DoH remains turned on.
@ -22,20 +20,19 @@ add_task(async function testDirtyEnable() {
"Breadcrumb not saved."
);
await ensureNoTRRModeChange(2);
checkHeuristicsTelemetry("prefHasUserValue", "first_run");
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(2);
ensureNoHeuristicsTelemetry();
// Restart for good measure.
await restartAddon();
await ensureNoTRRModeChange(2);
ensureNoHeuristicsTelemetry();
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(2);
ensureNoHeuristicsTelemetry();
// Clean up.
await resetPrefsAndRestartAddon();
});

Просмотреть файл

@ -1,7 +1,5 @@
"use strict";
add_task(setup);
add_task(async function testDoorhangerUserReject() {
// Set up a passing environment and enable DoH.
setPassingHeuristics();
@ -13,7 +11,6 @@ add_task(async function testDoorhangerUserReject() {
});
is(Preferences.get(prefs.DOH_SELF_ENABLED_PREF), true, "Breadcrumb saved.");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, EXAMPLE_URL);
let panel = await promise;
is(
Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF),
@ -22,7 +19,6 @@ add_task(async function testDoorhangerUserReject() {
);
await ensureTRRMode(2);
await checkHeuristicsTelemetry("enable_doh", "startup");
// Click the doorhanger's "reject" button.
let button = panel.querySelector(".popup-notification-secondary-button");
@ -50,24 +46,21 @@ add_task(async function testDoorhangerUserReject() {
"Breadcrumb cleared."
);
BrowserTestUtils.removeTab(tab);
await ensureTRRMode(5);
await checkHeuristicsTelemetry("disable_doh", "doorhangerDecline");
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(5);
ensureNoHeuristicsTelemetry();
// Restart the add-on for good measure.
await restartAddon();
await ensureNoTRRModeChange(5);
ensureNoHeuristicsTelemetry();
// Set failing environment and trigger another network change.
setFailingHeuristics();
simulateNetworkChange();
await ensureNoTRRModeChange(5);
ensureNoHeuristicsTelemetry();
// Clean up.
await resetPrefsAndRestartAddon();
});

Просмотреть файл

@ -1,34 +0,0 @@
"use strict";
add_task(setup);
add_task(async function testDoorhanger() {
Preferences.reset(prefs.PROFILE_CREATION_THRESHOLD_PREF);
// Set up a passing environment and enable DoH.
setPassingHeuristics();
Preferences.set(prefs.DOH_ENABLED_PREF, true);
await BrowserTestUtils.waitForCondition(() => {
return Preferences.get(prefs.DOH_SELF_ENABLED_PREF);
});
is(Preferences.get(prefs.DOH_SELF_ENABLED_PREF), true, "Breadcrumb saved.");
await BrowserTestUtils.waitForCondition(() => {
return Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF);
});
is(
Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF),
true,
"Doorhanger shown pref saved."
);
is(
Preferences.get(prefs.DOH_DOORHANGER_USER_DECISION_PREF),
"NewProfile",
"Doorhanger decision saved."
);
is(
Preferences.get(prefs.DOH_SELF_ENABLED_PREF),
true,
"Breadcrumb not cleared."
);
});

Просмотреть файл

@ -1,7 +1,5 @@
"use strict";
add_task(setup);
const { EnterprisePolicyTesting } = ChromeUtils.import(
"resource://testing-common/EnterprisePolicyTesting.jsm",
null
@ -38,28 +36,25 @@ add_task(async function testPolicyOverride() {
"Breadcrumb not saved."
);
await ensureNoTRRModeChange(0);
await checkHeuristicsTelemetry("policy_without_doh", "first_run");
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
ensureNoHeuristicsTelemetry();
// Restart for good measure.
await restartAddon();
await ensureNoTRRModeChange(0);
await checkHeuristicsTelemetry("policy_without_doh", "startup");
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
ensureNoHeuristicsTelemetry();
// Clean up.
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
policies: {},
});
EnterprisePolicyTesting.resetRunOnceState();
await resetPrefsAndRestartAddon();
is(
Services.policies.status,

Просмотреть файл

@ -1,7 +1,5 @@
"use strict";
add_task(setup);
add_task(async function testUserInterference() {
// Set up a passing environment and enable DoH.
setPassingHeuristics();
@ -13,7 +11,6 @@ add_task(async function testUserInterference() {
});
is(Preferences.get(prefs.DOH_SELF_ENABLED_PREF), true, "Breadcrumb saved.");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, EXAMPLE_URL);
let panel = await promise;
is(
Preferences.get(prefs.DOH_DOORHANGER_SHOWN_PREF),
@ -42,10 +39,7 @@ add_task(async function testUserInterference() {
"Doorhanger decision saved."
);
BrowserTestUtils.removeTab(tab);
await ensureTRRMode(2);
await checkHeuristicsTelemetry("enable_doh", "startup");
// Set the TRR mode pref manually and ensure we respect this.
Preferences.set(prefs.TRR_MODE_PREF, 0);
@ -53,7 +47,6 @@ add_task(async function testUserInterference() {
// Simulate a network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
await checkHeuristicsTelemetry("disable_doh", "userModified");
is(
Preferences.get(prefs.DOH_DISABLED_PREF, false),
@ -69,15 +62,15 @@ add_task(async function testUserInterference() {
// Simulate another network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
ensureNoHeuristicsTelemetry();
// Restart the add-on for good measure.
await restartAddon();
await ensureNoTRRModeChange(0);
ensureNoHeuristicsTelemetry();
// Simulate another network change.
simulateNetworkChange();
await ensureNoTRRModeChange(0);
ensureNoHeuristicsTelemetry();
// Clean up.
await resetPrefsAndRestartAddon();
});

Просмотреть файл

@ -12,14 +12,12 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/Preferences.jsm"
);
const { CommonUtils } = ChromeUtils.import(
"resource://services-common/utils.js"
);
SpecialPowers.pushPrefEnv({
set: [["security.notification_enable_delay", 0]],
});
const ADDON_ID = "doh-rollout@mozilla.org";
const EXAMPLE_URL = "https://example.com/";
const prefs = {
DOH_ENABLED_PREF: "doh-rollout.enabled",
TRR_MODE_PREF: "network.trr.mode",
@ -33,7 +31,6 @@ const prefs = {
DOH_BALROG_MIGRATION_PREF: "doh-rollout.balrog-migration-done",
DOH_DEBUG_PREF: "doh-rollout.debug",
MOCK_HEURISTICS_PREF: "doh-rollout.heuristics.mockValues",
PROFILE_CREATION_THRESHOLD_PREF: "doh-rollout.profileCreationThreshold",
};
const fakePassingHeuristics = JSON.stringify({
@ -58,65 +55,6 @@ const fakeFailingHeuristics = JSON.stringify({
policy: "disable_doh",
});
async function setup() {
SpecialPowers.pushPrefEnv({
set: [["security.notification_enable_delay", 0]],
});
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
Services.telemetry.clearEvents();
// Set the profile creation threshold to very far in the future by defualt,
// so that we can test the doorhanger. browser_doorhanger_newProfile.js
// overrides this.
Preferences.set(prefs.PROFILE_CREATION_THRESHOLD_PREF, "99999999999999");
registerCleanupFunction(async () => {
Services.telemetry.canRecordExtended = oldCanRecord;
Services.telemetry.clearEvents();
await resetPrefsAndRestartAddon();
});
}
async function checkHeuristicsTelemetry(decision, evaluateReason) {
let events;
await BrowserTestUtils.waitForCondition(() => {
events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS
).dynamic;
return events;
});
events = events.filter(
e => e[1] == "doh" && e[2] == "evaluate" && e[3] == "heuristics"
);
is(events.length, 1, "Found the expected heuristics event.");
is(events[0][4], decision, "The event records the expected decision");
if (evaluateReason) {
is(events[0][5].evaluateReason, evaluateReason, "Got the expected reason.");
}
// After checking the event, clear all telemetry. Since we check for a single
// event above, this ensures all heuristics events are intentional and tested.
// TODO: Test events other than heuristics. Those tests would also work the
// same way, so as to test one event at a time, and this clearEvents() call
// will continue to exist as-is.
Services.telemetry.clearEvents();
}
function ensureNoHeuristicsTelemetry() {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS
).dynamic;
if (!events) {
ok(true, "Found no heuristics events.");
return;
}
events = events.filter(
e => e[1] == "doh" && e[2] == "evaluate" && e[3] == "heuristics"
);
is(events.length, 0, "Found no heuristics events.");
}
function setPassingHeuristics() {
Preferences.set(prefs.MOCK_HEURISTICS_PREF, fakePassingHeuristics);
}
@ -153,12 +91,7 @@ async function waitForDoorhanger() {
}
function simulateNetworkChange() {
// The networkStatus API does not actually propagate the link status we supply
// here, but rather sends the link status from the NetworkLinkService.
// This means there's no point sending a down and then an up - the extension
// will just receive "up" twice.
// TODO: Implement a mock NetworkLinkService and use it to also simulate
// network down events.
Services.obs.notifyObservers(null, "network:link-status-changed", "down");
Services.obs.notifyObservers(null, "network:link-status-changed", "up");
}