summaryrefslogtreecommitdiffstats
path: root/browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js')
-rw-r--r--browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js260
1 files changed, 260 insertions, 0 deletions
diff --git a/browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js b/browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js
new file mode 100644
index 0000000000..ea235406a4
--- /dev/null
+++ b/browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js
@@ -0,0 +1,260 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+const { TelemetryTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryTestUtils.sys.mjs"
+);
+
+AddonTestUtils.initMochitest(this);
+
+const TELEMETRY_EVENTS_FILTERS = {
+ category: "addonsSearchDetection",
+ method: "etld_change",
+};
+
+// The search-detection built-in add-on registers dynamic events.
+const TELEMETRY_TEST_UTILS_OPTIONS = { clear: true, process: "dynamic" };
+
+const REDIRECT_SJS =
+ "browser/browser/extensions/search-detection/tests/browser/redirect.sjs?q={searchTerms}";
+// This URL will redirect to `example.net`, which is different than
+// `*.example.com`. That will be the final URL of a redirect chain:
+// www.example.com -> example.net
+const SEARCH_URL_WWW = `https://www.example.com/${REDIRECT_SJS}`;
+// This URL will redirect to `www.example.com`, which will create a redirect
+// chain with two hops:
+// test2.example.com -> www.example.com -> example.net
+const SEARCH_URL_TEST2 = `https://test2.example.com/${REDIRECT_SJS}`;
+// This URL will redirect to `test2.example.com`, which will create a redirect
+// chain with three hops:
+// test1.example.com -> test2.example.com -> www.example.com -> example.net
+const SEARCH_URL_TEST1 = `https://test1.example.com/${REDIRECT_SJS}`;
+
+const TEST_SEARCH_ENGINE_ADDON_ID = "some@addon-id";
+const TEST_SEARCH_ENGINE_ADDON_VERSION = "4.5.6";
+
+const testServerSideRedirect = async ({
+ searchURL,
+ expectedEvents,
+ tabURL,
+}) => {
+ Services.telemetry.clearEvents();
+
+ const searchEngineName = "test search engine";
+ // Load a default search engine because the add-on we are testing here
+ // monitors the search engines.
+ const searchEngine = ExtensionTestUtils.loadExtension({
+ manifest: {
+ version: TEST_SEARCH_ENGINE_ADDON_VERSION,
+ browser_specific_settings: {
+ gecko: { id: TEST_SEARCH_ENGINE_ADDON_ID },
+ },
+ chrome_settings_overrides: {
+ search_provider: {
+ name: searchEngineName,
+ keyword: "test",
+ search_url: searchURL,
+ },
+ },
+ },
+ useAddonManager: "temporary",
+ });
+
+ await searchEngine.startup();
+ ok(
+ Services.search.getEngineByName(searchEngineName),
+ "test search engine registered"
+ );
+ await AddonTestUtils.waitForSearchProviderStartup(searchEngine);
+
+ // Simulate a search (with the test search engine) by navigating to it.
+ const url = tabURL || searchURL.replace("{searchTerms}", "some terms");
+ await BrowserTestUtils.withNewTab("about:blank", async browser => {
+ // Wait for the tab to be fully loaded.
+ let loaded = BrowserTestUtils.browserLoaded(browser);
+ BrowserTestUtils.loadURIString(browser, url);
+ await loaded;
+ });
+
+ await searchEngine.unload();
+ ok(
+ !Services.search.getEngineByName(searchEngineName),
+ "test search engine unregistered"
+ );
+
+ TelemetryTestUtils.assertEvents(
+ expectedEvents,
+ TELEMETRY_EVENTS_FILTERS,
+ TELEMETRY_TEST_UTILS_OPTIONS
+ );
+};
+
+add_task(function test_redirect_final() {
+ return testServerSideRedirect({
+ // www.example.com -> example.net
+ searchURL: SEARCH_URL_WWW,
+ expectedEvents: [
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: TEST_SEARCH_ENGINE_ADDON_ID,
+ addonVersion: TEST_SEARCH_ENGINE_ADDON_VERSION,
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ ],
+ });
+});
+
+add_task(function test_redirect_two_hops() {
+ return testServerSideRedirect({
+ // test2.example.com -> www.example.com -> example.net
+ searchURL: SEARCH_URL_TEST2,
+ expectedEvents: [
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: TEST_SEARCH_ENGINE_ADDON_ID,
+ addonVersion: TEST_SEARCH_ENGINE_ADDON_VERSION,
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ ],
+ });
+});
+
+add_task(function test_redirect_three_hops() {
+ return testServerSideRedirect({
+ // test1.example.com -> test2.example.com -> www.example.com -> example.net
+ searchURL: SEARCH_URL_TEST1,
+ expectedEvents: [
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: TEST_SEARCH_ENGINE_ADDON_ID,
+ addonVersion: TEST_SEARCH_ENGINE_ADDON_VERSION,
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ ],
+ });
+});
+
+add_task(function test_no_event_when_search_engine_not_used() {
+ return testServerSideRedirect({
+ // www.example.com -> example.net
+ searchURL: SEARCH_URL_WWW,
+ // We do not expect any events because the user is not using the search
+ // engine that was registered.
+ tabURL: "http://mochi.test:8888/search?q=foobar",
+ expectedEvents: [],
+ });
+});
+
+add_task(function test_redirect_chain_does_not_start_on_first_request() {
+ return testServerSideRedirect({
+ // www.example.com -> example.net
+ searchURL: SEARCH_URL_WWW,
+ // User first navigates to an URL that isn't monitored and will be
+ // redirected to another URL that is monitored.
+ tabURL: `http://mochi.test:8888/browser/browser/extensions/search-detection/tests/browser/redirect.sjs?q={searchTerms}`,
+ expectedEvents: [
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: TEST_SEARCH_ENGINE_ADDON_ID,
+ addonVersion: TEST_SEARCH_ENGINE_ADDON_VERSION,
+ // We expect this and not `mochi.test` because we do not monitor
+ // `mochi.test`, only `example.com`, which is coming from the search
+ // engine registered in the test setup.
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ ],
+ });
+});
+
+add_task(async function test_two_extensions_reported() {
+ Services.telemetry.clearEvents();
+
+ const searchEngines = [];
+ for (const [addonId, addonVersion, isDefault] of [
+ ["1-addon@guid", "1.2", false],
+ ["2-addon@guid", "3.4", true],
+ ]) {
+ const searchEngine = ExtensionTestUtils.loadExtension({
+ manifest: {
+ version: addonVersion,
+ browser_specific_settings: {
+ gecko: { id: addonId },
+ },
+ chrome_settings_overrides: {
+ search_provider: {
+ is_default: isDefault,
+ name: `test search engine - ${addonId}`,
+ keyword: "test",
+ search_url: `${SEARCH_URL_WWW}&id=${addonId}`,
+ },
+ },
+ },
+ useAddonManager: "temporary",
+ });
+
+ await searchEngine.startup();
+ await AddonTestUtils.waitForSearchProviderStartup(searchEngine);
+
+ searchEngines.push(searchEngine);
+ }
+
+ // Simulate a search by navigating to it.
+ const url = SEARCH_URL_WWW.replace("{searchTerms}", "some terms");
+ await BrowserTestUtils.withNewTab("about:blank", async browser => {
+ // Wait for the tab to be fully loaded.
+ let loaded = BrowserTestUtils.browserLoaded(browser);
+ BrowserTestUtils.loadURIString(browser, url);
+ await loaded;
+ });
+
+ await Promise.all(searchEngines.map(engine => engine.unload()));
+
+ TelemetryTestUtils.assertEvents(
+ [
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: "1-addon@guid",
+ addonVersion: "1.2",
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ {
+ object: "other",
+ value: "server",
+ extra: {
+ addonId: "2-addon@guid",
+ addonVersion: "3.4",
+ from: "example.com",
+ to: "example.net",
+ },
+ },
+ ],
+ TELEMETRY_EVENTS_FILTERS,
+ TELEMETRY_TEST_UTILS_OPTIONS
+ );
+});