diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment_search.js | 410 |
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(); +}); |