Bug 1947734 - Test, r=anti-tracking-reviewers,timhuang

Differential Revision: https://phabricator.services.mozilla.com/D237880
This commit is contained in:
Emma Zuehlcke
2025-04-10 14:20:54 +00:00
parent 9f00747078
commit 7714fcfba7
3 changed files with 187 additions and 110 deletions

View File

@@ -16,6 +16,8 @@ support-files = [
"file_web_worker.js",
]
["browser_bouncetracking_clearingPurgeLogCrash.js"]
["browser_bouncetracking_cookie_behavior.js"]
["browser_bouncetracking_dry_run.js"]

View File

@@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Verifies that clearing the purge log via nsIClearDataService does not lead to
* a crash.
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1947281#c2 for details.
*/
async function bounceTwice() {
for (let i = 0; i < 2; i++) {
await runTestBounce({
bounceType: "client",
setState: "cookie-client",
// We don't want to clear the purge log here because we want to test that
// clearing the purge log through nsIClearDataService does not lead to a
// crash.
skipBounceTrackingProtectionCleanup: true,
// This also calls into BTP clearing.
skipSiteDataCleanup: true,
// Skip state checks on the second bounce. The second test run would
// otherwise fail because it expects to start with clean BTP state.
skipStateChecks: i == 1,
});
}
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.bounceTrackingProtection.requireStatefulBounces", true],
["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
],
});
});
add_task(async function test_crash() {
info("Bounce and purge twice so we get two entries in recent purges.");
await bounceTwice();
info("Clear BTP state via nsIClearDataService which must not crash.");
await new Promise(function (resolve) {
Services.clearData.deleteDataInTimeRange(
0,
// In microseconds
Date.now() * 1000,
true,
Ci.nsIClearDataService.CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
failedFlags => {
Assert.equal(failedFlags, 0, "Clearing should have succeeded");
resolve();
}
);
});
// Cleanup
await SiteDataTestUtils.clear();
});

View File

