fune/docshell/test/browser/browser_fission_maxOrigins.js

222 lines
7 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
SimpleTest.requestFlakyTimeout("Need to test expiration timeout");
function delay(msec) {
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
return new Promise(resolve => setTimeout(resolve, msec));
}
function promiseIdle() {
return new Promise(resolve => {
Services.tm.idleDispatchToMainThread(resolve);
});
}
const ORIGIN_CAP = 5;
const SLIDING_WINDOW_MS = 5000;
const PREF_ORIGIN_CAP = "fission.experiment.max-origins.origin-cap";
const PREF_SLIDING_WINDOW_MS =
"fission.experiment.max-origins.sliding-window-ms";
const PREF_QUALIFIED = "fission.experiment.max-origins.qualified";
const PREF_LAST_QUALIFIED = "fission.experiment.max-origins.last-qualified";
const PREF_LAST_DISQUALIFIED =
"fission.experiment.max-origins.last-disqualified";
const SITE_ORIGINS = [
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.com/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.org/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.net/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.tw/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.cn/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.fi/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.in/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://example.lk/",
// eslint-disable-next-line @microsoft/sdl/no-insecure-url
"http://w3c-test.org/",
"https://www.mozilla.org/",
];
function openTab(url) {
return BrowserTestUtils.openNewForegroundTab({
gBrowser,
url,
waitForStateStop: true,
});
}
async function assertQualified() {
// The unique origin calculation runs from an idle task, so make sure
// the queued idle task has had a chance to run.
await promiseIdle();
// Make sure the clock has advanced since the qualification timestamp
// was recorded.
await delay(1);
let qualified = Services.prefs.getBoolPref(PREF_QUALIFIED);
let lastQualified = Services.prefs.getIntPref(PREF_LAST_QUALIFIED);
let lastDisqualified = Services.prefs.getIntPref(PREF_LAST_DISQUALIFIED);
let currentTime = Date.now() / 1000;
ok(qualified, "Should be qualified");
ok(
lastQualified > 0,
`Last qualified timestamp (${lastQualified}) should be greater than 0`
);
ok(
lastQualified < currentTime,
`Last qualified timestamp (${lastQualified}) should be less than the current time (${currentTime})`
);
ok(
lastQualified > lastDisqualified,
`Last qualified timestamp (${lastQualified}) should be after the last disqualified time (${lastDisqualified})`
);
ok(
lastDisqualified < currentTime,
`Last disqualified timestamp (${lastDisqualified}) should be less than the current time (${currentTime})`
);
}
async function assertDisqualified(opts) {
// The unique origin calculation runs from an idle task, so make sure
// the queued idle task has had a chance to run.
await promiseIdle();
let qualified = Services.prefs.getBoolPref(PREF_QUALIFIED);
let lastQualified = Services.prefs.getIntPref(PREF_LAST_QUALIFIED, 0);
let lastDisqualified = Services.prefs.getIntPref(PREF_LAST_DISQUALIFIED);
let currentTime = Date.now() / 1000;
ok(!qualified, "Should not be qualified");
if (!opts.initialValues) {
ok(
lastQualified > 0,
`Last qualified timestamp (${lastQualified}) should be greater than 0`
);
}
ok(
lastQualified < currentTime,
`Last qualified timestamp (${lastQualified}) should be less than the current time (${currentTime})`
);
ok(
lastDisqualified < currentTime,
`Last disqualified timestamp (${lastDisqualified}) should be less than the current time (${currentTime})`
);
ok(
lastDisqualified > 0,
`Last disqualified timestamp (${lastDisqualified}) should be greater than 0`
);
if (opts.qualificationPending) {
ok(
lastQualified > lastDisqualified,
`Last qualified timestamp (${lastQualified}) should be after the last disqualified time (${lastDisqualified})`
);
} else {
ok(
lastDisqualified > lastQualified,
`Last disqualified timestamp (${lastDisqualified}) should be after the last qualified time (${lastQualified})`
);
}
}
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [
[PREF_ORIGIN_CAP, ORIGIN_CAP],
[PREF_SLIDING_WINDOW_MS, SLIDING_WINDOW_MS],
],
});
const { BrowserTelemetryUtils } = ChromeUtils.importESModule(
"resource://gre/modules/BrowserTelemetryUtils.sys.mjs"
);
// Make sure we actually record telemetry for our disqualifying origin
// count.
BrowserTelemetryUtils.min_interval = 1;
let tabs = [];
// Open one initial tab to make sure the origin counting code has had
// a chance to run before checking the initial state.
tabs.push(await openTab("http://mochi.test:8888/"));
await assertQualified();
let lastDisqualified = Services.prefs.getIntPref(PREF_LAST_DISQUALIFIED);
is(lastDisqualified, 0, "Last disqualification timestamp should be 0");
info(
`Opening ${SITE_ORIGINS.length} tabs with distinct origins to exceed the cap (${ORIGIN_CAP})`
);
ok(
SITE_ORIGINS.length > ORIGIN_CAP,
"Should have enough site origins to exceed the origin cap"
);
tabs.push(...(await Promise.all(SITE_ORIGINS.map(openTab))));
await assertDisqualified({ qualificationPending: false });
info("Close unique-origin tabs");
await Promise.all(tabs.map(tab => BrowserTestUtils.removeTab(tab)));
info("Open a new tab to trigger the origin count code once more");
tabs = [await openTab(SITE_ORIGINS[0])];
await assertDisqualified({ qualificationPending: true });
info(
"Wait long enough to clear the sliding window since last disqualified state"
);
await delay(SLIDING_WINDOW_MS + 1000);
info("Open a new tab to trigger the origin count code again");
tabs.push(await openTab(SITE_ORIGINS[0]));
await assertQualified();
info(
"Clear preference values and re-populate the initial value from telemetry"
);
Services.prefs.clearUserPref(PREF_QUALIFIED);
Services.prefs.clearUserPref(PREF_LAST_QUALIFIED);
Services.prefs.clearUserPref(PREF_LAST_DISQUALIFIED);
BrowserTelemetryUtils._checkedInitialExperimentQualification = false;
info("Open a new tab to trigger the origin count code again");
tabs.push(await openTab(SITE_ORIGINS[0]));
await assertDisqualified({ initialValues: true });
info(
"Wait long enough to clear the sliding window since last disqualified state"
);
await delay(SLIDING_WINDOW_MS + 1000);
info("Open a new tab to trigger the origin count code again");
tabs.push(await openTab(SITE_ORIGINS[0]));
await assertQualified();
await Promise.all(tabs.map(tab => BrowserTestUtils.removeTab(tab)));
// Clear the cached recording interval so it resets to the default
// value on the next call.
BrowserTelemetryUtils.min_interval = null;
});