Bug 1122050 - Environment addons data collection test coverage. r=gfritzsche

This commit is contained in:
Alessio Placitelli 2015-02-25 23:54:33 +01:00
parent 29041b0ed8
commit 376460a8c1
11 changed files with 604 additions and 7 deletions

View File

@ -42,3 +42,14 @@ $(histogram_data_file): $(histograms_file) $(data_python_deps)
$(PYTHON) $(srcdir)/gen-histogram-data.py $< > $@
GARBAGE += $(histogram_enum_file)
# This is so hacky. Waiting on bug 988938.
addondir = $(srcdir)/tests/addons
testdir = $(abspath $(DEPTH)/_tests/xpcshell/toolkit/components/telemetry/tests/unit)
misc:: $(call mkdir_deps,$(testdir))
$(EXIT_ON_ERROR) \
for dir in $(addondir)/*; do \
base=`basename $$dir`; \
(cd $$dir && zip -qr $(testdir)/$$base.xpi *); \
done

View File

@ -4,6 +4,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
HAS_MISC_RULE = True
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
XPIDL_SOURCES += [

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>telemetry-dictionary@tests.mozilla.org</em:id>
<em:version>1</em:version>
<em:type>64</em:type>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Telemetry test dictionary</em:name>
<em:description>A nice dictionary to prevent all typos for Telemetry.</em:description>
<em:bootstrap>true</em:bootstrap>
</Description>
</RDF>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>telemetry-experiment-1@tests.mozilla.org</em:id>
<em:version>1</em:version>
<em:type>128</em:type>
<!-- Front End MetaData -->
<em:name>Telemetry test experiment</em:name>
<em:description>Yet another experiment that experiments experimentally.</em:description>
</Description>
</RDF>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>telemetry-ext-2@tests.mozilla.org</em:id>
<em:version>2</em:version>
<em:type>2</em:type>
<!-- Front End MetaData -->
<em:name>Telemetry test extension 2</em:name>
<em:description>Yet another extension that extends twice.</em:description>
</Description>
</RDF>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>telemetry-ext-1@tests.mozilla.org</em:id>
<em:version>1</em:version>
<em:type>2</em:type>
<!-- Front End MetaData -->
<em:name>Telemetry test extension</em:name>
<em:description>Yet another extension that extends.</em:description>
</Description>
</RDF>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>tel-restartless-xpi@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>XPI Telemetry Restartless Test</em:name>
<em:description>A restartless addon which gets enabled without a reboot.</em:description>
<em:bootstrap>true</em:bootstrap>
</Description>
</RDF>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>telemetry-theme@tests.mozilla.org</em:id>
<em:version>1</em:version>
<em:type>4</em:type>
<!-- Front End MetaData -->
<em:name>Telemetry test theme</em:name>
<em:description>A good looking test theme for Telemetry.</em:description>
</Description>
</RDF>

View File

@ -3,12 +3,25 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
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/services/healthreport/profile.jsm", this);
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://testing-common/AddonManagerTesting.jsm");
Cu.import("resource://testing-common/httpd.js");
// Lazy load |LightweightThemeManager|, we won't be using it on Gonk.
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
// The webserver hosting the addons.
let gHttpServer = null;
// The URL of the webserver root.
let gHttpRoot = null;
// The URL of the data directory, on the webserver.
let gDataRoot = null;
const PLATFORM_VERSION = "1.9.2";
const APP_VERSION = "1";
@ -37,6 +50,106 @@ const gIsMac = ("@mozilla.org/xpcom/mac-utils;1" in Cc);
const gIsAndroid = ("@mozilla.org/android/bridge;1" in Cc);
const gIsGonk = ("@mozilla.org/cellbroadcast/gonkservice;1" in Cc);
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 PLUGINHOST_CONTRACTID = "@mozilla.org/plugin/host;1";
const PLUGINHOST_CID = Components.ID("{2329e6ea-1f15-4cbe-9ded-6e98e842de0e}");
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";
/**
* 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.
let 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.
let 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;
}
}
let PluginHostFactory = {
createInstance: function (outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return PluginHost.QueryInterface(iid);
}
};
function registerFakePluginHost() {
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(PLUGINHOST_CID, "Fake Plugin Host",
PLUGINHOST_CONTRACTID, PluginHostFactory);
}
/**
* 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);
@ -133,8 +246,8 @@ function checkBuildSection(data) {
Assert.ok("build" in data, "There must be a build section in Environment.");
for (let f in expectedInfo) {
Assert.ok(checkString(data.build[f]));
Assert.equal(data.build[f], expectedInfo[f]);
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 and hotfixVersion are in the environment.
@ -163,7 +276,8 @@ function checkSettingsSection(data) {
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]);
Assert.equal(typeof data.settings[f], EXPECTED_FIELDS_TYPES[f],
f + " must have the correct type.");
}
// Check "isDefaultBrowser" separately, as it can either be null or boolean.
@ -194,7 +308,7 @@ function checkPartnerSection(data) {
Assert.ok("partner" in data, "There must be a partner section in Environment.");
for (let f in EXPECTED_FIELDS) {
Assert.equal(data.partner[f], EXPECTED_FIELDS[f]);
Assert.equal(data.partner[f], EXPECTED_FIELDS[f], f + " must have the correct value.");
}
// Check that "partnerNames" exists and contains the correct element.
@ -216,11 +330,12 @@ function checkGfxAdapter(data) {
};
for (let f in EXPECTED_ADAPTER_FIELDS_TYPES) {
Assert.ok(f in data);
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]);
Assert.equal(typeof data[f], EXPECTED_ADAPTER_FIELDS_TYPES[f],
f + " must have the correct type.");
}
}
}
@ -233,7 +348,7 @@ function checkSystemSection(data) {
// Make sure we have all the top level sections and fields.
for (let f of EXPECTED_FIELDS) {
Assert.ok(f in data.system);
Assert.ok(f in data.system, f + " must be available.");
}
Assert.ok(Number.isFinite(data.system.memoryMB), "MemoryMB must be a number.");
@ -307,12 +422,137 @@ function checkSystemSection(data) {
catch (e) {}
}
function checkActiveAddon(data){
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",
};
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) {
Assert.equal(typeof data.version, "string");
Assert.equal(typeof data.userDisabled, "boolean");
Assert.equal(typeof data.applyBackgroundUpdates, "boolean");
}
function checkAddonsSection(data) {
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.
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) {
checkBuildSection(data);
checkSettingsSection(data);
checkProfileSection(data);
checkPartnerSection(data);
checkSystemSection(data);
checkAddonsSection(data);
}
function run_test() {
@ -320,6 +560,24 @@ function run_test() {
spoofGfxAdapter();
do_get_profile();
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(() => {}));
spoofPartnerInfo();
// Spoof the the hotfixVersion
Preferences.set("extensions.hotfix.lastVersion", APP_HOTFIX_VERSION);
@ -460,6 +718,193 @@ add_task(function* test_prefWatch_prefReset() {
yield TelemetryEnvironment.shutdown();
});
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;
yield TelemetryEnvironment.init();
let deferred = PromiseUtils.defer();
let receivedNotifications = 0;
let registerCheckpointPromise = (aExpected) => {
return new Promise(resolve => TelemetryEnvironment.registerChangeListener(
"testWatchAddons_Changes" + aExpected, () => {
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 AddonTestUtils.installXPIFromURL(ADDON_INSTALL_URL);
yield checkpointPromise;
assertCheckpoint(1);
checkpointPromise = registerCheckpointPromise(2);
let addon = yield AddonTestUtils.getAddonById(ADDON_ID);
addon.userDisabled = true;
yield checkpointPromise;
assertCheckpoint(2);
checkpointPromise = registerCheckpointPromise(3);
addon.userDisabled = false;
yield checkpointPromise;
assertCheckpoint(3);
checkpointPromise = registerCheckpointPromise(4);
yield AddonTestUtils.uninstallAddonByID(ADDON_ID);
yield checkpointPromise;
assertCheckpoint(4);
yield TelemetryEnvironment.shutdown();
Assert.equal(receivedNotifications, EXPECTED_NOTIFICATIONS,
"We must only receive the notifications we expect.");
});
add_task(function* test_pluginsWatch_Add() {
yield TelemetryEnvironment.init();
let newPlugin = new PluginTag(PLUGIN2_NAME, PLUGIN2_DESC, PLUGIN2_VERSION, true);
gInstalledPlugins.push(newPlugin);
let deferred = PromiseUtils.defer();
let receivedNotifications = 0;
let callback = () => {
receivedNotifications++;
deferred.resolve();
};
TelemetryEnvironment.registerChangeListener("testWatchPlugins_Add", callback);
Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null);
yield deferred.promise;
TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Add");
yield TelemetryEnvironment.shutdown();
Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
});
add_task(function* test_pluginsWatch_Remove() {
yield TelemetryEnvironment.init();
// Find the test plugin.
let plugin = gInstalledPlugins.find(plugin => (plugin.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");
yield TelemetryEnvironment.shutdown();
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";
yield TelemetryEnvironment.init();
let receivedNotifications = 0;
TelemetryEnvironment.registerChangeListener("testNotInteresting",
() => receivedNotifications++);
yield AddonTestUtils.installXPIFromURL(DICTIONARY_ADDON_INSTALL_URL);
yield AddonTestUtils.installXPIFromURL(INTERESTING_ADDON_INSTALL_URL);
Assert.equal(receivedNotifications, 1, "We must receive only one notification.");
TelemetryEnvironment.unregisterChangeListener("testNotInteresting");
yield TelemetryEnvironment.shutdown();
});
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,
};
const EXPECTED_PLUGIN_DATA = {
name: FLASH_PLUGIN_NAME,
version: FLASH_PLUGIN_VERSION,
description: FLASH_PLUGIN_DESC,
blocklisted: false,
disabled: false,
clicktoplay: true,
};
yield TelemetryEnvironment.init();
// Install an addon so we have some data.
yield AddonTestUtils.installXPIFromURL(ADDON_INSTALL_URL);
let data = yield TelemetryEnvironment.getEnvironmentData();
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 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.");
yield TelemetryEnvironment.shutdown();
});
add_task(function*() {
do_test_finished();
});

View File

@ -2,6 +2,22 @@
head = head.js
tail =
skip-if = toolkit == 'gonk'
# The *.xpi files are only needed for test_TelemetryEnvironment.js, but
# xpcshell fails to install tests if we move them under the test entry.
support-files =
dictionary.xpi
experiment.xpi
extension.xpi
extension-2.xpi
restartless.xpi
theme.xpi
generated-files =
dictionary.xpi
experiment.xpi
extension.xpi
extension-2.xpi
restartless.xpi
theme.xpi
[test_nsITelemetry.js]
[test_TelemetryEnvironment.js]

View File

@ -20,6 +20,16 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
this.AddonTestUtils = {
/**
* Get the add-on that is specified by its ID.
*
* @return {Promise<Object>} A promise that resolves returning the found addon or null
* if it is not found.
*/
getAddonById: function (id) {
return new Promise(resolve => AddonManager.getAddonByID(id, addon => resolve(addon)));
},
/**
* Uninstall an add-on that is specified by its ID.
*