Source code

Revision control

Copy as Markdown

Other Tools

/* Any copyright is dedicated to the Public Domain.
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
AddonManager: "resource://gre/modules/AddonManager.sys.mjs",
// AttributionCode is only needed for Firefox
AttributionCode: "resource:///modules/AttributionCode.sys.mjs",
});
const gIsWindows = AppConstants.platform == "win";
const gIsMac = AppConstants.platform == "macosx";
const gIsAndroid = AppConstants.platform == "android";
const gIsLinux = AppConstants.platform == "linux";
const MILLISECONDS_PER_MINUTE = 60 * 1000;
const MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
const MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
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";
// The profile reset date, in milliseconds (Today)
const PROFILE_RESET_DATE_MS = Date.now();
// The profile creation date, in milliseconds (Yesterday).
const PROFILE_FIRST_USE_MS = PROFILE_RESET_DATE_MS - MILLISECONDS_PER_DAY;
const PROFILE_CREATION_DATE_MS = PROFILE_FIRST_USE_MS - MILLISECONDS_PER_DAY;
const PROFILE_RECOVERED_FROM_BACKUP =
PROFILE_RESET_DATE_MS - MILLISECONDS_PER_HOUR;
const GFX_VENDOR_ID = "0xabcd";
const GFX_DEVICE_ID = "0x1234";
const EXPECTED_HDD_FIELDS = ["profile", "binary", "system"];
// Valid attribution code to write so that settings.attribution can be tested.
const ATTRIBUTION_CODE = "source%3Dgoogle.com%26dlsource%3Dunittest";
function truncateToDays(aMsec) {
return Math.floor(aMsec / MILLISECONDS_PER_DAY);
}
var SysInfo = {
overrides: {},
getProperty(name) {
// Assert.ok(false, "Mock SysInfo: " + name + ", " + JSON.stringify(this.overrides));
if (name in this.overrides) {
return this.overrides[name];
}
return this._genuine.QueryInterface(Ci.nsIPropertyBag).getProperty(name);
},
getPropertyAsACString(name) {
return this.get(name);
},
getPropertyAsUint32(name) {
return this.get(name);
},
get(name) {
return this._genuine.QueryInterface(Ci.nsIPropertyBag2).get(name);
},
get diskInfo() {
return this._genuine.QueryInterface(Ci.nsISystemInfo).diskInfo;
},
get osInfo() {
return this._genuine.QueryInterface(Ci.nsISystemInfo).osInfo;
},
get processInfo() {
return this._genuine.QueryInterface(Ci.nsISystemInfo).processInfo;
},
QueryInterface: ChromeUtils.generateQI(["nsIPropertyBag2", "nsISystemInfo"]),
};
/**
* TelemetryEnvironmentTesting - tools for testing the telemetry environment
* reporting.
*/
export var TelemetryEnvironmentTesting = {
EXPECTED_HDD_FIELDS,
init(appInfo) {
this.appInfo = appInfo;
},
setSysInfoOverrides(overrides) {
SysInfo.overrides = overrides;
},
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.
}
},
spoofProfileReset() {
return IOUtils.writeJSON(
PathUtils.join(PathUtils.profileDir, "times.json"),
{
created: PROFILE_CREATION_DATE_MS,
reset: PROFILE_RESET_DATE_MS,
firstUse: PROFILE_FIRST_USE_MS,
recoveredFromBackup: PROFILE_RECOVERED_FROM_BACKUP,
}
);
},
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) {
Services.prefs
.getDefaultBranch(null)
.setStringPref(pref, prefsToSpoof[pref]);
}
},
async spoofAttributionData() {
if (gIsWindows) {
lazy.AttributionCode._clearCache();
await lazy.AttributionCode.writeAttributionFile(ATTRIBUTION_CODE);
} else if (gIsMac) {
lazy.AttributionCode._clearCache();
const { MacAttribution } = ChromeUtils.importESModule(
"resource:///modules/MacAttribution.sys.mjs"
);
await MacAttribution.setAttributionString(ATTRIBUTION_CODE);
}
},
async cleanupAttributionData() {
if (gIsWindows) {
lazy.AttributionCode.attributionFile.remove(false);
lazy.AttributionCode._clearCache();
} else if (gIsMac) {
const { MacAttribution } = ChromeUtils.importESModule(
"resource:///modules/MacAttribution.sys.mjs"
);
await MacAttribution.delAttributionString();
}
},
registerFakeSysInfo() {
lazy.MockRegistrar.register("@mozilla.org/system-info;1", SysInfo);
},
/**
* 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.
*/
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.
*/
checkNullOrString(aValue) {
if (aValue) {
return this.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.
*/
checkNullOrBool(aValue) {
return aValue === null || typeof aValue == "boolean";
},
checkBuildSection(data) {
const expectedInfo = {
applicationId: APP_ID,
applicationName: APP_NAME,
buildId: this.appInfo.appBuildID,
version: APP_VERSION,
vendor: "Mozilla",
platformVersion: PLATFORM_VERSION,
xpcomAbi: "noarch-spidermonkey",
};
lazy.Assert.ok(
"build" in data,
"There must be a build section in Environment."
);
for (let f in expectedInfo) {
lazy.Assert.ok(
this.checkString(data.build[f]),
f + " must be a valid string."
);
lazy.Assert.equal(
data.build[f],
expectedInfo[f],
f + " must have the correct value."
);
}
// Make sure architecture is in the environment.
lazy.Assert.ok(this.checkString(data.build.architecture));
lazy.Assert.equal(
data.build.updaterAvailable,
AppConstants.MOZ_UPDATER,
"build.updaterAvailable must equal AppConstants.MOZ_UPDATER"
);
},
checkSettingsSection(data) {
const EXPECTED_FIELDS_TYPES = {
blocklistEnabled: "boolean",
e10sEnabled: "boolean",
e10sMultiProcesses: "number",
fissionEnabled: "boolean",
intl: "object",
locale: "string",
telemetryEnabled: "boolean",
update: "object",
userPrefs: "object",
};
lazy.Assert.ok(
"settings" in data,
"There must be a settings section in Environment."
);
for (let f in EXPECTED_FIELDS_TYPES) {
lazy.Assert.equal(
typeof data.settings[f],
EXPECTED_FIELDS_TYPES[f],
f + " must have the correct type."
);
}
// This property is not always present, but when it is, it must be a number.
if ("launcherProcessState" in data.settings) {
lazy.Assert.equal(typeof data.settings.launcherProcessState, "number");
}
// Check "addonCompatibilityCheckEnabled" separately.
lazy.Assert.equal(
data.settings.addonCompatibilityCheckEnabled,
lazy.AddonManager.checkCompatibility
);
// Check "isDefaultBrowser" separately, as it is not available on Android an can either be
// null or boolean on other platforms.
if (gIsAndroid) {
lazy.Assert.ok(
!("isDefaultBrowser" in data.settings),
"Must not be available on Android."
);
} else if ("isDefaultBrowser" in data.settings) {
// isDefaultBrowser might not be available in the payload, since it's
// gathered after the session was restored.
lazy.Assert.ok(this.checkNullOrBool(data.settings.isDefaultBrowser));
}
// Check "channel" separately, as it can either be null or string.
let update = data.settings.update;
lazy.Assert.ok(this.checkNullOrString(update.channel));
lazy.Assert.equal(typeof update.enabled, "boolean");
lazy.Assert.equal(typeof update.autoDownload, "boolean");
lazy.Assert.equal(typeof update.background, "boolean");
// Check sandbox settings exist and make sense
if (data.settings.sandbox.effectiveContentProcessLevel !== null) {
lazy.Assert.equal(
typeof data.settings.sandbox.effectiveContentProcessLevel,
"number",
"sandbox.effectiveContentProcessLevel must have the correct type"
);
}
if (data.settings.sandbox.contentWin32kLockdownState !== null) {
lazy.Assert.equal(
typeof data.settings.sandbox.contentWin32kLockdownState,
"number",
"sandbox.contentWin32kLockdownState must have the correct type"
);
let win32kLockdownState =
data.settings.sandbox.contentWin32kLockdownState;
lazy.Assert.ok(win32kLockdownState >= 1 && win32kLockdownState <= 17);
}
// Check "defaultSearchEngine" separately, as it can either be undefined or string.
if ("defaultSearchEngine" in data.settings) {
this.checkString(data.settings.defaultSearchEngine);
lazy.Assert.equal(typeof data.settings.defaultSearchEngineData, "object");
}
if ("defaultPrivateSearchEngineData" in data.settings) {
lazy.Assert.equal(
typeof data.settings.defaultPrivateSearchEngineData,
"object"
);
}
if ((gIsWindows || gIsMac) && AppConstants.MOZ_BUILD_APP == "browser") {
lazy.Assert.equal(typeof data.settings.attribution, "object");
lazy.Assert.equal(data.settings.attribution.source, "google.com");
lazy.Assert.equal(data.settings.attribution.dlsource, "unittest");
}
this.checkIntlSettings(data.settings);
},
checkIntlSettings({ intl }) {
let fields = [
"requestedLocales",
"availableLocales",
"appLocales",
"acceptLanguages",
];
for (let field of fields) {
lazy.Assert.ok(Array.isArray(intl[field]), `${field} is an array`);
}
// These fields may be null if they aren't ready yet. This is mostly to deal
// with test failures on Android, but they aren't guaranteed to exist.
let optionalFields = ["systemLocales", "regionalPrefsLocales"];
for (let field of optionalFields) {
let isArray = Array.isArray(intl[field]);
let isNull = intl[field] === null;
lazy.Assert.ok(isArray || isNull, `${field} is an array or null`);
}
},
checkProfileSection(data) {
lazy.Assert.ok(
"profile" in data,
"There must be a profile section in Environment."
);
lazy.Assert.equal(
data.profile.creationDate,
truncateToDays(PROFILE_CREATION_DATE_MS)
);
lazy.Assert.equal(
data.profile.resetDate,
truncateToDays(PROFILE_RESET_DATE_MS)
);
lazy.Assert.equal(
data.profile.firstUseDate,
truncateToDays(PROFILE_FIRST_USE_MS)
);
lazy.Assert.equal(
data.profile.recoveredFromBackup,
truncateToDays(PROFILE_RECOVERED_FROM_BACKUP)
);
},
checkPartnerSection(data, isInitial) {
const EXPECTED_FIELDS = {
distributionId: DISTRIBUTION_ID,
distributionVersion: DISTRIBUTION_VERSION,
partnerId: PARTNER_ID,
distributor: DISTRIBUTOR_NAME,
distributorChannel: DISTRIBUTOR_CHANNEL,
};
lazy.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];
lazy.Assert.strictEqual(
data.partner[f],
expected,
f + " must have the correct value."
);
}
// Check that "partnerNames" exists and contains the correct element.
lazy.Assert.ok(Array.isArray(data.partner.partnerNames));
if (isInitial) {
lazy.Assert.equal(data.partner.partnerNames.length, 0);
} else {
lazy.Assert.ok(data.partner.partnerNames.includes(PARTNER_NAME));
}
},
checkGfxAdapter(data) {
const EXPECTED_ADAPTER_FIELDS_TYPES = {
description: "string",
vendorID: "string",
deviceID: "string",
subsysID: "string",
RAM: "number",
driver: "string",
driverVendor: "string",
driverVersion: "string",
driverDate: "string",
GPUActive: "boolean",
};
for (let f in EXPECTED_ADAPTER_FIELDS_TYPES) {
lazy.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.
lazy.Assert.equal(
typeof data[f],
EXPECTED_ADAPTER_FIELDS_TYPES[f],
f + " must have the correct type."
);
}
}
},
checkSystemSection(data, assertProcessData) {
const EXPECTED_FIELDS = [
"memoryMB",
"cpu",
"os",
"hdd",
"gfx",
"appleModelId",
];
lazy.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) {
lazy.Assert.ok(f in data.system, f + " must be available.");
}
lazy.Assert.ok(
Number.isFinite(data.system.memoryMB),
"MemoryMB must be a number."
);
if (assertProcessData) {
if (gIsWindows || gIsMac || gIsLinux) {
let EXTRA_CPU_FIELDS = [
"cores",
"model",
"family",
"stepping",
"l2cacheKB",
"l3cacheKB",
"speedMHz",
"vendor",
"name",
];
for (let f of EXTRA_CPU_FIELDS) {
// Note this is testing TelemetryEnvironment.js only, not that the
// values are valid - null is the fallback.
lazy.Assert.ok(
f in data.system.cpu,
f + " must be available under cpu."
);
}
if (gIsWindows) {
lazy.Assert.equal(
typeof data.system.isWow64,
"boolean",
"isWow64 must be available on Windows and have the correct type."
);
lazy.Assert.equal(
typeof data.system.isWowARM64,
"boolean",
"isWowARM64 must be available on Windows and have the correct type."
);
lazy.Assert.equal(
typeof data.system.hasWinPackageId,
"boolean",
"hasWinPackageId must be available on Windows and have the correct type."
);
// This is only sent for Mozilla produced MSIX packages
lazy.Assert.ok(
!("winPackageFamilyName" in data.system) ||
data.system.winPackageFamilyName === null ||
typeof data.system.winPackageFamilyName === "string",
"winPackageFamilyName must be a string if non null"
);
lazy.Assert.ok(
"virtualMaxMB" in data.system,
"virtualMaxMB must be available."
);
lazy.Assert.ok(
Number.isFinite(data.system.virtualMaxMB),
"virtualMaxMB must be a number."
);
for (let f of [
"count",
"model",
"family",
"stepping",
"l2cacheKB",
"l3cacheKB",
"speedMHz",
]) {
lazy.Assert.ok(
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 [
"count",
"model",
"family",
"stepping",
"l2cacheKB",
"l3cacheKB",
"speedMHz",
]) {
lazy.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."
);
}
// We insist these are available
for (let f of ["cores"]) {
lazy.Assert.ok(
!(f in data.system.cpu) || Number.isFinite(data.system.cpu[f]),
f + " must be a number if non null."
);
}
}
}
let cpuData = data.system.cpu;
lazy.Assert.ok(
Array.isArray(cpuData.extensions),
"CPU extensions must be available."
);
let osData = data.system.os;
lazy.Assert.ok(this.checkNullOrString(osData.name));
lazy.Assert.ok(this.checkNullOrString(osData.version));
lazy.Assert.ok(this.checkNullOrString(osData.locale));
// Service pack is only available on Windows.
if (gIsWindows) {
lazy.Assert.ok(
Number.isFinite(osData.servicePackMajor),
"ServicePackMajor must be a number."
);
lazy.Assert.ok(
Number.isFinite(osData.servicePackMinor),
"ServicePackMinor must be a number."
);
if ("windowsBuildNumber" in osData) {
// This might not be available on all Windows platforms.
lazy.Assert.ok(
Number.isFinite(osData.windowsBuildNumber),
"windowsBuildNumber must be a number."
);
}
if ("windowsUBR" in osData) {
// This might not be available on all Windows platforms.
lazy.Assert.ok(
osData.windowsUBR === null || Number.isFinite(osData.windowsUBR),
"windowsUBR must be null or a number."
);
}
} else if (gIsAndroid) {
lazy.Assert.ok(this.checkNullOrString(osData.kernelVersion));
} else if (gIsLinux) {
lazy.Assert.ok(this.checkNullOrString(osData.distro));
lazy.Assert.ok(this.checkNullOrString(osData.distroVersion));
}
for (let disk of EXPECTED_HDD_FIELDS) {
lazy.Assert.ok(this.checkNullOrString(data.system.hdd[disk].model));
lazy.Assert.ok(this.checkNullOrString(data.system.hdd[disk].revision));
lazy.Assert.ok(this.checkNullOrString(data.system.hdd[disk].type));
}
let gfxData = data.system.gfx;
lazy.Assert.ok("D2DEnabled" in gfxData);
lazy.Assert.ok("DWriteEnabled" in gfxData);
lazy.Assert.ok("Headless" in gfxData);
lazy.Assert.ok("TargetFrameRate" in gfxData);
lazy.Assert.equal(typeof gfxData.TargetFrameRate, "number");
lazy.Assert.ok("EmbeddedInFirefoxReality" in gfxData);
lazy.Assert.ok("textScaleFactor" 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) {
lazy.Assert.equal(typeof gfxData.D2DEnabled, "boolean");
lazy.Assert.equal(typeof gfxData.DWriteEnabled, "boolean");
lazy.Assert.equal(typeof gfxData.EmbeddedInFirefoxReality, "boolean");
// As above, will be enabled again as part of bug 1154500.
// Assert.ok(this.checkString(gfxData.DWriteVersion));
}
lazy.Assert.ok("adapters" in gfxData);
lazy.Assert.ok(
!!gfxData.adapters.length,
"There must be at least one GFX adapter."
);
for (let adapter of gfxData.adapters) {
this.checkGfxAdapter(adapter);
}
lazy.Assert.equal(typeof gfxData.adapters[0].GPUActive, "boolean");
lazy.Assert.ok(
gfxData.adapters[0].GPUActive,
"The first GFX adapter must be active."
);
lazy.Assert.ok(Array.isArray(gfxData.monitors));
if (gIsWindows || gIsMac || gIsLinux) {
lazy.Assert.ok(
gfxData.monitors.length >= 1,
"There is at least one monitor."
);
lazy.Assert.equal(typeof gfxData.monitors[0].screenWidth, "number");
lazy.Assert.equal(typeof gfxData.monitors[0].screenHeight, "number");
lazy.Assert.equal(
typeof gfxData.monitors[0].defaultCSSScaleFactor,
"number"
);
lazy.Assert.equal(
typeof gfxData.monitors[0].contentsScaleFactor,
"number"
);
if (gIsWindows) {
lazy.Assert.equal(typeof gfxData.monitors[0].refreshRate, "number");
lazy.Assert.equal(typeof gfxData.monitors[0].pseudoDisplay, "boolean");
}
}
lazy.Assert.equal(typeof gfxData.features, "object");
lazy.Assert.equal(typeof gfxData.features.compositor, "string");
lazy.Assert.equal(typeof gfxData.features.gpuProcess, "object");
lazy.Assert.equal(typeof gfxData.features.gpuProcess.status, "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) {
lazy.Assert.equal(GFX_VENDOR_ID, gfxData.adapters[0].vendorID);
lazy.Assert.equal(GFX_DEVICE_ID, gfxData.adapters[0].deviceID);
}
let features = gfxInfo.getFeatures();
lazy.Assert.equal(features.compositor, gfxData.features.compositor);
lazy.Assert.equal(
features.gpuProcess.status,
gfxData.features.gpuProcess.status
);
lazy.Assert.equal(features.opengl, gfxData.features.opengl);
lazy.Assert.equal(features.webgl, gfxData.features.webgl);
} catch (e) {}
if (gIsMac) {
lazy.Assert.ok(this.checkString(data.system.appleModelId));
} else {
lazy.Assert.ok(this.checkNullOrString(data.system.appleModelId));
}
// This feature is only available on Windows
if (AppConstants.platform == "win") {
lazy.Assert.ok(
"sec" in data.system,
"sec must be available under data.system"
);
let SEC_FIELDS = ["antivirus", "antispyware", "firewall"];
for (let f of SEC_FIELDS) {
lazy.Assert.ok(
f in data.system.sec,
f + " must be available under data.system.sec"
);
let value = data.system.sec[f];
// value is null on Windows Server
lazy.Assert.ok(
value === null || Array.isArray(value),
f + " must be either null or an array"
);
if (Array.isArray(value)) {
for (let product of value) {
lazy.Assert.equal(
typeof product,
"string",
"Each element of " + f + " must be a string"
);
}
}
}
}
},
checkActiveAddon(data, partialRecord) {
let signedState = "number";
// system add-ons have an undefined signState
if (data.isSystem) {
signedState = "undefined";
}
const EXPECTED_ADDON_FIELDS_TYPES = {
version: "string",
scope: "number",
type: "string",
updateDay: "number",
isSystem: "boolean",
isWebExtension: "boolean",
multiprocessCompatible: "boolean",
};
const FULL_ADDON_FIELD_TYPES = {
blocklisted: "boolean",
name: "string",
userDisabled: "boolean",
appDisabled: "boolean",
foreignInstall: "boolean",
hasBinaryComponents: "boolean",
installDay: "number",
signedState,
};
let fields = EXPECTED_ADDON_FIELDS_TYPES;
if (!partialRecord) {
fields = Object.assign({}, fields, FULL_ADDON_FIELD_TYPES);
}
for (let [name, type] of Object.entries(fields)) {
lazy.Assert.ok(name in data, name + " must be available.");
lazy.Assert.equal(
typeof data[name],
type,
name + " must have the correct type."
);
}
if (!partialRecord) {
// We check "description" separately, as it can be null.
lazy.Assert.ok(this.checkNullOrString(data.description));
}
},
checkTheme(data) {
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) {
lazy.Assert.ok(f in data, f + " must be available.");
lazy.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.
lazy.Assert.ok(this.checkNullOrString(data.description));
},
checkActiveGMPlugin(data) {
// GMP plugin version defaults to null until GMPDownloader runs to update it.
if (data.version) {
lazy.Assert.equal(typeof data.version, "string");
}
lazy.Assert.equal(typeof data.userDisabled, "boolean");
lazy.Assert.equal(typeof data.applyBackgroundUpdates, "number");
},
checkAddonsSection(data, expectBrokenAddons, partialAddonsRecords) {
const EXPECTED_FIELDS = ["activeAddons", "theme", "activeGMPlugins"];
lazy.Assert.ok(
"addons" in data,
"There must be an addons section in Environment."
);
for (let f of EXPECTED_FIELDS) {
lazy.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) {
this.checkActiveAddon(activeAddons[addon], partialAddonsRecords);
}
}
// Check "theme" structure.
if (Object.keys(data.addons.theme).length !== 0) {
this.checkTheme(data.addons.theme);
}
// Check active GMPlugins
let activeGMPlugins = data.addons.activeGMPlugins;
for (let gmPlugin in activeGMPlugins) {
this.checkActiveGMPlugin(activeGMPlugins[gmPlugin]);
}
},
checkEnvironmentData(data, options = {}) {
const {
isInitial = false,
expectBrokenAddons = false,
assertProcessData = false,
} = options;
this.checkBuildSection(data);
this.checkSettingsSection(data);
this.checkProfileSection(data);
this.checkPartnerSection(data, isInitial);
this.checkSystemSection(data, assertProcessData);
this.checkAddonsSection(data, expectBrokenAddons);
},
};