Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* 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";
// The URL will guarantee to trigger a real-time request.
const TEST_URL = "https://www.example.com/";
let { UrlClassifierTestUtils } = ChromeUtils.importESModule(
);
function waitForSimulationResult() {
return new Promise(resolve => {
function observer(subject, topic, data) {
Services.obs.removeObserver(
observer,
"urlclassifier-realtime-simulation-result"
);
let [wouldSendRequest, requestBytes, responseBytes] = data.split(",");
resolve({
wouldSendRequest: wouldSendRequest === "1",
requestBytes: parseInt(requestBytes, 10),
responseBytes: parseInt(responseBytes, 10),
});
}
Services.obs.addObserver(
observer,
"urlclassifier-realtime-simulation-result"
);
});
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [
["browser.safebrowsing.realTime.enabled", true],
["browser.safebrowsing.realTime.debug", true],
["browser.safebrowsing.globalCache.enabled", true],
["browser.safebrowsing.realTime.simulation.enabled", true],
["browser.safebrowsing.realTime.simulation.cacheTTLSec", 1],
],
});
registerCleanupFunction(async () => {
UrlClassifierTestUtils.cleanRealTimeSimulatorCache();
Services.prefs.clearUserPref(
"privacy.trackingprotection.allow_list.hasUserInteractedWithETPSettings"
);
});
});
// Test that the simulator sends a notification when processing a URL.
add_task(async function test_simulation_notification() {
info("Testing simulation notification");
UrlClassifierTestUtils.cleanRealTimeSimulatorCache();
// Set the hit probability to 0.0 so we always get a cache miss.
await SpecialPowers.pushPrefEnv({
set: [["browser.safebrowsing.realTime.simulation.hitProbability", 0]],
});
await UrlClassifierTestUtils.addTestV5Entry();
let resultPromise = waitForSimulationResult();
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
let result = await resultPromise;
ok(result.wouldSendRequest, "Should indicate a request would be sent");
Assert.greater(
result.requestBytes,
0,
"Request bytes should be greater than 0"
);
is(result.responseBytes, 5, "Response bytes should be 5 (no hits)");
await BrowserTestUtils.removeTab(tab);
UrlClassifierTestUtils.cleanupTestV5Entry();
});
// Test that the telemetry is properly recorded.
add_task(async function test_simulation_telemetry() {
info("Testing simulation telemetry recording");
Services.fog.testResetFOG();
UrlClassifierTestUtils.cleanRealTimeSimulatorCache();
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.category", "standard"],
["browser.safebrowsing.realTime.simulation.hitProbability", 0],
],
});
await UrlClassifierTestUtils.addTestV5Entry();
let resultPromise = waitForSimulationResult();
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
let result = await resultPromise;
ok(result.wouldSendRequest, "Request should be sent");
// Verify Global Cache telemetry.
is(
Glean.urlclassifier.globalCacheMiss.standard_normal.testGetValue(),
1,
"Global cache miss should be recorded for standard_normal"
);
is(
Glean.urlclassifier.globalCacheHit.standard_normal.testGetValue(),
null,
"No global cache hit should be recorded"
);
// Verify simulation telemetry.
is(
Glean.urlclassifier.realtimeSimulationRequestCount.standard_normal.testGetValue(),
1,
"Request count should be 1 for standard_normal"
);
Assert.greater(
Glean.urlclassifier.realtimeSimulationRequestSize.standard_normal.testGetValue(),
0,
"Request size should be greater than 0"
);
is(
Glean.urlclassifier.realtimeSimulationResponseSize.standard_normal.testGetValue(),
5,
"Response size should be 5 (no hits)"
);
await BrowserTestUtils.removeTab(tab);
UrlClassifierTestUtils.cleanupTestV5Entry();
await SpecialPowers.popPrefEnv();
});
// Test that globalCacheHit telemetry is recorded when the URL is in the cache.
add_task(async function test_global_cache_hit_telemetry() {
info("Testing global cache hit telemetry");
Services.fog.testResetFOG();
await SpecialPowers.pushPrefEnv({
set: [["browser.contentblocking.category", "standard"]],
});
await UrlClassifierTestUtils.addTestV5Entry();
let notificationPromise = new Promise(resolve => {
function observer(subject, topic, data) {
Services.obs.removeObserver(observer, "urlclassifier-globalcache-result");
resolve(data);
}
Services.obs.addObserver(observer, "urlclassifier-globalcache-result");
});
let tab = BrowserTestUtils.addTab(
gBrowser,
);
let result = await notificationPromise;
is(result, "hit", "Should get a global cache hit");
// Verify Global Cache hit telemetry.
is(
Glean.urlclassifier.globalCacheHit.standard_normal.testGetValue(),
1,
"Global cache hit should be recorded for standard_normal"
);
is(
Glean.urlclassifier.globalCacheMiss.standard_normal.testGetValue(),
null,
"No global cache miss should be recorded"
);
// Verify no simulation telemetry is recorded for a cache hit.
is(
Glean.urlclassifier.realtimeSimulationRequestCount.standard_normal.testGetValue(),
null,
"No simulation request count for global cache hit"
);
await BrowserTestUtils.removeTab(tab);
UrlClassifierTestUtils.cleanupTestV5Entry();
await SpecialPowers.popPrefEnv();
});
// Test telemetry with strict ETP mode and private window.
add_task(async function test_simulation_telemetry_strict_private() {
info("Testing simulation telemetry with strict ETP in private window");
Services.fog.testResetFOG();
UrlClassifierTestUtils.cleanRealTimeSimulatorCache();
await SpecialPowers.pushPrefEnv({
set: [
["browser.contentblocking.category", "strict"],
["browser.safebrowsing.realTime.simulation.hitProbability", 0],
],
});
await UrlClassifierTestUtils.addTestV5Entry();
let privateWin = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
let resultPromise = waitForSimulationResult();
let tab = BrowserTestUtils.addTab(privateWin.gBrowser, TEST_URL);
let result = await resultPromise;
ok(result.wouldSendRequest, "Request should be sent");
// Verify telemetry is recorded under strict_private.
is(
Glean.urlclassifier.globalCacheMiss.strict_private.testGetValue(),
1,
"Global cache miss should be recorded for strict_private"
);
is(
Glean.urlclassifier.realtimeSimulationRequestCount.strict_private.testGetValue(),
1,
"Request count should be 1 for strict_private"
);
Assert.greater(
Glean.urlclassifier.realtimeSimulationRequestSize.strict_private.testGetValue(),
0,
"Request size should be greater than 0 for strict_private"
);
// Verify no telemetry recorded for standard_normal.
is(
Glean.urlclassifier.realtimeSimulationRequestCount.standard_normal.testGetValue(),
null,
"No request count should be recorded for standard_normal"
);
await BrowserTestUtils.removeTab(tab);
await BrowserTestUtils.closeWindow(privateWin);
UrlClassifierTestUtils.cleanupTestV5Entry();
await SpecialPowers.popPrefEnv();
});
// Test that the simulator caches results and doesn't send duplicate requests.
add_task(async function test_simulation_cache() {
info("Testing simulation cache behavior");
UrlClassifierTestUtils.cleanRealTimeSimulatorCache();
await UrlClassifierTestUtils.addTestV5Entry();
// Set hit probability to 1000000 (100%) so we always get a cache entry.
await SpecialPowers.pushPrefEnv({
set: [["browser.safebrowsing.realTime.simulation.hitProbability", 1000000]],
});
// First request should be sent.
let resultPromise = waitForSimulationResult();
let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
let result = await resultPromise;
ok(result.wouldSendRequest, "First request should be sent");
Assert.greater(
result.requestBytes,
0,
"Request bytes should be greater than 0"
);
Assert.greater(
result.responseBytes,
5,
"Response bytes should include hit data"
);
await BrowserTestUtils.removeTab(tab);
// Second request to the same URL should hit the cache.
resultPromise = waitForSimulationResult();
tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
result = await resultPromise;
ok(!result.wouldSendRequest, "Second request should hit cache");
is(result.requestBytes, 0, "No request bytes for cache hit");
is(result.responseBytes, 0, "No response bytes for cache hit");
await BrowserTestUtils.removeTab(tab);
// Wait for cache to expire.
info("Waiting for cache to expire");
/* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise(resolve => setTimeout(resolve, 2000));
// Third request should be sent again after cache expiry.
resultPromise = waitForSimulationResult();
tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
result = await resultPromise;
ok(
result.wouldSendRequest,
"Third request should be sent after cache expiry"
);
Assert.greater(
result.requestBytes,
0,
"Request bytes should be greater than 0 after expiry"
);
Assert.greater(
result.responseBytes,
5,
"Response bytes should include hit data after expiry"
);
await BrowserTestUtils.removeTab(tab);
UrlClassifierTestUtils.cleanupTestV5Entry();
});