-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1736684 - Part 2: Add test coverage for the search-detection buil…
…t-in add-on (server side). r=rpl - `test_redirect_{final,two_hops,three_hops}` correspond to SSR #1 - `test_no_event_when_search_engine_not_used` corresponds to SSR #2 - `test_redirect_chain_does_not_start_on_first_request` corresponds to SSR #3 - `test_two_extensions_reported` corresponds to SSR #4 Differential Revision: https://phabricator.services.mozilla.com/D129176
- Loading branch information
1 parent
9aff821
commit 21c2aee
Showing
4 changed files
with
297 additions
and
3 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
browser/extensions/search-detection/tests/browser/browser.ini
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
[DEFAULT] | ||
support-files = | ||
redirect.sjs | ||
|
||
[browser_client_side_redirection.js] | ||
[browser_extension_loaded.js] | ||
[browser_server_side_redirection.js] |
5 changes: 2 additions & 3 deletions
5
browser/extensions/search-detection/tests/browser/browser_extension_loaded.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
260 changes: 260 additions & 0 deletions
260
browser/extensions/search-detection/tests/browser/browser_server_side_redirection.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
/* Any copyright is dedicated to the Public Domain. | ||
* http://creativecommons.org/publicdomain/zero/1.0/ */ | ||
|
||
"use strict"; | ||
|
||
const { AddonTestUtils } = ChromeUtils.import( | ||
"resource://testing-common/AddonTestUtils.jsm" | ||
); | ||
|
||
const { TelemetryTestUtils } = ChromeUtils.import( | ||
"resource://testing-common/TelemetryTestUtils.jsm" | ||
); | ||
|
||
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.loadURI(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.loadURI(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 | ||
); | ||
}); |
32 changes: 32 additions & 0 deletions
32
browser/extensions/search-detection/tests/browser/redirect.sjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const REDIRECT_SJS = | ||
"browser/browser/extensions/search-detection/tests/browser/redirect.sjs"; | ||
|
||
// This handler is used to create redirect chains with multiple sub-domains, | ||
// and the next hop is defined by the current `host`. | ||
function handleRequest(request, response) { | ||
let newLocation; | ||
|
||
// test1.example.com -> test2.example.com -> www.example.com -> example.net | ||
switch (request.host) { | ||
case "test1.example.com": | ||
newLocation = `https://test2.example.com/${REDIRECT_SJS}`; | ||
break; | ||
case "test2.example.com": | ||
newLocation = `https://www.example.com/${REDIRECT_SJS}`; | ||
break; | ||
case "www.example.com": | ||
newLocation = "https://example.net/"; | ||
break; | ||
// We redirect `mochi.test` to `www` in | ||
// `test_redirect_chain_does_not_start_on_first_request()`. | ||
case "mochi.test": | ||
newLocation = `https://www.example.com/${REDIRECT_SJS}`; | ||
break; | ||
default: | ||
// Redirect to a different website in case of unexpected events. | ||
newLocation = "https://mozilla.org/"; | ||
} | ||
|
||
response.setStatusLine(request.httpVersion, 302, "Found"); | ||
response.setHeader("Location", newLocation); | ||
} |