mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 18:47:53 +00:00
96c88d557a
MozReview-Commit-ID: Bd10uC4pEfP --HG-- extra : rebase_source : 2f261194ff07a25c13aaad91255147e98e7c5127
236 lines
7.3 KiB
JavaScript
236 lines
7.3 KiB
JavaScript
/* -*- js-indent-level: 2; tab-width: 2; indent-tabs-mode: nil -*- */
|
|
var gConfig;
|
|
|
|
if (Cc === undefined) {
|
|
var Cc = Components.classes;
|
|
var Ci = Components.interfaces;
|
|
var Cu = Components.utils;
|
|
}
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Task.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
|
"resource://gre/modules/Services.jsm");
|
|
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
|
"resource://gre/modules/AddonManager.jsm");
|
|
|
|
// How long to wait for an add-on to uninstall before aborting
|
|
const MAX_UNINSTALL_TIME = 10000;
|
|
setTimeout(testInit, 0);
|
|
|
|
var sdkpath = null;
|
|
|
|
// Strip off the chrome prefix to get the actual path of the test directory
|
|
function realPath(chrome) {
|
|
return chrome.substring("chrome://mochitests/content/jetpack-addon/".length)
|
|
.replace(".xpi", "");
|
|
}
|
|
|
|
const chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
|
.getService(Ci.nsIChromeRegistry);
|
|
|
|
// Installs a single add-on returning a promise for when install is completed
|
|
function installAddon(url) {
|
|
let chromeURL = Services.io.newURI(url, null, null);
|
|
let file = chromeRegistry.convertChromeURL(chromeURL)
|
|
.QueryInterface(Ci.nsIFileURL).file;
|
|
|
|
let addon;
|
|
const listener = {
|
|
onInstalling(_addon) {
|
|
addon = _addon;
|
|
// Set add-on's test options
|
|
const options = {
|
|
test: {
|
|
iterations: 1,
|
|
stop: false,
|
|
keepOpen: true,
|
|
},
|
|
profile: {
|
|
memory: false,
|
|
leaks: false,
|
|
},
|
|
output: {
|
|
logLevel: "verbose",
|
|
format: "tbpl",
|
|
},
|
|
console: {
|
|
logLevel: "info",
|
|
},
|
|
}
|
|
setPrefs("extensions." + addon.id + ".sdk", options);
|
|
|
|
// If necessary override the add-ons module paths to point somewhere
|
|
// else
|
|
if (sdkpath) {
|
|
let paths = {}
|
|
for (let path of ["dev", "diffpatcher", "framescript", "method", "node", "sdk", "toolkit"]) {
|
|
paths[path] = sdkpath + path;
|
|
}
|
|
setPrefs("extensions.modules." + addon.id + ".path", paths);
|
|
}
|
|
},
|
|
};
|
|
AddonManager.addAddonListener(listener);
|
|
|
|
return AddonManager.installTemporaryAddon(file)
|
|
.then(() => {
|
|
AddonManager.removeAddonListener(listener);
|
|
return addon;
|
|
});
|
|
}
|
|
|
|
// Uninstalls an add-on returning a promise for when it is gone
|
|
function uninstallAddon(oldAddon) {
|
|
return new Promise(function(resolve, reject) {
|
|
AddonManager.addAddonListener({
|
|
onUninstalled: function(addon) {
|
|
if (addon.id != oldAddon.id)
|
|
return;
|
|
|
|
AddonManager.removeAddonListener(this);
|
|
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Uninstalled test add-on " + addon.id + "\n");
|
|
|
|
// Some add-ons do async work on uninstall, we must wait for that to
|
|
// complete
|
|
setTimeout(resolve, 500);
|
|
}
|
|
});
|
|
|
|
oldAddon.uninstall();
|
|
|
|
// The uninstall should happen quickly, if not throw an exception
|
|
setTimeout(() => {
|
|
reject(new Error(`Addon ${oldAddon.id} failed to uninstall in a timely fashion.`));
|
|
}, MAX_UNINSTALL_TIME);
|
|
});
|
|
}
|
|
|
|
// Waits for a test add-on to signal it has completed its tests
|
|
function waitForResults() {
|
|
return new Promise(function(resolve, reject) {
|
|
Services.obs.addObserver(function(subject, topic, data) {
|
|
Services.obs.removeObserver(arguments.callee, "sdk:test:results");
|
|
|
|
resolve(JSON.parse(data));
|
|
}, "sdk:test:results", false);
|
|
});
|
|
}
|
|
|
|
// Runs tests for the add-on available at URL.
|
|
var testAddon = Task.async(function*({ url }) {
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Installing test add-on " + realPath(url) + "\n");
|
|
let addon = yield installAddon(url);
|
|
|
|
let results = yield waitForResults();
|
|
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Uninstalling test add-on " + addon.id + "\n");
|
|
yield uninstallAddon(addon);
|
|
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Testing add-on " + realPath(url) + " is complete\n");
|
|
return results;
|
|
});
|
|
|
|
// Sets a set of prefs for test add-ons
|
|
function setPrefs(root, options) {
|
|
Object.keys(options).forEach(id => {
|
|
const key = root + "." + id;
|
|
const value = options[id]
|
|
const type = typeof(value);
|
|
|
|
value === null ? void(0) :
|
|
value === undefined ? void(0) :
|
|
type === "boolean" ? Services.prefs.setBoolPref(key, value) :
|
|
type === "string" ? Services.prefs.setCharPref(key, value) :
|
|
type === "number" ? Services.prefs.setIntPref(key, parseInt(value)) :
|
|
type === "object" ? setPrefs(key, value) :
|
|
void(0);
|
|
});
|
|
}
|
|
|
|
function testInit() {
|
|
// Make sure to run the test harness for the first opened window only
|
|
if (Services.prefs.prefHasUserValue("testing.jetpackTestHarness.running"))
|
|
return;
|
|
|
|
Services.prefs.setBoolPref("testing.jetpackTestHarness.running", true);
|
|
|
|
// Get the list of tests to run
|
|
let config = readConfig();
|
|
getTestList(config, function(links) {
|
|
try {
|
|
let fileNames = [];
|
|
let fileNameRegexp = /.+\.xpi$/;
|
|
arrayOfTestFiles(links, fileNames, fileNameRegexp);
|
|
|
|
if (config.startAt || config.endAt) {
|
|
fileNames = skipTests(fileNames, config.startAt, config.endAt);
|
|
}
|
|
|
|
// Override the SDK modules if necessary
|
|
try {
|
|
let sdklibs = Services.prefs.getCharPref("extensions.sdk.path");
|
|
// sdkpath is a file path, make it a URI
|
|
let sdkfile = Cc["@mozilla.org/file/local;1"].
|
|
createInstance(Ci.nsIFile);
|
|
sdkfile.initWithPath(sdklibs);
|
|
sdkpath = Services.io.newFileURI(sdkfile).spec;
|
|
}
|
|
catch (e) {
|
|
// Stick with the built-in modules
|
|
}
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function finish() {
|
|
if (passed + failed == 0) {
|
|
dump("TEST-UNEXPECTED-FAIL | jetpack-addon-harness.js | " +
|
|
"No tests to run. Did you pass invalid test_paths?\n");
|
|
}
|
|
else {
|
|
dump("Jetpack Addon Test Summary\n");
|
|
dump("\tPassed: " + passed + "\n" +
|
|
"\tFailed: " + failed + "\n" +
|
|
"\tTodo: 0\n");
|
|
}
|
|
|
|
if (config.closeWhenDone) {
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Shutting down.\n");
|
|
|
|
const appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
|
|
getService(Ci.nsIAppStartup);
|
|
appStartup.quit(appStartup.eAttemptQuit);
|
|
}
|
|
}
|
|
|
|
function testNextAddon() {
|
|
if (fileNames.length == 0)
|
|
return finish();
|
|
|
|
let filename = fileNames.shift();
|
|
dump("TEST-INFO | jetpack-addon-harness.js | Starting test add-on " + realPath(filename.url) + "\n");
|
|
testAddon(filename).then(results => {
|
|
passed += results.passed;
|
|
failed += results.failed;
|
|
}).then(testNextAddon, error => {
|
|
// If something went wrong during the test then a previous test add-on
|
|
// may still be installed, this leaves us in an unexpected state so
|
|
// probably best to just abandon testing at this point
|
|
failed++;
|
|
dump("TEST-UNEXPECTED-FAIL | jetpack-addon-harness.js | Error testing " + realPath(filename.url) + ": " + error + "\n");
|
|
finish();
|
|
});
|
|
}
|
|
|
|
testNextAddon();
|
|
}
|
|
catch (e) {
|
|
dump("TEST-UNEXPECTED-FAIL | jetpack-addon-harness.js | error starting test harness (" + e + ")\n");
|
|
dump(e.stack);
|
|
}
|
|
});
|
|
}
|