diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js | 1522 |
1 files changed, 0 insertions, 1522 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js deleted file mode 100644 index 2518a80ba..000000000 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js +++ /dev/null @@ -1,1522 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this); -Cu.import("resource://gre/modules/Preferences.jsm", this); -Cu.import("resource://gre/modules/PromiseUtils.jsm", this); -Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); -Cu.import("resource://testing-common/AddonManagerTesting.jsm"); -Cu.import("resource://testing-common/httpd.js"); -Cu.import("resource://testing-common/MockRegistrar.jsm", this); -Cu.import("resource://gre/modules/FileUtils.jsm"); - -// AttributionCode is only needed for Firefox -XPCOMUtils.defineLazyModuleGetter(this, "AttributionCode", - "resource:///modules/AttributionCode.jsm"); - -// Lazy load |LightweightThemeManager|, we won't be using it on Gonk. -XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", - "resource://gre/modules/LightweightThemeManager.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge", - "resource://gre/modules/ProfileAge.jsm"); - -// 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; - -const PLATFORM_VERSION = "1.9.2"; -const APP_VERSION = "1"; -const APP_ID = "xpcshell@tests.mozilla.org"; -const APP_NAME = "XPCShell"; - -const DISTRIBUTION_ID = "distributor-id"; -const DISTRIBUTION_VERSION = "4.5.6b"; -const DISTRIBUTOR_NAME = "Some Distributor"; -const DISTRIBUTOR_CHANNEL = "A Channel"; -const PARTNER_NAME = "test"; -const PARTNER_ID = "NicePartner-ID-3785"; -const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; - -const GFX_VENDOR_ID = "0xabcd"; -const GFX_DEVICE_ID = "0x1234"; - -// The profile reset date, in milliseconds (Today) -const PROFILE_RESET_DATE_MS = Date.now(); -// The profile creation date, in milliseconds (Yesterday). -const PROFILE_CREATION_DATE_MS = PROFILE_RESET_DATE_MS - MILLISECONDS_PER_DAY; - -const FLASH_PLUGIN_NAME = "Shockwave Flash"; -const FLASH_PLUGIN_DESC = "A mock flash plugin"; -const FLASH_PLUGIN_VERSION = "\u201c1.1.1.1\u201d"; -const PLUGIN_MIME_TYPE1 = "application/x-shockwave-flash"; -const PLUGIN_MIME_TYPE2 = "text/plain"; - -const PLUGIN2_NAME = "Quicktime"; -const PLUGIN2_DESC = "A mock Quicktime plugin"; -const PLUGIN2_VERSION = "2.3"; - -const PERSONA_ID = "3785"; -// Defined by LightweightThemeManager, it is appended to the PERSONA_ID. -const PERSONA_ID_SUFFIX = "@personas.mozilla.org"; -const PERSONA_NAME = "Test Theme"; -const PERSONA_DESCRIPTION = "A nice theme/persona description."; - -const PLUGIN_UPDATED_TOPIC = "plugins-list-updated"; - -// system add-ons are enabled at startup, so record date when the test starts -const SYSTEM_ADDON_INSTALL_DATE = Date.now(); - -// Valid attribution code to write so that settings.attribution can be tested. -const ATTRIBUTION_CODE = "source%3Dgoogle.com"; - -/** - * Used to mock plugin tags in our fake plugin host. - */ -function PluginTag(aName, aDescription, aVersion, aEnabled) { - this.name = aName; - this.description = aDescription; - this.version = aVersion; - this.disabled = !aEnabled; -} - -PluginTag.prototype = { - name: null, - description: null, - version: null, - filename: null, - fullpath: null, - disabled: false, - blocklisted: false, - clicktoplay: true, - - mimeTypes: [ PLUGIN_MIME_TYPE1, PLUGIN_MIME_TYPE2 ], - - getMimeTypes: function(count) { - count.value = this.mimeTypes.length; - return this.mimeTypes; - } -}; - -// A container for the plugins handled by the fake plugin host. -var gInstalledPlugins = [ - new PluginTag("Java", "A mock Java plugin", "1.0", false /* Disabled */), - new PluginTag(FLASH_PLUGIN_NAME, FLASH_PLUGIN_DESC, FLASH_PLUGIN_VERSION, true), -]; - -// A fake plugin host for testing plugin telemetry environment. -var PluginHost = { - getPluginTags: function(countRef) { - countRef.value = gInstalledPlugins.length; - return gInstalledPlugins; - }, - - QueryInterface: function(iid) { - if (iid.equals(Ci.nsIPluginHost) - || iid.equals(Ci.nsISupports)) - return this; - - throw Components.results.NS_ERROR_NO_INTERFACE; - } -} - -function registerFakePluginHost() { - MockRegistrar.register("@mozilla.org/plugin/host;1", PluginHost); -} - -var SysInfo = { - overrides: {}, - - getProperty(name) { - // Assert.ok(false, "Mock SysInfo: " + name + ", " + JSON.stringify(this.overrides)); - if (name in this.overrides) { - return this.overrides[name]; - } - try { - return this._genuine.getProperty(name); - } catch (ex) { - throw ex; - } - }, - - get(name) { - return this._genuine.get(name); - }, - - QueryInterface(iid) { - if (iid.equals(Ci.nsIPropertyBag2) - || iid.equals(Ci.nsISupports)) - return this; - - throw Cr.NS_ERROR_NO_INTERFACE; - } -}; - -function registerFakeSysInfo() { - MockRegistrar.register("@mozilla.org/system-info;1", SysInfo); -} - -function MockAddonWrapper(aAddon) { - this.addon = aAddon; -} -MockAddonWrapper.prototype = { - get id() { - return this.addon.id; - }, - - get type() { - return "service"; - }, - - get appDisabled() { - return false; - }, - - get isCompatible() { - return true; - }, - - get isPlatformCompatible() { - return true; - }, - - get scope() { - return AddonManager.SCOPE_PROFILE; - }, - - get foreignInstall() { - return false; - }, - - get providesUpdatesSecurely() { - return true; - }, - - get blocklistState() { - return 0; // Not blocked. - }, - - get pendingOperations() { - return AddonManager.PENDING_NONE; - }, - - get permissions() { - return AddonManager.PERM_CAN_UNINSTALL | AddonManager.PERM_CAN_DISABLE; - }, - - get isActive() { - return true; - }, - - get name() { - return this.addon.name; - }, - - get version() { - return this.addon.version; - }, - - get creator() { - return new AddonManagerPrivate.AddonAuthor(this.addon.author); - }, - - get userDisabled() { - return this.appDisabled; - }, -}; - -function createMockAddonProvider(aName) { - let mockProvider = { - _addons: [], - - get name() { - return aName; - }, - - addAddon: function(aAddon) { - this._addons.push(aAddon); - AddonManagerPrivate.callAddonListeners("onInstalled", new MockAddonWrapper(aAddon)); - }, - - getAddonsByTypes: function (aTypes, aCallback) { - aCallback(this._addons.map(a => new MockAddonWrapper(a))); - }, - - shutdown() { - return Promise.resolve(); - }, - }; - - return mockProvider; -} - -/** - * Used to spoof the Persona Id. - */ -function spoofTheme(aId, aName, aDesc) { - return { - id: aId, - name: aName, - description: aDesc, - headerURL: "http://lwttest.invalid/a.png", - footerURL: "http://lwttest.invalid/b.png", - textcolor: Math.random().toString(), - accentcolor: Math.random().toString() - }; -} - -function spoofGfxAdapter() { - try { - let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug); - gfxInfo.spoofVendorID(GFX_VENDOR_ID); - gfxInfo.spoofDeviceID(GFX_DEVICE_ID); - } catch (x) { - // If we can't test gfxInfo, that's fine, we'll note it later. - } -} - -function spoofProfileReset() { - let profileAccessor = new ProfileAge(); - - return profileAccessor.writeTimes({ - created: PROFILE_CREATION_DATE_MS, - reset: PROFILE_RESET_DATE_MS - }); -} - -function spoofPartnerInfo() { - let prefsToSpoof = {}; - prefsToSpoof["distribution.id"] = DISTRIBUTION_ID; - prefsToSpoof["distribution.version"] = DISTRIBUTION_VERSION; - prefsToSpoof["app.distributor"] = DISTRIBUTOR_NAME; - prefsToSpoof["app.distributor.channel"] = DISTRIBUTOR_CHANNEL; - prefsToSpoof["app.partner.test"] = PARTNER_NAME; - prefsToSpoof["mozilla.partner.id"] = PARTNER_ID; - - // Spoof the preferences. - for (let pref in prefsToSpoof) { - Preferences.set(pref, prefsToSpoof[pref]); - } -} - -function getAttributionFile() { - let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile); - file.append("mozilla"); - file.append(AppConstants.MOZ_APP_NAME); - file.append("postSigningData"); - return file; -} - -function spoofAttributionData() { - if (gIsWindows) { - AttributionCode._clearCache(); - let stream = Cc["@mozilla.org/network/file-output-stream;1"]. - createInstance(Ci.nsIFileOutputStream); - stream.init(getAttributionFile(), -1, -1, 0); - stream.write(ATTRIBUTION_CODE, ATTRIBUTION_CODE.length); - } -} - -function cleanupAttributionData() { - if (gIsWindows) { - getAttributionFile().remove(false); - AttributionCode._clearCache(); - } -} - -/** - * Check that a value is a string and not empty. - * - * @param aValue The variable to check. - * @return True if |aValue| has type "string" and is not empty, False otherwise. - */ -function checkString(aValue) { - return (typeof aValue == "string") && (aValue != ""); -} - -/** - * If value is non-null, check if it's a valid string. - * - * @param aValue The variable to check. - * @return True if it's null or a valid string, false if it's non-null and an invalid - * string. - */ -function checkNullOrString(aValue) { - if (aValue) { - return checkString(aValue); - } else if (aValue === null) { - return true; - } - - return false; -} - -/** - * If value is non-null, check if it's a boolean. - * - * @param aValue The variable to check. - * @return True if it's null or a valid boolean, false if it's non-null and an invalid - * boolean. - */ -function checkNullOrBool(aValue) { - return aValue === null || (typeof aValue == "boolean"); -} - -function checkBuildSection(data) { - const expectedInfo = { - applicationId: APP_ID, - applicationName: APP_NAME, - buildId: gAppInfo.appBuildID, - version: APP_VERSION, - vendor: "Mozilla", - platformVersion: PLATFORM_VERSION, - xpcomAbi: "noarch-spidermonkey", - }; - - Assert.ok("build" in data, "There must be a build section in Environment."); - - for (let f in expectedInfo) { - Assert.ok(checkString(data.build[f]), f + " must be a valid string."); - Assert.equal(data.build[f], expectedInfo[f], f + " must have the correct value."); - } - - // Make sure architecture is in the environment. - Assert.ok(checkString(data.build.architecture)); - - if (gIsMac) { - let macUtils = Cc["@mozilla.org/xpcom/mac-utils;1"].getService(Ci.nsIMacUtils); - if (macUtils && macUtils.isUniversalBinary) { - Assert.ok(checkString(data.build.architecturesInBinary)); - } - } -} - -function checkSettingsSection(data) { - const EXPECTED_FIELDS_TYPES = { - blocklistEnabled: "boolean", - e10sEnabled: "boolean", - e10sCohort: "string", - telemetryEnabled: "boolean", - locale: "string", - update: "object", - userPrefs: "object", - }; - - Assert.ok("settings" in data, "There must be a settings section in Environment."); - - for (let f in EXPECTED_FIELDS_TYPES) { - Assert.equal(typeof data.settings[f], EXPECTED_FIELDS_TYPES[f], - f + " must have the correct type."); - } - - // Check "addonCompatibilityCheckEnabled" separately, as it is not available - // on Gonk. - if (gIsGonk) { - Assert.ok(!("addonCompatibilityCheckEnabled" in data.settings), "Must not be available on Gonk."); - } else { - Assert.equal(data.settings.addonCompatibilityCheckEnabled, AddonManager.checkCompatibility); - } - - // Check "isDefaultBrowser" separately, as it is not available on Android an can either be - // null or boolean on other platforms. - if (gIsAndroid) { - Assert.ok(!("isDefaultBrowser" in data.settings), "Must not be available on Android."); - } else { - Assert.ok(checkNullOrBool(data.settings.isDefaultBrowser)); - } - - // Check "channel" separately, as it can either be null or string. - let update = data.settings.update; - Assert.ok(checkNullOrString(update.channel)); - Assert.equal(typeof update.enabled, "boolean"); - Assert.equal(typeof update.autoDownload, "boolean"); - - // Check "defaultSearchEngine" separately, as it can either be undefined or string. - if ("defaultSearchEngine" in data.settings) { - checkString(data.settings.defaultSearchEngine); - Assert.equal(typeof data.settings.defaultSearchEngineData, "object"); - } - - if ("attribution" in data.settings) { - Assert.equal(typeof data.settings.attribution, "object"); - Assert.equal(data.settings.attribution.source, "google.com"); - } -} - -function checkProfileSection(data) { - Assert.ok("profile" in data, "There must be a profile section in Environment."); - Assert.equal(data.profile.creationDate, truncateToDays(PROFILE_CREATION_DATE_MS)); - Assert.equal(data.profile.resetDate, truncateToDays(PROFILE_RESET_DATE_MS)); -} - -function checkPartnerSection(data, isInitial) { - const EXPECTED_FIELDS = { - distributionId: DISTRIBUTION_ID, - distributionVersion: DISTRIBUTION_VERSION, - partnerId: PARTNER_ID, - distributor: DISTRIBUTOR_NAME, - distributorChannel: DISTRIBUTOR_CHANNEL, - }; - - Assert.ok("partner" in data, "There must be a partner section in Environment."); - - for (let f in EXPECTED_FIELDS) { - let expected = isInitial ? null : EXPECTED_FIELDS[f]; - Assert.strictEqual(data.partner[f], expected, f + " must have the correct value."); - } - - // Check that "partnerNames" exists and contains the correct element. - Assert.ok(Array.isArray(data.partner.partnerNames)); - if (isInitial) { - Assert.equal(data.partner.partnerNames.length, 0); - } else { - Assert.ok(data.partner.partnerNames.includes(PARTNER_NAME)); - } -} - -function checkGfxAdapter(data) { - const EXPECTED_ADAPTER_FIELDS_TYPES = { - description: "string", - vendorID: "string", - deviceID: "string", - subsysID: "string", - RAM: "number", - driver: "string", - driverVersion: "string", - driverDate: "string", - GPUActive: "boolean", - }; - - for (let f in EXPECTED_ADAPTER_FIELDS_TYPES) { - Assert.ok(f in data, f + " must be available."); - - if (data[f]) { - // Since we have a non-null value, check if it has the correct type. - Assert.equal(typeof data[f], EXPECTED_ADAPTER_FIELDS_TYPES[f], - f + " must have the correct type."); - } - } -} - -function checkSystemSection(data) { - const EXPECTED_FIELDS = [ "memoryMB", "cpu", "os", "hdd", "gfx" ]; - const EXPECTED_HDD_FIELDS = [ "profile", "binary", "system" ]; - - Assert.ok("system" in data, "There must be a system section in Environment."); - - // Make sure we have all the top level sections and fields. - for (let f of EXPECTED_FIELDS) { - Assert.ok(f in data.system, f + " must be available."); - } - - Assert.ok(Number.isFinite(data.system.memoryMB), "MemoryMB must be a number."); - - if (gIsWindows || gIsMac || gIsLinux) { - let EXTRA_CPU_FIELDS = ["cores", "model", "family", "stepping", - "l2cacheKB", "l3cacheKB", "speedMHz", "vendor"]; - - for (let f of EXTRA_CPU_FIELDS) { - // Note this is testing TelemetryEnvironment.js only, not that the - // values are valid - null is the fallback. - Assert.ok(f in data.system.cpu, f + " must be available under cpu."); - } - - if (gIsWindows) { - Assert.equal(typeof data.system.isWow64, "boolean", - "isWow64 must be available on Windows and have the correct type."); - Assert.ok("virtualMaxMB" in data.system, "virtualMaxMB must be available."); - Assert.ok(Number.isFinite(data.system.virtualMaxMB), - "virtualMaxMB must be a number."); - } - - // We insist these are available - for (let f of ["cores"]) { - Assert.ok(!(f in data.system.cpu) || - Number.isFinite(data.system.cpu[f]), - f + " must be a number if non null."); - } - - // These should be numbers if they are not null - for (let f of ["model", "family", "stepping", "l2cacheKB", - "l3cacheKB", "speedMHz"]) { - Assert.ok(!(f in data.system.cpu) || - data.system.cpu[f] === null || - Number.isFinite(data.system.cpu[f]), - f + " must be a number if non null."); - } - } - - let cpuData = data.system.cpu; - Assert.ok(Number.isFinite(cpuData.count), "CPU count must be a number."); - Assert.ok(Array.isArray(cpuData.extensions), "CPU extensions must be available."); - - // Device data is only available on Android or Gonk. - if (gIsAndroid || gIsGonk) { - let deviceData = data.system.device; - Assert.ok(checkNullOrString(deviceData.model)); - Assert.ok(checkNullOrString(deviceData.manufacturer)); - Assert.ok(checkNullOrString(deviceData.hardware)); - Assert.ok(checkNullOrBool(deviceData.isTablet)); - } - - let osData = data.system.os; - Assert.ok(checkNullOrString(osData.name)); - Assert.ok(checkNullOrString(osData.version)); - Assert.ok(checkNullOrString(osData.locale)); - - // Service pack is only available on Windows. - if (gIsWindows) { - Assert.ok(Number.isFinite(osData["servicePackMajor"]), - "ServicePackMajor must be a number."); - Assert.ok(Number.isFinite(osData["servicePackMinor"]), - "ServicePackMinor must be a number."); - if ("windowsBuildNumber" in osData) { - // This might not be available on all Windows platforms. - Assert.ok(Number.isFinite(osData["windowsBuildNumber"]), - "windowsBuildNumber must be a number."); - } - if ("windowsUBR" in osData) { - // This might not be available on all Windows platforms. - Assert.ok((osData["windowsUBR"] === null) || Number.isFinite(osData["windowsUBR"]), - "windowsUBR must be null or a number."); - } - } else if (gIsAndroid || gIsGonk) { - Assert.ok(checkNullOrString(osData.kernelVersion)); - } - - let check = gIsWindows ? checkString : checkNullOrString; - for (let disk of EXPECTED_HDD_FIELDS) { - Assert.ok(check(data.system.hdd[disk].model)); - Assert.ok(check(data.system.hdd[disk].revision)); - } - - let gfxData = data.system.gfx; - Assert.ok("D2DEnabled" in gfxData); - Assert.ok("DWriteEnabled" in gfxData); - // DWriteVersion is disabled due to main thread jank and will be enabled - // again as part of bug 1154500. - // Assert.ok("DWriteVersion" in gfxData); - if (gIsWindows) { - Assert.equal(typeof gfxData.D2DEnabled, "boolean"); - Assert.equal(typeof gfxData.DWriteEnabled, "boolean"); - // As above, will be enabled again as part of bug 1154500. - // Assert.ok(checkString(gfxData.DWriteVersion)); - } - - Assert.ok("adapters" in gfxData); - Assert.ok(gfxData.adapters.length > 0, "There must be at least one GFX adapter."); - for (let adapter of gfxData.adapters) { - checkGfxAdapter(adapter); - } - Assert.equal(typeof gfxData.adapters[0].GPUActive, "boolean"); - Assert.ok(gfxData.adapters[0].GPUActive, "The first GFX adapter must be active."); - - Assert.ok(Array.isArray(gfxData.monitors)); - if (gIsWindows || gIsMac) { - Assert.ok(gfxData.monitors.length >= 1, "There is at least one monitor."); - Assert.equal(typeof gfxData.monitors[0].screenWidth, "number"); - Assert.equal(typeof gfxData.monitors[0].screenHeight, "number"); - if (gIsWindows) { - Assert.equal(typeof gfxData.monitors[0].refreshRate, "number"); - Assert.equal(typeof gfxData.monitors[0].pseudoDisplay, "boolean"); - } - if (gIsMac) { - Assert.equal(typeof gfxData.monitors[0].scale, "number"); - } - } - - Assert.equal(typeof gfxData.features, "object"); - Assert.equal(typeof gfxData.features.compositor, "string"); - - try { - // If we've not got nsIGfxInfoDebug, then this will throw and stop us doing - // this test. - let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug); - - if (gIsWindows || gIsMac) { - Assert.equal(GFX_VENDOR_ID, gfxData.adapters[0].vendorID); - Assert.equal(GFX_DEVICE_ID, gfxData.adapters[0].deviceID); - } - - let features = gfxInfo.getFeatures(); - Assert.equal(features.compositor, gfxData.features.compositor); - Assert.equal(features.opengl, gfxData.features.opengl); - Assert.equal(features.webgl, gfxData.features.webgl); - } - catch (e) {} -} - -function checkActiveAddon(data) { - let signedState = mozinfo.addon_signing ? "number" : "undefined"; - // system add-ons have an undefined signState - if (data.isSystem) - signedState = "undefined"; - - const EXPECTED_ADDON_FIELDS_TYPES = { - blocklisted: "boolean", - name: "string", - userDisabled: "boolean", - appDisabled: "boolean", - version: "string", - scope: "number", - type: "string", - foreignInstall: "boolean", - hasBinaryComponents: "boolean", - installDay: "number", - updateDay: "number", - signedState: signedState, - isSystem: "boolean", - }; - - for (let f in EXPECTED_ADDON_FIELDS_TYPES) { - Assert.ok(f in data, f + " must be available."); - Assert.equal(typeof data[f], EXPECTED_ADDON_FIELDS_TYPES[f], - f + " must have the correct type."); - } - - // We check "description" separately, as it can be null. - Assert.ok(checkNullOrString(data.description)); -} - -function checkPlugin(data) { - const EXPECTED_PLUGIN_FIELDS_TYPES = { - name: "string", - version: "string", - description: "string", - blocklisted: "boolean", - disabled: "boolean", - clicktoplay: "boolean", - updateDay: "number", - }; - - for (let f in EXPECTED_PLUGIN_FIELDS_TYPES) { - Assert.ok(f in data, f + " must be available."); - Assert.equal(typeof data[f], EXPECTED_PLUGIN_FIELDS_TYPES[f], - f + " must have the correct type."); - } - - Assert.ok(Array.isArray(data.mimeTypes)); - for (let type of data.mimeTypes) { - Assert.ok(checkString(type)); - } -} - -function checkTheme(data) { - // "hasBinaryComponents" is not available when testing. - const EXPECTED_THEME_FIELDS_TYPES = { - id: "string", - blocklisted: "boolean", - name: "string", - userDisabled: "boolean", - appDisabled: "boolean", - version: "string", - scope: "number", - foreignInstall: "boolean", - installDay: "number", - updateDay: "number", - }; - - for (let f in EXPECTED_THEME_FIELDS_TYPES) { - Assert.ok(f in data, f + " must be available."); - Assert.equal(typeof data[f], EXPECTED_THEME_FIELDS_TYPES[f], - f + " must have the correct type."); - } - - // We check "description" separately, as it can be null. - Assert.ok(checkNullOrString(data.description)); -} - -function checkActiveGMPlugin(data) { - // GMP plugin version defaults to null until GMPDownloader runs to update it. - if (data.version) { - Assert.equal(typeof data.version, "string"); - } - Assert.equal(typeof data.userDisabled, "boolean"); - Assert.equal(typeof data.applyBackgroundUpdates, "number"); -} - -function checkAddonsSection(data, expectBrokenAddons) { - const EXPECTED_FIELDS = [ - "activeAddons", "theme", "activePlugins", "activeGMPlugins", "activeExperiment", - "persona", - ]; - - Assert.ok("addons" in data, "There must be an addons section in Environment."); - for (let f of EXPECTED_FIELDS) { - Assert.ok(f in data.addons, f + " must be available."); - } - - // Check the active addons, if available. - if (!expectBrokenAddons) { - let activeAddons = data.addons.activeAddons; - for (let addon in activeAddons) { - checkActiveAddon(activeAddons[addon]); - } - } - - // Check "theme" structure. - if (Object.keys(data.addons.theme).length !== 0) { - checkTheme(data.addons.theme); - } - - // Check the active plugins. - Assert.ok(Array.isArray(data.addons.activePlugins)); - for (let plugin of data.addons.activePlugins) { - checkPlugin(plugin); - } - - // Check active GMPlugins - let activeGMPlugins = data.addons.activeGMPlugins; - for (let gmPlugin in activeGMPlugins) { - checkActiveGMPlugin(activeGMPlugins[gmPlugin]); - } - - // Check the active Experiment - let experiment = data.addons.activeExperiment; - if (Object.keys(experiment).length !== 0) { - Assert.ok(checkString(experiment.id)); - Assert.ok(checkString(experiment.branch)); - } - - // Check persona - Assert.ok(checkNullOrString(data.addons.persona)); -} - -function checkEnvironmentData(data, isInitial = false, expectBrokenAddons = false) { - checkBuildSection(data); - checkSettingsSection(data); - checkProfileSection(data); - checkPartnerSection(data, isInitial); - checkSystemSection(data); - checkAddonsSection(data, expectBrokenAddons); -} - -add_task(function* setup() { - // Load a custom manifest to provide search engine loading from JAR files. - do_load_manifest("chrome.manifest"); - registerFakeSysInfo(); - spoofGfxAdapter(); - do_get_profile(); - - // 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; - loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION); - - // Spoof the persona ID, but not on Gonk. - if (!gIsGonk) { - LightweightThemeManager.currentTheme = - spoofTheme(PERSONA_ID, PERSONA_NAME, PERSONA_DESCRIPTION); - } - // Register a fake plugin host for consistent flash version data. - registerFakePluginHost(); - - // Setup a webserver to serve Addons, Plugins, 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()); - do_register_cleanup(() => 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") { - spoofAttributionData(); - do_register_cleanup(cleanupAttributionData); - } - - yield spoofProfileReset(); - TelemetryEnvironment.delayedInit(); -}); - -add_task(function* test_checkEnvironment() { - let environmentData = yield TelemetryEnvironment.onInitialized(); - checkEnvironmentData(environmentData, true); - - spoofPartnerInfo(); - Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null); - - environmentData = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(environmentData); -}); - -add_task(function* test_prefWatchPolicies() { - const PREF_TEST_1 = "toolkit.telemetry.test.pref_new"; - const PREF_TEST_2 = "toolkit.telemetry.test.pref1"; - const PREF_TEST_3 = "toolkit.telemetry.test.pref2"; - const PREF_TEST_4 = "toolkit.telemetry.test.pref_old"; - const PREF_TEST_5 = "toolkit.telemetry.test.requiresRestart"; - - const expectedValue = "some-test-value"; - const unexpectedValue = "unexpected-test-value"; - - const PREFS_TO_WATCH = new Map([ - [PREF_TEST_1, {what: TelemetryEnvironment.RECORD_PREF_VALUE}], - [PREF_TEST_2, {what: TelemetryEnvironment.RECORD_PREF_STATE}], - [PREF_TEST_3, {what: TelemetryEnvironment.RECORD_PREF_STATE}], - [PREF_TEST_4, {what: TelemetryEnvironment.RECORD_PREF_VALUE}], - [PREF_TEST_5, {what: TelemetryEnvironment.RECORD_PREF_VALUE, requiresRestart: true}], - ]); - - Preferences.set(PREF_TEST_4, expectedValue); - Preferences.set(PREF_TEST_5, expectedValue); - - // Set the Environment preferences to watch. - TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH); - let deferred = PromiseUtils.defer(); - - // Check that the pref values are missing or present as expected - Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_1], undefined); - Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_4], expectedValue); - Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_5], expectedValue); - - TelemetryEnvironment.registerChangeListener("testWatchPrefs", - (reason, data) => deferred.resolve(data)); - let oldEnvironmentData = TelemetryEnvironment.currentEnvironment; - - // Trigger a change in the watched preferences. - Preferences.set(PREF_TEST_1, expectedValue); - Preferences.set(PREF_TEST_2, false); - Preferences.set(PREF_TEST_5, unexpectedValue); - let eventEnvironmentData = yield deferred.promise; - - // Unregister the listener. - TelemetryEnvironment.unregisterChangeListener("testWatchPrefs"); - - // Check environment contains the correct data. - Assert.deepEqual(oldEnvironmentData, eventEnvironmentData); - let userPrefs = TelemetryEnvironment.currentEnvironment.settings.userPrefs; - - Assert.equal(userPrefs[PREF_TEST_1], expectedValue, - "Environment contains the correct preference value."); - Assert.equal(userPrefs[PREF_TEST_2], "<user-set>", - "Report that the pref was user set but the value is not shown."); - Assert.ok(!(PREF_TEST_3 in userPrefs), - "Do not report if preference not user set."); - Assert.equal(userPrefs[PREF_TEST_5], expectedValue, - "The pref value in the environment data should still be the same"); -}); - -add_task(function* test_prefWatch_prefReset() { - const PREF_TEST = "toolkit.telemetry.test.pref1"; - const PREFS_TO_WATCH = new Map([ - [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}], - ]); - - // Set the preference to a non-default value. - Preferences.set(PREF_TEST, false); - - // Set the Environment preferences to watch. - TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH); - let deferred = PromiseUtils.defer(); - TelemetryEnvironment.registerChangeListener("testWatchPrefs_reset", deferred.resolve); - - Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST], "<user-set>"); - - // Trigger a change in the watched preferences. - Preferences.reset(PREF_TEST); - yield deferred.promise; - - Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST], undefined); - - // Unregister the listener. - TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_reset"); -}); - -add_task(function* test_addonsWatch_InterestingChange() { - const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi"; - const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org"; - // We only expect a single notification for each install, uninstall, enable, disable. - const EXPECTED_NOTIFICATIONS = 4; - - let receivedNotifications = 0; - - let registerCheckpointPromise = (aExpected) => { - return new Promise(resolve => TelemetryEnvironment.registerChangeListener( - "testWatchAddons_Changes" + aExpected, (reason, data) => { - Assert.equal(reason, "addons-changed"); - receivedNotifications++; - resolve(); - })); - }; - - let assertCheckpoint = (aExpected) => { - Assert.equal(receivedNotifications, aExpected); - TelemetryEnvironment.unregisterChangeListener("testWatchAddons_Changes" + aExpected); - }; - - // Test for receiving one notification after each change. - let checkpointPromise = registerCheckpointPromise(1); - yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); - yield checkpointPromise; - assertCheckpoint(1); - Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons); - - checkpointPromise = registerCheckpointPromise(2); - let addon = yield AddonManagerTesting.getAddonById(ADDON_ID); - addon.userDisabled = true; - yield checkpointPromise; - assertCheckpoint(2); - Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons)); - - checkpointPromise = registerCheckpointPromise(3); - addon.userDisabled = false; - yield checkpointPromise; - assertCheckpoint(3); - Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons); - - checkpointPromise = registerCheckpointPromise(4); - yield AddonManagerTesting.uninstallAddonByID(ADDON_ID); - yield checkpointPromise; - assertCheckpoint(4); - Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons)); - - Assert.equal(receivedNotifications, EXPECTED_NOTIFICATIONS, - "We must only receive the notifications we expect."); -}); - -add_task(function* test_pluginsWatch_Add() { - if (gIsAndroid) { - Assert.ok(true, "Skipping: there is no Plugin Manager on Android."); - return; - } - - Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 1); - - let newPlugin = new PluginTag(PLUGIN2_NAME, PLUGIN2_DESC, PLUGIN2_VERSION, true); - gInstalledPlugins.push(newPlugin); - - let deferred = PromiseUtils.defer(); - let receivedNotifications = 0; - let callback = (reason, data) => { - receivedNotifications++; - Assert.equal(reason, "addons-changed"); - deferred.resolve(); - }; - TelemetryEnvironment.registerChangeListener("testWatchPlugins_Add", callback); - - Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null); - yield deferred.promise; - - Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 2); - - TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Add"); - - Assert.equal(receivedNotifications, 1, "We must only receive one notification."); -}); - -add_task(function* test_pluginsWatch_Remove() { - if (gIsAndroid) { - Assert.ok(true, "Skipping: there is no Plugin Manager on Android."); - return; - } - - // Find the test plugin. - let plugin = gInstalledPlugins.find(p => (p.name == PLUGIN2_NAME)); - Assert.ok(plugin, "The test plugin must exist."); - - // Remove it from the PluginHost. - gInstalledPlugins = gInstalledPlugins.filter(p => p != plugin); - - let deferred = PromiseUtils.defer(); - let receivedNotifications = 0; - let callback = () => { - receivedNotifications++; - deferred.resolve(); - }; - TelemetryEnvironment.registerChangeListener("testWatchPlugins_Remove", callback); - - Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null); - yield deferred.promise; - - TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Remove"); - - Assert.equal(receivedNotifications, 1, "We must only receive one notification."); -}); - -add_task(function* test_addonsWatch_NotInterestingChange() { - // We are not interested to dictionary addons changes. - const DICTIONARY_ADDON_INSTALL_URL = gDataRoot + "dictionary.xpi"; - const INTERESTING_ADDON_INSTALL_URL = gDataRoot + "restartless.xpi"; - - let receivedNotification = false; - let deferred = PromiseUtils.defer(); - TelemetryEnvironment.registerChangeListener("testNotInteresting", - () => { - Assert.ok(!receivedNotification, "Should not receive multiple notifications"); - receivedNotification = true; - deferred.resolve(); - }); - - yield AddonManagerTesting.installXPIFromURL(DICTIONARY_ADDON_INSTALL_URL); - yield AddonManagerTesting.installXPIFromURL(INTERESTING_ADDON_INSTALL_URL); - - yield deferred.promise; - Assert.ok(!("telemetry-dictionary@tests.mozilla.org" in - TelemetryEnvironment.currentEnvironment.addons.activeAddons), - "Dictionaries should not appear in active addons."); - - TelemetryEnvironment.unregisterChangeListener("testNotInteresting"); -}); - -add_task(function* test_addonsAndPlugins() { - const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi"; - const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org"; - const ADDON_INSTALL_DATE = truncateToDays(Date.now()); - const EXPECTED_ADDON_DATA = { - blocklisted: false, - description: "A restartless addon which gets enabled without a reboot.", - name: "XPI Telemetry Restartless Test", - userDisabled: false, - appDisabled: false, - version: "1.0", - scope: 1, - type: "extension", - foreignInstall: false, - hasBinaryComponents: false, - installDay: ADDON_INSTALL_DATE, - updateDay: ADDON_INSTALL_DATE, - signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED, - isSystem: false, - }; - const SYSTEM_ADDON_ID = "tel-system-xpi@tests.mozilla.org"; - const EXPECTED_SYSTEM_ADDON_DATA = { - blocklisted: false, - description: "A system addon which is shipped with Firefox.", - name: "XPI Telemetry System Add-on Test", - userDisabled: false, - appDisabled: false, - version: "1.0", - scope: 1, - type: "extension", - foreignInstall: false, - hasBinaryComponents: false, - installDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE), - updateDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE), - signedState: undefined, - isSystem: true, - }; - - const EXPECTED_PLUGIN_DATA = { - name: FLASH_PLUGIN_NAME, - version: FLASH_PLUGIN_VERSION, - description: FLASH_PLUGIN_DESC, - blocklisted: false, - disabled: false, - clicktoplay: true, - }; - - // Install an addon so we have some data. - yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); - - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - // Check addon data. - Assert.ok(ADDON_ID in data.addons.activeAddons, "We must have one active addon."); - let targetAddon = data.addons.activeAddons[ADDON_ID]; - for (let f in EXPECTED_ADDON_DATA) { - Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value."); - } - - // Check system add-on data. - Assert.ok(SYSTEM_ADDON_ID in data.addons.activeAddons, "We must have one active system addon."); - let targetSystemAddon = data.addons.activeAddons[SYSTEM_ADDON_ID]; - for (let f in EXPECTED_SYSTEM_ADDON_DATA) { - Assert.equal(targetSystemAddon[f], EXPECTED_SYSTEM_ADDON_DATA[f], f + " must have the correct value."); - } - - // Check theme data. - let theme = data.addons.theme; - Assert.equal(theme.id, (PERSONA_ID + PERSONA_ID_SUFFIX)); - Assert.equal(theme.name, PERSONA_NAME); - Assert.equal(theme.description, PERSONA_DESCRIPTION); - - // Check plugin data. - Assert.equal(data.addons.activePlugins.length, 1, "We must have only one active plugin."); - let targetPlugin = data.addons.activePlugins[0]; - for (let f in EXPECTED_PLUGIN_DATA) { - Assert.equal(targetPlugin[f], EXPECTED_PLUGIN_DATA[f], f + " must have the correct value."); - } - - // Check plugin mime types. - Assert.ok(targetPlugin.mimeTypes.find(m => m == PLUGIN_MIME_TYPE1)); - Assert.ok(targetPlugin.mimeTypes.find(m => m == PLUGIN_MIME_TYPE2)); - Assert.ok(!targetPlugin.mimeTypes.find(m => m == "Not There.")); - - let personaId = (gIsGonk) ? null : PERSONA_ID; - Assert.equal(data.addons.persona, personaId, "The correct Persona Id must be reported."); - - // Uninstall the addon. - yield AddonManagerTesting.uninstallAddonByID(ADDON_ID); -}); - -add_task(function* test_signedAddon() { - const ADDON_INSTALL_URL = gDataRoot + "signed.xpi"; - const ADDON_ID = "tel-signed-xpi@tests.mozilla.org"; - const ADDON_INSTALL_DATE = truncateToDays(Date.now()); - const EXPECTED_ADDON_DATA = { - blocklisted: false, - description: "A signed addon which gets enabled without a reboot.", - name: "XPI Telemetry Signed Test", - userDisabled: false, - appDisabled: false, - version: "1.0", - scope: 1, - type: "extension", - foreignInstall: false, - hasBinaryComponents: false, - installDay: ADDON_INSTALL_DATE, - updateDay: ADDON_INSTALL_DATE, - signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED, - }; - - let deferred = PromiseUtils.defer(); - TelemetryEnvironment.registerChangeListener("test_signedAddon", deferred.resolve); - - // Install the addon. - yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); - - yield deferred.promise; - // Unregister the listener. - TelemetryEnvironment.unregisterChangeListener("test_signedAddon"); - - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - // Check addon data. - Assert.ok(ADDON_ID in data.addons.activeAddons, "Add-on should be in the environment."); - let targetAddon = data.addons.activeAddons[ADDON_ID]; - for (let f in EXPECTED_ADDON_DATA) { - Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value."); - } -}); - -add_task(function* test_addonsFieldsLimit() { - const ADDON_INSTALL_URL = gDataRoot + "long-fields.xpi"; - const ADDON_ID = "tel-longfields-xpi@tests.mozilla.org"; - - // Install the addon and wait for the TelemetryEnvironment to pick it up. - let deferred = PromiseUtils.defer(); - TelemetryEnvironment.registerChangeListener("test_longFieldsAddon", deferred.resolve); - yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); - yield deferred.promise; - TelemetryEnvironment.unregisterChangeListener("test_longFieldsAddon"); - - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - // Check that the addon is available and that the string fields are limited. - Assert.ok(ADDON_ID in data.addons.activeAddons, "Add-on should be in the environment."); - let targetAddon = data.addons.activeAddons[ADDON_ID]; - - // TelemetryEnvironment limits the length of string fields for activeAddons to 100 chars, - // to mitigate misbehaving addons. - Assert.lessOrEqual(targetAddon.version.length, 100, - "The version string must have been limited"); - Assert.lessOrEqual(targetAddon.name.length, 100, - "The name string must have been limited"); - Assert.lessOrEqual(targetAddon.description.length, 100, - "The description string must have been limited"); -}); - -add_task(function* test_collectionWithbrokenAddonData() { - const BROKEN_ADDON_ID = "telemetry-test2.example.com@services.mozilla.org"; - const BROKEN_MANIFEST = { - id: "telemetry-test2.example.com@services.mozilla.org", - name: "telemetry broken addon", - origin: "https://telemetry-test2.example.com", - version: 1, // This is intentionally not a string. - signedState: AddonManager.SIGNEDSTATE_SIGNED, - }; - - const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi"; - const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org"; - const ADDON_INSTALL_DATE = truncateToDays(Date.now()); - const EXPECTED_ADDON_DATA = { - blocklisted: false, - description: "A restartless addon which gets enabled without a reboot.", - name: "XPI Telemetry Restartless Test", - userDisabled: false, - appDisabled: false, - version: "1.0", - scope: 1, - type: "extension", - foreignInstall: false, - hasBinaryComponents: false, - installDay: ADDON_INSTALL_DATE, - updateDay: ADDON_INSTALL_DATE, - signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING : - AddonManager.SIGNEDSTATE_NOT_REQUIRED, - }; - - let receivedNotifications = 0; - - let registerCheckpointPromise = (aExpected) => { - return new Promise(resolve => TelemetryEnvironment.registerChangeListener( - "testBrokenAddon_collection" + aExpected, (reason, data) => { - Assert.equal(reason, "addons-changed"); - receivedNotifications++; - resolve(); - })); - }; - - let assertCheckpoint = (aExpected) => { - Assert.equal(receivedNotifications, aExpected); - TelemetryEnvironment.unregisterChangeListener("testBrokenAddon_collection" + aExpected); - }; - - // Register the broken provider and install the broken addon. - let checkpointPromise = registerCheckpointPromise(1); - let brokenAddonProvider = createMockAddonProvider("Broken Extensions Provider"); - AddonManagerPrivate.registerProvider(brokenAddonProvider); - brokenAddonProvider.addAddon(BROKEN_MANIFEST); - yield checkpointPromise; - assertCheckpoint(1); - - // Now install an addon which returns the correct information. - checkpointPromise = registerCheckpointPromise(2); - yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); - yield checkpointPromise; - assertCheckpoint(2); - - // Check that the new environment contains the Social addon installed with the broken - // manifest and the rest of the data. - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data, false, true /* expect broken addons*/); - - let activeAddons = data.addons.activeAddons; - Assert.ok(BROKEN_ADDON_ID in activeAddons, - "The addon with the broken manifest must be reported."); - Assert.equal(activeAddons[BROKEN_ADDON_ID].version, null, - "null should be reported for invalid data."); - Assert.ok(ADDON_ID in activeAddons, - "The valid addon must be reported."); - Assert.equal(activeAddons[ADDON_ID].description, EXPECTED_ADDON_DATA.description, - "The description for the valid addon should be correct."); - - // Unregister the broken provider so we don't mess with other tests. - AddonManagerPrivate.unregisterProvider(brokenAddonProvider); - - // Uninstall the valid addon. - yield AddonManagerTesting.uninstallAddonByID(ADDON_ID); -}); - -add_task(function* test_defaultSearchEngine() { - // Check that no default engine is in the environment before the search service is - // initialized. - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - Assert.ok(!("defaultSearchEngine" in data.settings)); - Assert.ok(!("defaultSearchEngineData" in data.settings)); - - // Load the engines definitions from a custom JAR file: that's needed so that - // the search provider reports an engine identifier. - let url = "chrome://testsearchplugin/locale/searchplugins/"; - let resProt = Services.io.getProtocolHandler("resource") - .QueryInterface(Ci.nsIResProtocolHandler); - resProt.setSubstitution("search-plugins", - Services.io.newURI(url, null, null)); - - // Initialize the search service. - yield new Promise(resolve => Services.search.init(resolve)); - - // Our default engine from the JAR file has an identifier. Check if it is correctly - // reported. - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - Assert.equal(data.settings.defaultSearchEngine, "telemetrySearchIdentifier"); - let expectedSearchEngineData = { - name: "telemetrySearchIdentifier", - loadPath: "jar:[other]/searchTest.jar!testsearchplugin/telemetrySearchIdentifier.xml", - origin: "default", - submissionURL: "http://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); - - // Remove all the search engines. - for (let engine of Services.search.getEngines()) { - Services.search.removeEngine(engine); - } - // The search service does not notify "engine-current" when removing a default engine. - // Manually force the notification. - // TODO: remove this when bug 1165341 is resolved. - Services.obs.notifyObservers(null, "browser-search-engine-modified", "engine-current"); - - // Then check that no default engine is reported if none is available. - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - Assert.equal(data.settings.defaultSearchEngine, "NONE"); - Assert.deepEqual(data.settings.defaultSearchEngineData, {name:"NONE"}); - - // Add a new search engine (this will have no engine identifier). - const SEARCH_ENGINE_ID = "telemetry_default"; - const SEARCH_ENGINE_URL = "http://www.example.org/?search={searchTerms}"; - Services.search.addEngineWithDetails(SEARCH_ENGINE_ID, "", null, "", "get", 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); - Services.search.defaultEngine = Services.search.getEngineByName(SEARCH_ENGINE_ID); - yield deferred.promise; - - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID; - Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE); - - const EXPECTED_SEARCH_ENGINE_DATA = { - name: "telemetry_default", - loadPath: "[other]addEngineWithDetails", - origin: "verified" - }; - Assert.deepEqual(data.settings.defaultSearchEngineData, EXPECTED_SEARCH_ENGINE_DATA); - TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault"); - - // 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 = yield new Promise((resolve, reject) => { - Services.obs.addObserver(function obs(obsSubject, obsTopic, obsData) { - try { - let searchEngine = obsSubject.QueryInterface(Ci.nsISearchEngine); - do_print("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", false); - Services.search.addEngine("file://" + do_get_cwd().path + "/engine.xml", - null, null, false); - }); - Services.search.defaultEngine = engine; - yield promise; - TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault"); - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - Assert.deepEqual(data.settings.defaultSearchEngineData, - {"name":"engine-telemetry", "loadPath":"[other]/engine.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-current"); - yield promise; - TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault"); - data = TelemetryEnvironment.currentEnvironment; - Assert.equal(data.settings.defaultSearchEngineData.origin, "invalid"); - Services.search.removeEngine(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. - TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH); - deferred = PromiseUtils.defer(); - TelemetryEnvironment.registerChangeListener("testSearchEngine_pref", deferred.resolve); - // Trigger an environment change. - Preferences.set(PREF_TEST, 1); - yield deferred.promise; - TelemetryEnvironment.unregisterChangeListener("testSearchEngine_pref"); - - // Check that the search engine information is correctly retained when prefs change. - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE); - - // Check that by default we are not sending a cohort identifier... - Assert.equal(data.settings.searchCohort, undefined); - - // ... but that if a cohort identifier is set, we send it. - Services.prefs.setCharPref("browser.search.cohort", "testcohort"); - Services.obs.notifyObservers(null, "browser-search-service", "init-complete"); - data = TelemetryEnvironment.currentEnvironment; - Assert.equal(data.settings.searchCohort, "testcohort"); -}); - -add_task(function* test_osstrings() { - // First test that numbers in sysinfo properties are converted to string fields - // in system.os. - SysInfo.overrides = { - version: 1, - name: 2, - kernel_version: 3, - }; - - yield TelemetryEnvironment.testCleanRestart().onInitialized(); - let data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - Assert.equal(data.system.os.version, "1"); - Assert.equal(data.system.os.name, "2"); - if (AppConstants.platform == "android") { - Assert.equal(data.system.os.kernelVersion, "3"); - } - - // Check that null values are also handled. - SysInfo.overrides = { - version: null, - name: null, - kernel_version: null, - }; - - yield TelemetryEnvironment.testCleanRestart().onInitialized(); - data = TelemetryEnvironment.currentEnvironment; - checkEnvironmentData(data); - - Assert.equal(data.system.os.version, null); - Assert.equal(data.system.os.name, null); - if (AppConstants.platform == "android") { - Assert.equal(data.system.os.kernelVersion, null); - } - - // Clean up. - SysInfo.overrides = {}; - yield TelemetryEnvironment.testCleanRestart().onInitialized(); -}); - -add_task(function* test_environmentShutdown() { - // 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); - - // Set up the preferences and listener, then the trigger shutdown - TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH); - TelemetryEnvironment.registerChangeListener("test_environmentShutdownChange", () => { - // Register a new change listener that asserts if change is propogated - Assert.ok(false, "No change should be propagated after shutdown."); - }); - TelemetryEnvironment.shutdown(); - - // Flipping the test preference after shutdown should not trigger the listener - Preferences.set(PREF_TEST, 1); - - // Unregister the listener. - TelemetryEnvironment.unregisterChangeListener("test_environmentShutdownChange"); -}); |