summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js410
1 files changed, 410 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js
new file mode 100644
index 0000000000..5b3a572ef1
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js
@@ -0,0 +1,410 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { TelemetryEnvironment } = ChromeUtils.importESModule(
+ "resource://gre/modules/TelemetryEnvironment.sys.mjs"
+);
+const { SearchTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/SearchTestUtils.sys.mjs"
+);
+const { TelemetryEnvironmentTesting } = ChromeUtils.importESModule(
+ "resource://testing-common/TelemetryEnvironmentTesting.sys.mjs"
+);
+
+SearchTestUtils.init(this);
+
+function promiseNextTick() {
+ return new Promise(resolve => executeSoon(resolve));
+}
+
+// The webserver hosting the addons.
+var gHttpServer = null;
+// The URL of the webserver root.
+var gHttpRoot = null;
+// The URL of the data directory, on the webserver.
+var gDataRoot = null;
+
+add_task(async function setup() {
+ TelemetryEnvironmentTesting.registerFakeSysInfo();
+ TelemetryEnvironmentTesting.spoofGfxAdapter();
+ do_get_profile();
+
+ // We need to ensure FOG is initialized, otherwise we will panic trying to get test values.
+ Services.fog.initializeFOG();
+
+ // The system add-on must be installed before AddonManager is started.
+ const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
+ do_get_file("system.xpi").copyTo(
+ distroDir,
+ "tel-system-xpi@tests.mozilla.org.xpi"
+ );
+ let system_addon = FileUtils.File(distroDir.path);
+ system_addon.append("tel-system-xpi@tests.mozilla.org.xpi");
+ system_addon.lastModifiedTime = SYSTEM_ADDON_INSTALL_DATE;
+ await loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
+
+ TelemetryEnvironmentTesting.init(gAppInfo);
+
+ // The test runs in a fresh profile so starting the AddonManager causes
+ // the addons database to be created (as does setting new theme).
+ // For test_addonsStartup below, we want to test a "warm" startup where
+ // there is already a database on disk. Simulate that here by just
+ // restarting the AddonManager.
+ await AddonTestUtils.promiseShutdownManager();
+ await AddonTestUtils.overrideBuiltIns({ system: [] });
+ AddonTestUtils.addonStartup.remove(true);
+ await AddonTestUtils.promiseStartupManager();
+
+ // Setup a webserver to serve Addons, etc.
+ gHttpServer = new HttpServer();
+ gHttpServer.start(-1);
+ let port = gHttpServer.identity.primaryPort;
+ gHttpRoot = "http://localhost:" + port + "/";
+ gDataRoot = gHttpRoot + "data/";
+ gHttpServer.registerDirectory("/data/", do_get_cwd());
+ registerCleanupFunction(() => gHttpServer.stop(() => {}));
+
+ // Create the attribution data file, so that settings.attribution will exist.
+ // The attribution functionality only exists in Firefox.
+ if (AppConstants.MOZ_BUILD_APP == "browser") {
+ TelemetryEnvironmentTesting.spoofAttributionData();
+ registerCleanupFunction(TelemetryEnvironmentTesting.cleanupAttributionData);
+ }
+
+ await TelemetryEnvironmentTesting.spoofProfileReset();
+ await TelemetryEnvironment.delayedInit();
+ await SearchTestUtils.useTestEngines("data", "search-extensions");
+
+ // Now continue with startup.
+ let initPromise = TelemetryEnvironment.onInitialized();
+ finishAddonManagerStartup();
+
+ // Fake the delayed startup event for intl data to load.
+ fakeIntlReady();
+
+ let environmentData = await initPromise;
+ TelemetryEnvironmentTesting.checkEnvironmentData(environmentData, {
+ isInitial: true,
+ });
+
+ TelemetryEnvironmentTesting.spoofPartnerInfo();
+ Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC);
+
+ environmentData = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(environmentData, {
+ assertProcessData: true,
+ });
+});
+
+async function checkDefaultSearch(privateOn, reInitSearchService) {
+ // Start off with separate default engine for private browsing turned off.
+ Preferences.set(
+ "browser.search.separatePrivateDefault.ui.enabled",
+ privateOn
+ );
+ Preferences.set("browser.search.separatePrivateDefault", privateOn);
+
+ let data;
+ if (privateOn) {
+ data = await TelemetryEnvironment.testCleanRestart().onInitialized();
+ } else {
+ data = TelemetryEnvironment.currentEnvironment;
+ }
+
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.ok(!("defaultSearchEngine" in data.settings));
+ Assert.ok(!("defaultSearchEngineData" in data.settings));
+ Assert.ok(!("defaultPrivateSearchEngine" in data.settings));
+ Assert.ok(!("defaultPrivateSearchEngineData" in data.settings));
+
+ // Load the engines definitions from a xpcshell data: that's needed so that
+ // the search provider reports an engine identifier.
+
+ // Initialize the search service.
+ if (reInitSearchService) {
+ Services.search.wrappedJSObject.reset();
+ }
+ await Services.search.init();
+ await promiseNextTick();
+
+ // Our default engine from the JAR file has an identifier. Check if it is correctly
+ // reported.
+ data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.equal(data.settings.defaultSearchEngine, "telemetrySearchIdentifier");
+ let expectedSearchEngineData = {
+ name: "telemetrySearchIdentifier",
+ loadPath: "[addon]telemetrySearchIdentifier@search.mozilla.org",
+ origin: "default",
+ submissionURL:
+ "https://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB?search=&sourceId=Mozilla-search",
+ };
+ Assert.deepEqual(
+ data.settings.defaultSearchEngineData,
+ expectedSearchEngineData
+ );
+ if (privateOn) {
+ Assert.equal(
+ data.settings.defaultPrivateSearchEngine,
+ "telemetrySearchIdentifier"
+ );
+ Assert.deepEqual(
+ data.settings.defaultPrivateSearchEngineData,
+ expectedSearchEngineData,
+ "Should have the correct data for the private search engine"
+ );
+ } else {
+ Assert.ok(
+ !("defaultPrivateSearchEngine" in data.settings),
+ "Should not have private name recorded as the pref for separate is off"
+ );
+ Assert.ok(
+ !("defaultPrivateSearchEngineData" in data.settings),
+ "Should not have private data recorded as the pref for separate is off"
+ );
+ }
+
+ // Add a new search engine (this will have no engine identifier).
+ const SEARCH_ENGINE_ID = privateOn
+ ? "telemetry_private"
+ : "telemetry_default";
+ const SEARCH_ENGINE_URL = `https://www.example.org/${
+ privateOn ? "private" : ""
+ }`;
+ await SearchTestUtils.installSearchExtension({
+ id: `${SEARCH_ENGINE_ID}@test.engine`,
+ name: SEARCH_ENGINE_ID,
+ search_url: SEARCH_ENGINE_URL,
+ });
+
+ // Register a new change listener and then wait for the search engine change to be notified.
+ let deferred = PromiseUtils.defer();
+ TelemetryEnvironment.registerChangeListener(
+ "testWatch_SearchDefault",
+ deferred.resolve
+ );
+ if (privateOn) {
+ // As we had no default and no search engines, the normal mode engine will
+ // assume the same as the added engine. To ensure the telemetry is different
+ // we enforce a different default here.
+ const engine = await Services.search.getEngineByName(
+ "telemetrySearchIdentifier"
+ );
+ engine.hidden = false;
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ await Services.search.setDefaultPrivate(
+ Services.search.getEngineByName(SEARCH_ENGINE_ID),
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ } else {
+ await Services.search.setDefault(
+ Services.search.getEngineByName(SEARCH_ENGINE_ID),
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ }
+ await deferred.promise;
+
+ data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+
+ const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID;
+ const EXPECTED_SEARCH_ENGINE_DATA = {
+ name: SEARCH_ENGINE_ID,
+ loadPath: `[addon]${SEARCH_ENGINE_ID}@test.engine`,
+ origin: "verified",
+ };
+ if (privateOn) {
+ Assert.equal(
+ data.settings.defaultSearchEngine,
+ "telemetrySearchIdentifier"
+ );
+ Assert.deepEqual(
+ data.settings.defaultSearchEngineData,
+ expectedSearchEngineData
+ );
+ Assert.equal(
+ data.settings.defaultPrivateSearchEngine,
+ EXPECTED_SEARCH_ENGINE
+ );
+ Assert.deepEqual(
+ data.settings.defaultPrivateSearchEngineData,
+ EXPECTED_SEARCH_ENGINE_DATA
+ );
+ } else {
+ Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
+ Assert.deepEqual(
+ data.settings.defaultSearchEngineData,
+ EXPECTED_SEARCH_ENGINE_DATA
+ );
+ }
+ TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
+}
+
+add_task(async function test_defaultSearchEngine() {
+ await checkDefaultSearch(false);
+
+ // Cleanly install an engine from an xml file, and check if origin is
+ // recorded as "verified".
+ let promise = new Promise(resolve => {
+ TelemetryEnvironment.registerChangeListener(
+ "testWatch_SearchDefault",
+ resolve
+ );
+ });
+ let engine = await new Promise((resolve, reject) => {
+ Services.obs.addObserver(function obs(obsSubject, obsTopic, obsData) {
+ try {
+ let searchEngine = obsSubject.QueryInterface(Ci.nsISearchEngine);
+ info("Observed " + obsData + " for " + searchEngine.name);
+ if (
+ obsData != "engine-added" ||
+ searchEngine.name != "engine-telemetry"
+ ) {
+ return;
+ }
+
+ Services.obs.removeObserver(obs, "browser-search-engine-modified");
+ resolve(searchEngine);
+ } catch (ex) {
+ reject(ex);
+ }
+ }, "browser-search-engine-modified");
+ Services.search.addOpenSearchEngine(gDataRoot + "/engine.xml", null);
+ });
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ await promise;
+ TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
+ let data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.deepEqual(data.settings.defaultSearchEngineData, {
+ name: "engine-telemetry",
+ loadPath: "[http]localhost/engine-telemetry.xml",
+ origin: "verified",
+ });
+
+ // Now break this engine's load path hash.
+ promise = new Promise(resolve => {
+ TelemetryEnvironment.registerChangeListener(
+ "testWatch_SearchDefault",
+ resolve
+ );
+ });
+ engine.wrappedJSObject.setAttr("loadPathHash", "broken");
+ Services.obs.notifyObservers(
+ null,
+ "browser-search-engine-modified",
+ "engine-default"
+ );
+ await promise;
+ TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
+ data = TelemetryEnvironment.currentEnvironment;
+ Assert.equal(data.settings.defaultSearchEngineData.origin, "invalid");
+ await Services.search.removeEngine(engine);
+
+ const SEARCH_ENGINE_ID = "telemetry_default";
+ const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID;
+ // Work around bug 1165341: Intentionally set the default engine.
+ await Services.search.setDefault(
+ Services.search.getEngineByName(SEARCH_ENGINE_ID),
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+
+ // Double-check the default for the next part of the test.
+ data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
+
+ // Define and reset the test preference.
+ const PREF_TEST = "toolkit.telemetry.test.pref1";
+ const PREFS_TO_WATCH = new Map([
+ [PREF_TEST, { what: TelemetryEnvironment.RECORD_PREF_STATE }],
+ ]);
+ Preferences.reset(PREF_TEST);
+
+ // Watch the test preference.
+ await TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
+ let deferred = PromiseUtils.defer();
+ TelemetryEnvironment.registerChangeListener(
+ "testSearchEngine_pref",
+ deferred.resolve
+ );
+ // Trigger an environment change.
+ Preferences.set(PREF_TEST, 1);
+ await deferred.promise;
+ TelemetryEnvironment.unregisterChangeListener("testSearchEngine_pref");
+
+ // Check that the search engine information is correctly retained when prefs change.
+ data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
+});
+
+add_task(async function test_defaultPrivateSearchEngine() {
+ await checkDefaultSearch(true, true);
+});
+
+add_task(async function test_defaultSearchEngine_paramsChanged() {
+ let extension = await SearchTestUtils.installSearchExtension(
+ {
+ name: "TestEngine",
+ search_url: "https://www.google.com/fake1",
+ },
+ { skipUnload: true }
+ );
+
+ let promise = new Promise(resolve => {
+ TelemetryEnvironment.registerChangeListener(
+ "testWatch_SearchDefault",
+ resolve
+ );
+ });
+ let engine = Services.search.getEngineByName("TestEngine");
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ await promise;
+
+ let data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.deepEqual(data.settings.defaultSearchEngineData, {
+ name: "TestEngine",
+ loadPath: "[addon]testengine@tests.mozilla.org",
+ origin: "verified",
+ submissionURL: "https://www.google.com/fake1?q=",
+ });
+
+ promise = new Promise(resolve => {
+ TelemetryEnvironment.registerChangeListener(
+ "testWatch_SearchDefault",
+ resolve
+ );
+ });
+
+ engine.wrappedJSObject.update({
+ manifest: SearchTestUtils.createEngineManifest({
+ name: "TestEngine",
+ version: "1.2",
+ search_url: "https://www.google.com/fake2",
+ }),
+ });
+
+ await promise;
+
+ data = TelemetryEnvironment.currentEnvironment;
+ TelemetryEnvironmentTesting.checkEnvironmentData(data);
+ Assert.deepEqual(data.settings.defaultSearchEngineData, {
+ name: "TestEngine",
+ loadPath: "[addon]testengine@tests.mozilla.org",
+ origin: "verified",
+ submissionURL: "https://www.google.com/fake2?q=",
+ });
+
+ await extension.unload();
+});