@@ -281,6 +281,8 @@ async function waitForRecordBounces(browser) {
* @param {boolean} [options.skipBounceTrackingProtectionCleanup=false] - Skip
* the cleanup of BounceTrackingProtection state. When this is enabled the
* caller is responsible for cleaning BTP state.
* @param {boolean} [options.skipStateChecks=false] - Only run a bounce,
* skipping BTP state checks.
* @param {boolean} [options.closeTabAfterBounce=false] - Close the tab right
* after the bounce completes before the extended navigation ends as the result
* of a timeout or user interaction.
@@ -299,6 +301,7 @@ async function runTestBounce(options = {}) {
expectPurge = true,
originAttributes = {},
postBounceCallback = () => {},
skipStateChecks = false,
skipSiteDataCleanup = false,
skipBounceTrackingProtectionCleanup = false,
closeTabAfterBounce = false,
@@ -322,34 +325,36 @@ async function runTestBounce(options = {}) {
}
}
if (btpIsDisabled) {
Assert.ok(!expectCandidate, "Expect no classification in disabled mode.");
Assert.ok(
!expectRecordBounces,
"Expect no record bounces in disabled mode."
);
Assert.ok(!expectPurge, "Expect no purge in disabled mode.");
} else {
Assert.ok(
bounceTrackingProtection,
"BTP singleton must be available in any of the 'enabled' modes."
);
}
if (!skipStateChecks) {
if (btpIsDisabled) {
Assert.ok(!expectCandidate, "Expect no classification in disabled mode.");
Assert.ok(
!expectRecordBounces,
"Expect no record bounces in disabled mode."
);
Assert.ok(!expectPurge, "Expect no purge in disabled mode.");
} else {
Assert.ok(
bounceTrackingProtection,
"BTP singleton must be available in any of the 'enabled' modes."
);
}
if (bounceTrackingProtection) {
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
originAttributes
).length,
0,
"No bounce tracker hosts initially."
);
Assert.equal(
bounceTrackingProtection.testGetUserActivationHosts(originAttributes)
.length,
0,
"No user activation hosts initially."
);
if (bounceTrackingProtection) {
Assert.equal(
bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
originAttributes
).length,
0,
"No bounce tracker hosts initially."
);
Assert.equal(
bounceTrackingProtection.testGetUserActivationHosts(originAttributes)
.length,
0,
"No user activation hosts initially."
);
}
}
let win = window;
@@ -448,55 +453,57 @@ async function runTestBounce(options = {}) {
await new Promise(resolve => setTimeout(resolve, 0));
}
if (btpIsDisabled) {
// In MODE_DISABLED `bounceTrackingProtection` may still be defined if it
// was previously accessed in an enabled state. In that case make sure
// nothing is recorded.
if (bounceTrackingProtection) {
if (!skipStateChecks) {
if (btpIsDisabled) {
// In MODE_DISABLED `bounceTrackingProtection` may still be defined if it
// was previously accessed in an enabled state. In that case make sure
// nothing is recorded.
if (bounceTrackingProtection) {
Assert.deepEqual(
bounceTrackingProtection
.testGetBounceTrackerCandidateHosts(originAttributes)
.map(entry => entry.siteHost),
[],
"Should not have identified any bounce trackers"
);
Assert.deepEqual(
bounceTrackingProtection
.testGetUserActivationHosts(originAttributes)
.map(entry => entry.siteHost),
[],
"Should not have recorded any user activation"
);
} else {
info("BTP singleton is unavailable because mode is MODE_DISABLED.");
}
} else {
// Any of the "enabled" modes.
Assert.deepEqual(
bounceTrackingProtection
.testGetBounceTrackerCandidateHosts(originAttributes)
.map(entry => entry.siteHost),
[],
"Should not have identified any bounce trackers"
expectCandidate ? [SITE_TRACKER] : [],
`Should ${
expectCandidate ? "" : "not "
}have identified ${SITE_TRACKER} as a bounce tracker.`
);
let expectedUserActivationHosts = [SITE_A];
if (!closeTabAfterBounce) {
// If we didn't close the tab early we should have user activation for the
// destination site.
expectedUserActivationHosts.push(SITE_B);
}
Assert.deepEqual(
bounceTrackingProtection
.testGetUserActivationHosts(originAttributes)
.map(entry => entry.siteHost),
[],
"Should not have recorded any user activation"
.map(entry => entry.siteHost)
.sort(),
expectedUserActivationHosts.sort(),
"Should only have user activation for sites where we clicked links."
);
} else {
info("BTP singleton is unavailable because mode is MODE_DISABLED.");
}
} else {
// Any of the "enabled" modes.
Assert.deepEqual(
bounceTrackingProtection
.testGetBounceTrackerCandidateHosts(originAttributes)
.map(entry => entry.siteHost),
expectCandidate ? [SITE_TRACKER] : [],
`Should ${
expectCandidate ? "" : "not "
}have identified ${SITE_TRACKER} as a bounce tracker.`
);
let expectedUserActivationHosts = [SITE_A];
if (!closeTabAfterBounce) {
// If we didn't close the tab early we should have user activation for the
// destination site.
expectedUserActivationHosts.push(SITE_B);
}
Assert.deepEqual(
bounceTrackingProtection
.testGetUserActivationHosts(originAttributes)
.map(entry => entry.siteHost)
.sort(),
expectedUserActivationHosts.sort(),
"Should only have user activation for sites where we clicked links."
);
}
// If the caller specified a function to run after the bounce, run it now.
@@ -518,53 +525,61 @@ async function runTestBounce(options = {}) {
"testRunPurgeBounceTrackers should reject when BTP is disabled."
);
} else {
Assert.deepEqual(
await bounceTrackingProtection.testRunPurgeBounceTrackers(),
expectPurge ? [SITE_TRACKER] : [],
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
);
let purgedHosts =
await bounceTrackingProtection.testRunPurgeBounceTrackers();
info("Testing the purge log.");
let purgeLog =
bounceTrackingProtection.testGetRecentlyPurgedTrackers(
originAttributes
if (!skipStateChecks) {
Assert.deepEqual(
purgedHosts,
expectPurge ? [SITE_TRACKER] : [],
`Should ${expectPurge ? "" : "not "}purge state for ${SITE_TRACKER}.`
);
// Purges are only logged in (fully) enabled mode. Dry-run mode does not
// log purges.
if (expectPurge && mode == Ci.nsIBounceTrackingProtection.MODE_ENABLED) {
Assert.equal(
purgeLog.length,
1,
"Should have one tracker in purge log."
);
let { siteHost, timeStamp, purgeTime } = purgeLog[0];
Assert.equal(
siteHost,
SITE_TRACKER,
`The purge log entry should be for site host '${SITE_TRACKER}'`
);
Assert.greater(
timeStamp,
0,
"The purge log entry should have a valid timestamp for bounce time."
);
Assert.greater(
purgeTime,
0,
"The purge log entry should have a valid timestamp for purge time."
);
Assert.greaterOrEqual(
purgeTime,
timeStamp,
"The purge time should be greater or equal to bounce time."
);
} else {
Assert.equal(
purgeLog.length,
0,
"Should have no trackers in purge log."
);
info("Testing the purge log.");
let purgeLog =
bounceTrackingProtection.testGetRecentlyPurgedTrackers(
originAttributes
);
// Purges are only logged in (fully) enabled mode. Dry-run mode does not
// log purges.
if (
expectPurge &&
mode == Ci.nsIBounceTrackingProtection.MODE_ENABLED
) {
Assert.equal(
purgeLog.length,
1,
"Should have one tracker in purge log."
);
let { siteHost, timeStamp, purgeTime } = purgeLog[0];
Assert.equal(
siteHost,
SITE_TRACKER,
`The purge log entry should be for site host '${SITE_TRACKER}'`
);
Assert.greater(
timeStamp,
0,
"The purge log entry should have a valid timestamp for bounce time."
);
Assert.greater(
purgeTime,
0,
"The purge log entry should have a valid timestamp for purge time."
);
Assert.greaterOrEqual(
purgeTime,
timeStamp,
"The purge time should be greater or equal to bounce time."
);
} else {
Assert.equal(
purgeLog.length,
0,
"Should have no trackers in purge log."
);
}
}
}
} else {