Bug 1256088 - Merge mock app-info implementation into AppInfo.jsm. r=gps
authorTooru Fujisawa <arai_a@mac.com>
Wed, 16 Mar 2016 16:58:29 +0900
changeset 288935 c36ae47d019b8015595b0adad2a4568b9821b299
parent 288934 1114b55d0da25b717aa02c7a4d9fc9b0efb53bf1
child 288936 6dbf14f1dc41bd5c7e9436a5e89d9f57701884a1
push id30093
push userkwierso@gmail.com
push dateWed, 16 Mar 2016 23:33:15 +0000
treeherdermozilla-central@20218dd51efa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1256088
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1256088 - Merge mock app-info implementation into AppInfo.jsm. r=gps
browser/components/places/tests/unit/head_bookmarks.js
browser/components/sessionstore/test/unit/test_backup_once.js
browser/components/sessionstore/test/unit/test_shutdown_cleanup.js
browser/experiments/test/xpcshell/head.js
browser/experiments/test/xpcshell/test_conditions.js
browser/modules/test/unit/social/head.js
chrome/test/unit/test_abi.js
chrome/test/unit/test_bug380398.js
chrome/test/unit/test_bug397073.js
chrome/test/unit/test_bug399707.js
chrome/test/unit/test_bug401153.js
chrome/test/unit/test_no_remote_registration.js
dom/plugins/test/unit/test_nice_plugin_name.js
js/xpconnect/tests/unit/test_xpcomutils.js
security/manager/ssl/tests/unit/test_cert_blocklist.js
services/common/tests/unit/head_global.js
services/crypto/tests/unit/head_helpers.js
services/mobileid/tests/xpcshell/head.js
services/sync/tests/unit/head_appinfo.js
testing/modules/AppInfo.jsm
toolkit/components/search/tests/xpcshell/head_search.js
toolkit/components/search/tests/xpcshell/test_json_cache.js
toolkit/components/social/test/xpcshell/head.js
toolkit/components/startup/tests/unit/head_startup.js
toolkit/components/telemetry/tests/unit/head.js
toolkit/components/telemetry/tests/unit/test_TelemetryController.js
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js
toolkit/components/urlformatter/tests/unit/head_urlformatter.js
toolkit/components/urlformatter/tests/unit/test_urlformatter.js
toolkit/modules/tests/xpcshell/test_Services.js
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -24,46 +24,23 @@ XPCOMUtils.defineLazyGetter(this, "Place
   Cu.import("resource:///modules/PlacesUIUtils.jsm");
   return PlacesUIUtils;
 });
 
 const ORGANIZER_FOLDER_ANNO = "PlacesOrganizer/OrganizerFolder";
 const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery";
 
 // Needed by some test that relies on having an app registered.
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "PlacesTest",
   ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}",
   version: "1",
-  appBuildID: "2007010101",
   platformVersion: "",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIXULAppInfo,
-    Ci.nsIXULRuntime,
-  ])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
+});
 
 // Smart bookmarks constants.
 const SMART_BOOKMARKS_VERSION = 7;
 const SMART_BOOKMARKS_ON_TOOLBAR = 1;
 const SMART_BOOKMARKS_ON_MENU =  3; // Takes into account the additional separator.
 
 // Default bookmarks constants.
 const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1;
--- a/browser/components/sessionstore/test/unit/test_backup_once.js
+++ b/browser/components/sessionstore/test/unit/test_backup_once.js
@@ -8,46 +8,23 @@ var {XPCOMUtils} = Cu.import("resource:/
 var {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 var {SessionWorker} = Cu.import("resource:///modules/sessionstore/SessionWorker.jsm", {});
 
 var File = OS.File;
 var Paths;
 var SessionFile;
 
 // We need a XULAppInfo to initialize SessionFile
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "SessionRestoreTest",
   ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}",
   version: "1",
-  appBuildID: "2007010101",
   platformVersion: "",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIXULAppInfo,
-    Ci.nsIXULRuntime,
-  ])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
+});
 
 function run_test() {
   run_next_test();
 }
 
 add_task(function* init() {
   // Make sure that we have a profile before initializing SessionFile
   let profd = do_get_profile();
--- a/browser/components/sessionstore/test/unit/test_shutdown_cleanup.js
+++ b/browser/components/sessionstore/test/unit/test_shutdown_cleanup.js
@@ -17,47 +17,23 @@ const {Paths} = SessionFile;
 
 const {OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
 const {File} = OS;
 
 const MAX_ENTRIES = 9;
 const URL = "http://example.com/#";
 
 // We need a XULAppInfo to initialize SessionFile
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "SessionRestoreTest",
   ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}",
   version: "1",
-  appBuildID: "2007010101",
   platformVersion: "",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIXULAppInfo,
-    Ci.nsIXULRuntime,
-  ])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
+});
 
 add_task(function* setup() {
   let source = do_get_file("data/sessionstore_valid.js");
   source.copyTo(profd, "sessionstore.js");
 
   // Finish SessionFile initialization.
   yield SessionFile.read();
 
--- a/browser/experiments/test/xpcshell/head.js
+++ b/browser/experiments/test/xpcshell/head.js
@@ -60,18 +60,16 @@ const EXPERIMENT1A_XPI_SHA1 = "sha1:" + 
 const EXPERIMENT2_ID       = "test-experiment-2@tests.mozilla.org"
 const EXPERIMENT2_XPI_NAME = "experiment-2.xpi";
 const EXPERIMENT2_PATH     = getExperimentPath(EXPERIMENT2_XPI_NAME);
 const EXPERIMENT2_XPI_SHA1 = "sha1:" + sha1File(EXPERIMENT2_PATH);
 
 const EXPERIMENT3_ID       = "test-experiment-3@tests.mozilla.org";
 const EXPERIMENT4_ID       = "test-experiment-4@tests.mozilla.org";
 
-const DEFAULT_BUILDID      = "2014060601";
-
 const FAKE_EXPERIMENTS_1 = [
   {
     id: "id1",
     name: "experiment1",
     description: "experiment 1",
     active: true,
     detailUrl: "https://dummy/experiment1",
     branch: "foo",
@@ -157,73 +155,25 @@ function getExperimentAddons(previous=fa
     } else {
       deferred.resolve(addons.filter(a => !a.appDisabled));
     }
   });
 
   return deferred.promise;
 }
 
-function createAppInfo(optionsIn) {
-  const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
-  const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
-
-  let options = optionsIn || {};
-  let id = options.id || "xpcshell@tests.mozilla.org";
-  let name = options.name || "XPCShell";
-  let version = options.version || "1.0";
-  let platformVersion = options.platformVersion || "1.0";
-  let date = options.date || new Date();
-
-  let buildID = options.buildID || DEFAULT_BUILDID;
-
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: buildID,
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: buildID,
-
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
-
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
-
-  let XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null) {
-        throw Cr.NS_ERROR_NO_AGGREGATION;
-      }
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-
-  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+function createAppInfo(ID="xpcshell@tests.mozilla.org", name="XPCShell",
+                       version="1.0", platformVersion="1.0") {
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 /**
  * Replace the experiments on an Experiments with a new list.
  *
  * This monkeypatches getExperiments(). It doesn't monkeypatch the internal
  * experiments list. So its utility is not as great as it could be.
  */
--- a/browser/experiments/test/xpcshell/test_conditions.js
+++ b/browser/experiments/test/xpcshell/test_conditions.js
@@ -88,16 +88,43 @@ const sanityFilter = function filter(c) 
     throw Error("No .telemetryEnvironment");
   }
   if (c.telemetryEnvironment.build == undefined) {
     throw Error("No .telemetryEnvironment.build");
   }
   return true;
 }
 
+// Utility function to generate build ID for previous/next date.
+function addDate(buildId, diff) {
+  let m = /^([0-9]{4})([0-9]{2})([0-9]{2})(.*)$/.exec(buildId);
+  if (!m) {
+    throw Error("Unsupported build ID: " + buildId);
+  }
+  let year = Number.parseInt(m[1], 10);
+  let month = Number.parseInt(m[2], 10);
+  let date = Number.parseInt(m[3], 10);
+  let remainingParts = m[4];
+
+  let d = new Date();
+  d.setUTCFullYear(year, month - 1, date);
+  d.setTime(d.getTime() + diff * 24 * 60 * 60 * 1000);
+
+  let yearStr = String(d.getUTCFullYear());
+  let monthStr = ("0" + String(d.getUTCMonth() + 1)).slice(-2);
+  let dateStr = ("0" + String(d.getUTCDate())).slice(-2);
+  return yearStr + monthStr + dateStr + remainingParts;
+}
+function prevDate(buildId) {
+  return addDate(buildId, -1);
+}
+function nextDate(buildId) {
+  return addDate(buildId, 1);
+}
+
 add_task(function* test_simpleFields() {
   let testData = [
     // "expected applicable?", failure reason or null, manifest data
 
     // misc. environment
 
     [false, ["appName"], {appName: []}],
     [false, ["appName"], {appName: ["foo", gAppInfo.name + "-invalid"]}],
@@ -133,23 +160,23 @@ add_task(function* test_simpleFields() {
     [true,  ["maxVersion"], {maxVersion: "1.7pre"}],
 
     // build id
 
     [false, ["buildIDs"], {buildIDs: []}],
     [false, ["buildIDs"], {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID + "-invalid"]}],
     [true,  null,         {buildIDs: ["not-a-build-id", gAppInfo.platformBuildID]}],
 
-    [true,  null,           {minBuildID: "2014060501"}],
-    [true,  null,           {minBuildID: "2014060601"}],
-    [false, ["minBuildID"], {minBuildID: "2014060701"}],
+    [true,  null,           {minBuildID: prevDate(gAppInfo.platformBuildID)}],
+    [true,  null,           {minBuildID: gAppInfo.platformBuildID}],
+    [false, ["minBuildID"], {minBuildID: nextDate(gAppInfo.platformBuildID)}],
 
-    [false, ["maxBuildID"], {maxBuildID: "2014010101"}],
-    [true,  null,           {maxBuildID: "2014060601"}],
-    [true,  null,           {maxBuildID: "2014060901"}],
+    [false, ["maxBuildID"], {maxBuildID: prevDate(gAppInfo.platformBuildID)}],
+    [true,  null,           {maxBuildID: gAppInfo.platformBuildID}],
+    [true,  null,           {maxBuildID: nextDate(gAppInfo.platformBuildID)}],
 
     // sample
 
     [false, ["sample"], {sample: -1 }],
     [false, ["sample"], {sample: 0.0}],
     [false, ["sample"], {sample: 0.1}],
     [true,  null,       {sample: 0.5}],
     [true,  null,       {sample: 0.6}],
--- a/browser/modules/test/unit/social/head.js
+++ b/browser/modules/test/unit/social/head.js
@@ -23,62 +23,24 @@ var manifests = [
 
 const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
 
 // SocialProvider class relies on blocklisting being enabled.  To enable
 // blocklisting, we have to setup an app and initialize the blocklist (see
 // initApp below).
 const gProfD = do_get_profile();
 
-const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
-const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
-
-function createAppInfo(id, name, version, platformVersion) {
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: "2007010101",
-
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
-
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
-
-  var XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null)
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-  var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+function createAppInfo(ID, name, version, platformVersion="1.0") {
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 function initApp() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
   // prepare a blocklist file for the blocklist service
   var blocklistFile = gProfD.clone();
   blocklistFile.append("blocklist.xml");
   if (blocklistFile.exists())
--- a/chrome/test/unit/test_abi.js
+++ b/chrome/test/unit/test_abi.js
@@ -1,46 +1,15 @@
-const XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo)
-     || iid.equals(Ci.nsIXULRuntime)
-     || iid.equals(Ci.nsISupports))
-      return this;
-  
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-const XULAppInfoFactory = {
-  // These two are used when we register all our factories (and unregister)
-  CID: XULAPPINFO_CID,
-  scheme: "XULAppInfo",
-  contractID: XULAPPINFO_CONTRACTID,
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+});
 
 registerManifests([do_get_file("data/test_abi.manifest")]);
 
 const catman = Components.classes["@mozilla.org/categorymanager;1"].
   getService(Components.interfaces.nsICategoryManager);
 
 function is_registered(name) {
   try {
--- a/chrome/test/unit/test_bug380398.js
+++ b/chrome/test/unit/test_bug380398.js
@@ -5,49 +5,23 @@
 
 
 var MANIFESTS = [
   do_get_file("data/test_bug380398.manifest")
 ];
 
 registerManifests(MANIFESTS);
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
-  ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
+  id: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo)
-     || iid.equals(Ci.nsIXULRuntime)
-     || iid.equals(Ci.nsISupports))
-      return this;
-  
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+});
 
 var gIOS = Cc["@mozilla.org/network/io-service;1"]
             .getService(Ci.nsIIOService);
 var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                  .getService(Ci.nsIChromeRegistry);
 chromeReg.checkForNewChrome();
 
 var target = gIOS.newFileURI(do_get_file("data"));
--- a/chrome/test/unit/test_bug397073.js
+++ b/chrome/test/unit/test_bug397073.js
@@ -5,49 +5,23 @@
 
 var MANIFESTS = [
   do_get_file("data/test_bug397073.manifest")
 ];
 
 
 registerManifests(MANIFESTS);
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo)
-     || iid.equals(Ci.nsIXULRuntime)
-     || iid.equals(Ci.nsISupports))
-      return this;
-  
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+});
 
 var gIOS = Cc["@mozilla.org/network/io-service;1"]
             .getService(Ci.nsIIOService);
 var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                  .getService(Ci.nsIChromeRegistry);
 chromeReg.checkForNewChrome();
 
 var target = gIOS.newFileURI(do_get_file("data"));
--- a/chrome/test/unit/test_bug399707.js
+++ b/chrome/test/unit/test_bug399707.js
@@ -4,49 +4,23 @@
  */
 
 var MANIFESTS = [
   do_get_file("data/test_bug399707.manifest")
 ];
 
 registerManifests(MANIFESTS);
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo)
-     || iid.equals(Ci.nsIXULRuntime)
-     || iid.equals(Ci.nsISupports))
-      return this;
-  
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+});
 
 var gIOS = Cc["@mozilla.org/network/io-service;1"]
             .getService(Ci.nsIIOService);
 var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                  .getService(Ci.nsIChromeRegistry);
 chromeReg.checkForNewChrome();
 
 var target = gIOS.newFileURI(do_get_file("data"));
--- a/chrome/test/unit/test_bug401153.js
+++ b/chrome/test/unit/test_bug401153.js
@@ -4,49 +4,23 @@
  */
 
 var MANIFESTS = [
   do_get_file("data/test_bug401153.manifest")
 ];
 
 registerManifests(MANIFESTS);
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo)
-     || iid.equals(Ci.nsIXULRuntime)
-     || iid.equals(Ci.nsISupports))
-      return this;
-  
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+});
 
 var gIOS = Cc["@mozilla.org/network/io-service;1"]
             .getService(Ci.nsIIOService);
 var chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
                  .getService(Ci.nsIChromeRegistry);
 chromeReg.checkForNewChrome();
 
 var rph = gIOS.getProtocolHandler("resource")
--- a/chrome/test/unit/test_no_remote_registration.js
+++ b/chrome/test/unit/test_no_remote_registration.js
@@ -6,39 +6,29 @@
 
 var manifests = [
   do_get_file("data/test_no_remote_registration.manifest"),
 ];
 registerManifests(manifests);
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Components.utils.import("resource://testing-common/AppInfo.jsm", this);
+var XULAppInfo = newAppInfo({
   name: "XPCShell",
   ID: "{39885e5f-f6b4-4e2a-87e5-6259ecf79011}",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIXULAppInfo,
-    Ci.nsIXULRuntime,
-  ])
-};
+});
 
 var XULAppInfoFactory = {
   // These two are used when we register all our factories (and unregister)
-  CID: XULAPPINFO_CID,
+  CID: Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"),
   scheme: "XULAppInfo",
-  contractID: XULAPPINFO_CONTRACTID,
+  contractID: "@mozilla.org/xre/app-info;1",
   createInstance: function (outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return XULAppInfo.QueryInterface(iid);
   }
 };
 
 function ProtocolHandler(aScheme, aFlags)
--- a/dom/plugins/test/unit/test_nice_plugin_name.js
+++ b/dom/plugins/test/unit/test_nice_plugin_name.js
@@ -6,59 +6,24 @@
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 var gAppInfo = null;
 
-function createAppInfo(id, name, version, platformVersion) {
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: "2007010101",
-
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
-
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
-
-  let XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null)
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+function createAppInfo(ID, name, version, platformVersion="1.0") {
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 var gPluginHost = null;
 
 function test_expected_permission_string(aPermString) {
   gPluginHost.reloadPlugins(false);
   let plugin = get_test_plugintag();
   do_check_false(plugin == null);
--- a/js/xpconnect/tests/unit/test_xpcomutils.js
+++ b/js/xpconnect/tests/unit/test_xpcomutils.js
@@ -118,33 +118,24 @@ add_test(function test_defineLazyService
 
 add_test(function test_categoryRegistration()
 {
   const CATEGORY_NAME = "test-cat";
   const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
   const XULAPPINFO_CID = Components.ID("{fc937916-656b-4fb3-a395-8c63569e27a8}");
 
   // Create a fake app entry for our category registration apps filter.
-  let XULAppInfo = {
-    vendor: "Mozilla",
+  let tmp = {};
+  Components.utils.import("resource://testing-common/AppInfo.jsm", tmp);
+  let XULAppInfo = tmp.newAppInfo({
     name: "catRegTest",
     ID: "{adb42a9a-0d19-4849-bf4d-627614ca19be}",
     version: "1",
-    appBuildID: "2007010101",
     platformVersion: "",
-    platformBuildID: "2007010101",
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    QueryInterface: XPCOMUtils.generateQI([
-      Ci.nsIXULAppInfo,
-      Ci.nsIXULRuntime,
-    ])
-  };
+  });
   let XULAppInfoFactory = {
     createInstance: function (outer, iid) {
       if (outer != null)
         throw Cr.NS_ERROR_NO_AGGREGATION;
       return XULAppInfo.QueryInterface(iid);
     }
   };
   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
--- a/security/manager/ssl/tests/unit/test_cert_blocklist.js
+++ b/security/manager/ssl/tests/unit/test_cert_blocklist.js
@@ -11,57 +11,24 @@
 // * it does a sanity check to ensure other cert verifier behavior is
 //   unmodified
 
 // First, we need to setup appInfo for the blocklist service to work
 var id = "xpcshell@tests.mozilla.org";
 var appName = "XPCShell";
 var version = "1";
 var platformVersion = "1.9.2";
-var appInfo = {
-  // nsIXULAppInfo
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: appName,
   ID: id,
   version: version,
-  appBuildID: "2007010101",
   platformVersion: platformVersion ? platformVersion : "1.0",
-  platformBuildID: "2007010101",
-
-  // nsIXULRuntime
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-    // Do nothing
-  },
-
-  // nsICrashReporter
-  annotations: {},
-
-  annotateCrashReport: function(key, data) {
-    this.annotations[key] = data;
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                         Ci.nsIXULRuntime,
-                                         Ci.nsICrashReporter,
-                                         Ci.nsISupports])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    appInfo.QueryInterface(iid);
-    if (outer != null) {
-      throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
-    }
-    return appInfo.QueryInterface(iid);
-  }
-};
+  crashReporter: true,
+});
 
 // we need to ensure we setup revocation data before certDB, or we'll start with
 // no revocation.txt in the profile
 var profile = do_get_profile();
 
 // Write out an empty blocklist.xml file to the profile to ensure nothing
 // is blocklisted by default
 var blockFile = profile.clone();
@@ -73,23 +40,18 @@ stream.init(blockFile,
   FileUtils.PERMS_FILE, 0);
 
 var data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<blocklist xmlns=\"http://www.mozilla.org/2006/addons-blocklist\">\n" +
            "</blocklist>\n";
 stream.write(data, data.length);
 stream.close();
 
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
-const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
 const PREF_KINTO_UPDATE_ENABLED = "services.kinto.update_enabled";
 const PREF_ONECRL_VIA_AMO = "security.onecrl.via.amo";
-registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                          XULAPPINFO_CONTRACTID, XULAppInfoFactory);
 
 var revocations = profile.clone();
 revocations.append("revocations.txt");
 if (!revocations.exists()) {
   let existing = do_get_file("test_onecrl/sample_revocations.txt", false);
   existing.copyTo(profile, "revocations.txt");
 }
 
--- a/services/common/tests/unit/head_global.js
+++ b/services/common/tests/unit/head_global.js
@@ -1,45 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = Components;
 
 var gSyncProfile = do_get_profile();
-
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "xpcshell@tests.mozilla.org",
   version: "1",
-  appBuildID: "20100621",
   platformVersion: "",
-  platformBuildID: "20100621",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime]),
-  invalidateCachesOnRestart: function invalidateCachesOnRestart() { }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
+});
 
 function addResourceAlias() {
   Cu.import("resource://gre/modules/Services.jsm");
   const handler = Services.io.getProtocolHandler("resource")
                   .QueryInterface(Ci.nsIResProtocolHandler);
 
   let modules = ["common", "crypto"];
   for (let module of modules) {
--- a/services/crypto/tests/unit/head_helpers.js
+++ b/services/crypto/tests/unit/head_helpers.js
@@ -15,44 +15,24 @@ catch(ex) {
 var OS = "XPCShell";
 if (mozinfo.os == "win")
   OS = "WINNT";
 else if (mozinfo.os == "mac")
   OS = "Darwin";
 else
   OS = "Linux";
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "{3e3ba16c-1675-4e88-b9c8-afef81b3d2ef}",
   version: "1",
-  appBuildID: "20100621",
   platformVersion: "",
-  platformBuildID: "20100621",
-  inSafeMode: false,
-  logConsoleErrors: true,
   OS: OS,
-  XPCOMABI: "noarch-spidermonkey",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
-
+});
 }
 
 // Register resource alias. Normally done in SyncComponents.manifest.
 function addResourceAlias() {
   Cu.import("resource://gre/modules/Services.jsm");
   const resProt = Services.io.getProtocolHandler("resource")
                           .QueryInterface(Ci.nsIResProtocolHandler);
   let uri = Services.io.newURI("resource://gre/modules/services-crypto/",
--- a/services/mobileid/tests/xpcshell/head.js
+++ b/services/mobileid/tests/xpcshell/head.js
@@ -425,43 +425,15 @@ var MobileIdentityUIGlue = {
     .registerFactory(Components.ID(kMobileIdentityUIGlueUUID),
                      "MobileIdentityUIGlue",
                      kMobileIdentityUIGlueContractID,
                      fakeMobileIdentityUIGlueFactory);
 })();
 
 // The tests rely on having an app registered. Otherwise, it will throw.
 // Override XULAppInfo.
-const XUL_APP_INFO_UUID = Components.ID("{84fdc459-d96d-421c-9bff-a8193233ae75}");
-const XUL_APP_INFO_CONTRACT_ID = "@mozilla.org/xre/app-info;1";
-
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "MobileIdTest",
   ID: "{230de50e-4cd1-11dc-8314-0800200b9a66}",
   version: "1",
-  appBuildID: "2007010101",
   platformVersion: "",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsIXULAppInfo,
-    Ci.nsIXULRuntime,
-  ])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-Cm.QueryInterface(Ci.nsIComponentRegistrar)
-  .registerFactory(XUL_APP_INFO_UUID,
-                   "XULAppInfo",
-                   XUL_APP_INFO_CONTRACT_ID,
-                   XULAppInfoFactory);
+});
--- a/services/sync/tests/unit/head_appinfo.js
+++ b/services/sync/tests/unit/head_appinfo.js
@@ -24,45 +24,24 @@ function getOS() {
       return "WINNT";
     case "mac":
       return "Darwin";
     default:
       return "Linux";
   }
 }
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "XPCShell",
   ID: "xpcshell@tests.mozilla.org",
   version: "1",
-  appBuildID: "20100621",
   platformVersion: "",
-  platformBuildID: "20100621",
-  inSafeMode: false,
-  logConsoleErrors: true,
   OS: getOS(),
-  XPCOMABI: "noarch-spidermonkey",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime]),
-  invalidateCachesOnRestart: function invalidateCachesOnRestart() { }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
-
+});
 
 // Register resource aliases. Normally done in SyncComponents.manifest.
 function addResourceAlias() {
   const resProt = Services.io.getProtocolHandler("resource")
                           .QueryInterface(Ci.nsIResProtocolHandler);
   for (let s of ["common", "sync", "crypto"]) {
     let uri = Services.io.newURI("resource://gre/modules/services-" + s + "/", null,
                                  null);
--- a/testing/modules/AppInfo.jsm
+++ b/testing/modules/AppInfo.jsm
@@ -1,72 +1,111 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = [
+  "newAppInfo",
   "getAppInfo",
   "updateAppInfo",
 ];
 
 
-const {interfaces: Ci, results: Cr, utils: Cu} = Components;
+const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-var APP_INFO = {
-  vendor: "Mozilla",
-  name: "xpcshell",
-  ID: "xpcshell@tests.mozilla.org",
-  version: "1",
-  appBuildID: "20121107",
-  platformVersion: "p-ver",
-  platformBuildID: "20121106",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
+/**
+ * Create new XULAppInfo instance with specified options.
+ *
+ * options is a object with following keys:
+ *   ID:              nsIXULAppInfo.ID
+ *   name:            nsIXULAppInfo.name
+ *   version:         nsIXULAppInfo.version
+ *   platformVersion: nsIXULAppInfo.platformVersion
+ *   OS:              nsIXULRuntime.OS
+ *
+ *   crashReporter:   nsICrashReporter interface is implemented if true
+ *   extraProps:      extra properties added to XULAppInfo
+ */
+this.newAppInfo = function (options={}) {
+  let ID = ("ID" in options) ? options.ID : "xpcshell@tests.mozilla.org";
+  let name = ("name" in options) ? options.name : "xpcshell";
+  let version = ("version" in options) ? options.version : "1";
+  let platformVersion
+      = ("platformVersion" in options) ? options.platformVersion : "p-ver";
+  let OS = ("OS" in options) ? options.OS : "XPCShell";
+  let extraProps = ("extraProps" in options) ? options.extraProps : {};
+
+  let appInfo = {
+    // nsIXULAppInfo
+    vendor: "Mozilla",
+    name: name,
+    ID: ID,
+    version: version,
+    appBuildID: "20160315",
+    platformVersion: platformVersion,
+    platformBuildID: "20160316",
 
-  invalidateCachesOnRestart() {},
+    // nsIXULRuntime
+    inSafeMode: false,
+    logConsoleErrors: true,
+    OS: OS,
+    XPCOMABI: "noarch-spidermonkey",
+    invalidateCachesOnRestart() {},
 
-  // nsIWinAppHelper
-  get userCanElevate() {
-    return false;
-  },
+    // nsIWinAppHelper
+    get userCanElevate() {
+      return false;
+    },
+  };
 
-  QueryInterface(iid) {
-    let interfaces = [ Ci.nsIXULAppInfo, Ci.nsIXULRuntime ];
-    if ("nsIWinAppHelper" in Ci)
-      interfaces.push(Ci.nsIWinAppHelper);
-    if (!interfaces.some(v => iid.equals(v)))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
+  let interfaces = [Ci.nsIXULAppInfo,
+                    Ci.nsIXULRuntime];
+  if ("nsIWinAppHelper" in Ci) {
+    interfaces.push(Ci.nsIWinAppHelper);
   }
+
+  if ("crashReporter" in options && options.crashReporter) {
+    // nsICrashReporter
+    appInfo.annotations = {};
+    appInfo.annotateCrashReport = function(key, data) {
+      this.annotations[key] = data;
+    };
+    interfaces.push(Ci.nsICrashReporter);
+  }
+
+  for (let key of Object.keys(extraProps)) {
+    appInfo.browserTabsRemoteAutostart = extraProps[key];
+  }
+
+  appInfo.QueryInterface = XPCOMUtils.generateQI(interfaces);
+
+  return appInfo;
 };
 
+var currentAppInfo = newAppInfo();
 
 /**
  * Obtain a reference to the current object used to define XULAppInfo.
  */
-this.getAppInfo = function () { return APP_INFO; }
+this.getAppInfo = function () { return currentAppInfo; };
 
 /**
  * Update the current application info.
  *
- * If the argument is defined, it will be the object used. Else, APP_INFO is
- * used.
+ * See newAppInfo for options.
  *
  * To change the current XULAppInfo, simply call this function. If there was
  * a previously registered app info object, it will be unloaded and replaced.
  */
-this.updateAppInfo = function (obj) {
-  obj = obj || APP_INFO;
-  APP_INFO = obj;
+this.updateAppInfo = function (options) {
+  currentAppInfo = newAppInfo(options);
 
   let id = Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}");
   let cid = "@mozilla.org/xre/app-info;1";
   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 
   // Unregister an existing factory if one exists.
   try {
     let existing = Components.manager.getClassObjectByContractID(cid, Ci.nsIFactory);
@@ -74,15 +113,15 @@ this.updateAppInfo = function (obj) {
   } catch (ex) {}
 
   let factory = {
     createInstance: function (outer, iid) {
       if (outer != null) {
         throw Cr.NS_ERROR_NO_AGGREGATION;
       }
 
-      return obj.QueryInterface(iid);
+      return currentAppInfo.QueryInterface(iid);
     },
   };
 
   registrar.registerFactory(id, "XULAppInfo", cid, factory);
 };
 
--- a/toolkit/components/search/tests/xpcshell/head_search.js
+++ b/toolkit/components/search/tests/xpcshell/head_search.js
@@ -22,50 +22,30 @@ const MODE_CREATE = FileUtils.MODE_CREAT
 const MODE_TRUNCATE = FileUtils.MODE_TRUNCATE;
 
 const CACHE_FILENAME = "search.json.mozlz4";
 
 // nsSearchService.js uses Services.appinfo.name to build a salt for a hash.
 var XULRuntime = Components.classesByID["{95d89e3e-a169-41a3-8e56-719978e15b12}"]
                            .getService(Ci.nsIXULRuntime);
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+var isChild = XULRuntime.processType == XULRuntime.PROCESS_TYPE_CONTENT;
+
+updateAppInfo({
   name: "XPCShell",
   ID: "xpcshell@test.mozilla.org",
   version: "5",
-  appBuildID: "2007010101",
   platformVersion: "1.9",
-  platformBuildID: "2007010101",
-  inSafeMode: false,
-  logConsoleErrors: true,
   // mirror OS from the base impl as some of the "location" tests rely on it
   OS: XULRuntime.OS,
-  XPCOMABI: "noarch-spidermonkey",
   // mirror processType from the base implementation
-  processType: XULRuntime.processType,
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo, Ci.nsIXULRuntime,
-                                         Ci.nsISupports])
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var isChild = XULRuntime.processType == XULRuntime.PROCESS_TYPE_CONTENT;
-
-Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
-          .registerFactory(Components.ID("{ecff8849-cee8-40a7-bd4a-3f4fdfeddb5c}"),
-                           "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                           XULAppInfoFactory);
+  extraProps: {
+    processType: XULRuntime.processType,
+  },
+});
 
 var gProfD;
 if (!isChild) {
   // Need to create and register a profile folder.
   gProfD = do_get_profile();
 }
 
 function dumpn(text)
--- a/toolkit/components/search/tests/xpcshell/test_json_cache.js
+++ b/toolkit/components/search/tests/xpcshell/test_json_cache.js
@@ -37,16 +37,17 @@ var cacheTemplate, appPluginsPath, profP
 function run_test() {
   removeMetadata();
   removeCacheFile();
 
   updateAppInfo();
 
   let cacheTemplateFile = do_get_file("data/search.json");
   cacheTemplate = readJSONFile(cacheTemplateFile);
+  cacheTemplate.buildID = getAppInfo().platformBuildID;
 
   let engineFile = gProfD.clone();
   engineFile.append("searchplugins");
   engineFile.append("test-search-engine.xml");
   engineFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
   // Copy the test engine to the test profile.
   let engineTemplateFile = do_get_file("data/engine.xml");
--- a/toolkit/components/social/test/xpcshell/head.js
+++ b/toolkit/components/social/test/xpcshell/head.js
@@ -12,59 +12,26 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/PlacesUtils.jsm");
 
 const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
 const gProfD = do_get_profile();
 
 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
 
-function createAppInfo(id, name, version, platformVersion) {
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: "2007010101",
-
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
+var gAppInfo = null;
 
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
-
-  var XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null)
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-  var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+function createAppInfo(ID, name, version, platformVersion="1.0") {
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 function initApp() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
   // prepare a blocklist file for the blocklist service
   var blocklistFile = gProfD.clone();
   blocklistFile.append("blocklist.xml");
   if (blocklistFile.exists())
--- a/toolkit/components/startup/tests/unit/head_startup.js
+++ b/toolkit/components/startup/tests/unit/head_startup.js
@@ -3,55 +3,28 @@
 
 const XULRUNTIME_CONTRACTID = "@mozilla.org/xre/runtime;1";
 const XULRUNTIME_CID = Components.ID("7685dac8-3637-4660-a544-928c5ec0e714}");
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var gAppInfo = null;
 
-function createAppInfo(id, name, version, platformVersion) {
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: "2007010101",
-
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
+function createAppInfo(ID, name, version, platformVersion="1.0") {
+  let tmp = {};
+  Components.utils.import("resource://testing-common/AppInfo.jsm", tmp);
+  gAppInfo = tmp.newAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
     replacedLockTime: 0,
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
-
-    // nsICrashReporter
-    annotations: {
-    },
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
+  });
 
   let XULAppInfoFactory = {
     createInstance: function (outer, iid) {
       if (outer != null)
         throw Components.results.NS_ERROR_NO_AGGREGATION;
       return gAppInfo.QueryInterface(iid);
     }
   };
   let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
   registrar.registerFactory(XULRUNTIME_CID, "XULRuntime",
                             XULRUNTIME_CONTRACTID, XULAppInfoFactory);
-
 }
--- a/toolkit/components/telemetry/tests/unit/head.js
+++ b/toolkit/components/telemetry/tests/unit/head.js
@@ -21,17 +21,16 @@ const Telemetry = Cc["@mozilla.org/base/
 const MILLISECONDS_PER_MINUTE = 60 * 1000;
 const MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
 const MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
 
 const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
 
 const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
 
-var gOldAppInfo = null;
 var gGlobalScope = this;
 
 const PingServer = {
   _httpServer: null,
   _started: false,
   _defers: [ PromiseUtils.defer() ],
   _currentDeferred: 0,
 
@@ -153,83 +152,41 @@ function wrapWithExceptionHandler(f) {
       dump("Caught exception: " + ex.message + "\n");
       dump(ex.stack);
       do_test_finished();
     }
   }
   return wrapper;
 }
 
-function loadAddonManager(id, name, version, platformVersion) {
+function loadAddonManager(ID, name, version, platformVersion) {
   let ns = {};
   Cu.import("resource://gre/modules/Services.jsm", ns);
   let head = "../../../../mozapps/extensions/test/xpcshell/head_addons.js";
   let file = do_get_file(head);
   let uri = ns.Services.io.newFileURI(file);
   ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
-  createAppInfo(id, name, version, platformVersion);
+  createAppInfo(ID, name, version, platformVersion);
   // As we're not running in application, we need to setup the features directory
   // used by system add-ons.
   const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
   registerDirectory("XREAppFeat", distroDir);
   startupManager();
 }
 
-function createAppInfo(id, name, version, platformVersion) {
-  const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
-  const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
-  let gAppInfo;
-  if (!gOldAppInfo) {
-    gOldAppInfo = Cc[XULAPPINFO_CONTRACTID].getService(Ci.nsIXULRuntime);
-  }
-
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion,
-    platformBuildID: "2007010101",
+var gAppInfo = null;
 
-    // nsIXULRuntime
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
-    },
-
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
-                                           Ci.nsIXULRuntime,
-                                           Ci.nsICrashReporter,
-                                           Ci.nsISupports])
-  };
-
-  Object.setPrototypeOf(gAppInfo, gOldAppInfo);
-
-  var XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null)
-        throw Cr.NS_ERROR_NO_AGGREGATION;
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-  var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+function createAppInfo(ID, name, version, platformVersion) {
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 // Fake the timeout functions for the TelemetryScheduler.
 function fakeSchedulerTimer(set, clear) {
   let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
   session.Policy.setSchedulerTickTimeout = set;
   session.Policy.clearSchedulerTickTimeout = clear;
 }
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
@@ -50,17 +50,17 @@ function sendPing(aSendClientId, aSendEn
 }
 
 function checkPingFormat(aPing, aType, aHasClientId, aHasEnvironment) {
   const MANDATORY_PING_FIELDS = [
     "type", "id", "creationDate", "version", "application", "payload"
   ];
 
   const APPLICATION_TEST_DATA = {
-    buildId: "2007010101",
+    buildId: gAppInfo.appBuildID,
     name: APP_NAME,
     version: APP_VERSION,
     displayVersion: AppConstants.MOZ_APP_VERSION_DISPLAY,
     vendor: "Mozilla",
     platformVersion: PLATFORM_VERSION,
     xpcomAbi: "noarch-spidermonkey",
   };
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -305,17 +305,17 @@ function checkNullOrString(aValue) {
 function checkNullOrBool(aValue) {
   return aValue === null || (typeof aValue == "boolean");
 }
 
 function checkBuildSection(data) {
   const expectedInfo = {
     applicationId: APP_ID,
     applicationName: APP_NAME,
-    buildId: "2007010101",
+    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.");
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -151,17 +151,17 @@ function getSavedPingFile(basename) {
 }
 
 function checkPingFormat(aPing, aType, aHasClientId, aHasEnvironment) {
   const MANDATORY_PING_FIELDS = [
     "type", "id", "creationDate", "version", "application", "payload"
   ];
 
   const APPLICATION_TEST_DATA = {
-    buildId: "2007010101",
+    buildId: gAppInfo.appBuildID,
     name: APP_NAME,
     version: APP_VERSION,
     vendor: "Mozilla",
     platformVersion: PLATFORM_VERSION,
     xpcomAbi: "noarch-spidermonkey",
   };
 
   // Check that the ping contains all the mandatory fields.
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js
@@ -5,17 +5,17 @@ var Cu = Components.utils;
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/TelemetryController.jsm", this);
 Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
 // The @mozilla/xre/app-info;1 XPCOM object provided by the xpcshell test harness doesn't
-// implement the nsIAppInfo interface, which is needed by Services.jsm and
+// implement the nsIXULAppInfo interface, which is needed by Services.jsm and
 // TelemetrySession.jsm. updateAppInfo() creates and registers a minimal mock app-info.
 Cu.import("resource://testing-common/AppInfo.jsm");
 updateAppInfo();
 
 var gGlobalScope = this;
 function loadAddonManager() {
   let ns = {};
   Cu.import("resource://gre/modules/Services.jsm", ns);
--- a/toolkit/components/urlformatter/tests/unit/head_urlformatter.js
+++ b/toolkit/components/urlformatter/tests/unit/head_urlformatter.js
@@ -1,41 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cr = Components.results;
+var Cu = Components.utils;
 
-var XULAppInfo = {
-  vendor: "Mozilla",
+Cu.import("resource://testing-common/AppInfo.jsm", this);
+updateAppInfo({
   name: "Url Formatter Test",
   ID: "urlformattertest@test.mozilla.org",
   version: "1",
-  appBuildID: "2007122405",
   platformVersion: "2.0",
-  platformBuildID: "2007122406",
-  inSafeMode: false,
-  logConsoleErrors: true,
-  OS: "XPCShell",
-  XPCOMABI: "noarch-spidermonkey",
-
-  QueryInterface: function QueryInterface(iid) {
-    if (iid.equals(Ci.nsIXULAppInfo) ||
-        iid.equals(Ci.nsIXULRuntime) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
-};
-
-var XULAppInfoFactory = {
-  createInstance: function (outer, iid) {
-    if (outer != null)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return XULAppInfo.QueryInterface(iid);
-  }
-};
-
-var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-registrar.registerFactory(Components.ID("{ecff8849-cee8-40a7-bd4a-3f4fdfeddb5c}"),
-                          "XULAppInfo", "@mozilla.org/xre/app-info;1",
-                          XULAppInfoFactory);
+});
+var gAppInfo = getAppInfo();
--- a/toolkit/components/urlformatter/tests/unit/test_urlformatter.js
+++ b/toolkit/components/urlformatter/tests/unit/test_urlformatter.js
@@ -34,23 +34,23 @@ function run_test() {
   } catch (e) {}
   // Set distribution values.
   defaults.setCharPref("distribution.id", "bacon");
   defaults.setCharPref("distribution.version", "1.0");
 
   var upperUrlRaw = "http://%LOCALE%.%VENDOR%.foo/?name=%NAME%&id=%ID%&version=%VERSION%&platversion=%PLATFORMVERSION%&abid=%APPBUILDID%&pbid=%PLATFORMBUILDID%&app=%APP%&os=%OS%&abi=%XPCOMABI%";
   var lowerUrlRaw = "http://%locale%.%vendor%.foo/?name=%name%&id=%id%&version=%version%&platversion=%platformversion%&abid=%appbuildid%&pbid=%platformbuildid%&app=%app%&os=%os%&abi=%xpcomabi%";
   //XXX %APP%'s RegExp is not global, so it only replaces the first space
-  var ulUrlRef = "http://" + locale + ".Mozilla.foo/?name=Url Formatter Test&id=urlformattertest@test.mozilla.org&version=1&platversion=2.0&abid=2007122405&pbid=2007122406&app=urlformatter test&os=XPCShell&abi=" + abi;
+  var ulUrlRef = "http://" + locale + ".Mozilla.foo/?name=Url Formatter Test&id=urlformattertest@test.mozilla.org&version=1&platversion=2.0&abid=" + gAppInfo.appBuildID + "&pbid=" + gAppInfo.platformBuildID + "&app=urlformatter test&os=XPCShell&abi=" + abi;
   var multiUrl = "http://%VENDOR%.%VENDOR%.%NAME%.%VENDOR%.%NAME%";
   var multiUrlRef = "http://Mozilla.Mozilla.Url Formatter Test.Mozilla.Url Formatter Test";
   var encodedUrl = "https://%LOCALE%.%VENDOR%.foo/?q=%E3%82%BF%E3%83%96&app=%NAME%&ver=%PLATFORMVERSION%";
   var encodedUrlRef = "https://" + locale + ".Mozilla.foo/?q=%E3%82%BF%E3%83%96&app=Url Formatter Test&ver=2.0";
   var advancedUrl = "http://test.mozilla.com/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/";
-  var advancedUrlRef = "http://test.mozilla.com/Url Formatter Test/1/2007122405/XPCShell_" + abi + "/" + locale + "/" + channel + "/" + OSVersion + "/bacon/1.0/";
+  var advancedUrlRef = "http://test.mozilla.com/Url Formatter Test/1/" + gAppInfo.appBuildID + "/XPCShell_" + abi + "/" + locale + "/" + channel + "/" + OSVersion + "/bacon/1.0/";
 
   var pref = "xpcshell.urlformatter.test";
   var str = Cc["@mozilla.org/supports-string;1"].
             createInstance(Ci.nsISupportsString);
   str.data = upperUrlRaw;
   prefs.setComplexValue(pref, Ci.nsISupportsString, str);
 
   do_check_eq(formatter.formatURL(upperUrlRaw), ulUrlRef);
--- a/toolkit/modules/tests/xpcshell/test_Services.js
+++ b/toolkit/modules/tests/xpcshell/test_Services.js
@@ -72,39 +72,21 @@ function run_test()
     checkService("search", Ci.nsIBrowserSearchService);
   }
   if ("nsIAndroidBridge" in Ci) {
     checkService("androidBridge", Ci.nsIAndroidBridge);
   }
 
   // In xpcshell tests, the "@mozilla.org/xre/app-info;1" component implements
   // only the nsIXULRuntime interface, but not nsIXULAppInfo.  To test the
-  // service getter for the latter interface, we define a minimal mock factory
-  // that returns an object defining both interfaces.
-  let contractID = "@mozilla.org/xre/app-info;1";
-  let mockFactory = {
-    createInstance: function (aOuter, aIid) {
-      return {
-        QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULRuntime,
-                                               Ci.nsIXULAppInfo]),
-      }.QueryInterface(aIid);
-    }
-  };
-
-  let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
-  let cid = registrar.contractIDToCID(contractID);
-  let oldFactory = Components.manager.getClassObject(Cc[contractID],
-                                                     Ci.nsIFactory);
-  registrar.unregisterFactory(cid, oldFactory);
-  registrar.registerFactory(cid, "", contractID, mockFactory);
+  // service getter for the latter interface, load mock app-info.
+  let tmp = {};
+  Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo();
 
   // We need to reload the module to update the lazy getter.
   Cu.unload("resource://gre/modules/Services.jsm");
   Cu.import("resource://gre/modules/Services.jsm");
 
   checkService("appinfo", Ci.nsIXULAppInfo);
 
-  // Clean up.
-  registrar.unregisterFactory(cid, mockFactory);
-  registrar.registerFactory(cid, "", contractID, oldFactory);
-
   Cu.unload("resource://gre/modules/Services.jsm");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -1,17 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var AM_Cc = Components.classes;
 var AM_Ci = Components.interfaces;
+var AM_Cu = Components.utils;
 
-const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
-const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
 const CERTDB_CONTRACTID = "@mozilla.org/security/x509certdb;1";
 const CERTDB_CID = Components.ID("{fb0bbc5c-452e-4783-b32c-80124693d871}");
 
 const PREF_EM_CHECK_UPDATE_SECURITY   = "extensions.checkUpdateSecurity";
 const PREF_EM_STRICT_COMPATIBILITY    = "extensions.strictCompatibility";
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
 const PREF_GETADDONS_BYIDS               = "extensions.getAddons.get.url";
@@ -256,60 +255,27 @@ function isNightlyChannel() {
   try {
     channel = Services.prefs.getCharPref("app.update.channel");
   }
   catch (e) { }
 
   return channel != "aurora" && channel != "beta" && channel != "release" && channel != "esr";
 }
 
-function createAppInfo(id, name, version, platformVersion) {
-  gAppInfo = {
-    // nsIXULAppInfo
-    vendor: "Mozilla",
-    name: name,
-    ID: id,
-    version: version,
-    appBuildID: "2007010101",
-    platformVersion: platformVersion ? platformVersion : "1.0",
-    platformBuildID: "2007010101",
-
-    // nsIXULRuntime
-    browserTabsRemoteAutostart: false,
-    inSafeMode: false,
-    logConsoleErrors: true,
-    OS: "XPCShell",
-    XPCOMABI: "noarch-spidermonkey",
-    invalidateCachesOnRestart: function invalidateCachesOnRestart() {
-      // Do nothing
+function createAppInfo(ID, name, version, platformVersion="1.0") {
+  let tmp = {};
+  AM_Cu.import("resource://testing-common/AppInfo.jsm", tmp);
+  tmp.updateAppInfo({
+    ID, name, version, platformVersion,
+    crashReporter: true,
+    extraProps: {
+      browserTabsRemoteAutostart: false,
     },
-
-    // nsICrashReporter
-    annotations: {},
-
-    annotateCrashReport: function(key, data) {
-      this.annotations[key] = data;
-    },
-
-    QueryInterface: XPCOMUtils.generateQI([AM_Ci.nsIXULAppInfo,
-                                           AM_Ci.nsIXULRuntime,
-                                           AM_Ci.nsICrashReporter,
-                                           AM_Ci.nsISupports])
-  };
-
-  var XULAppInfoFactory = {
-    createInstance: function (outer, iid) {
-      if (outer != null)
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      return gAppInfo.QueryInterface(iid);
-    }
-  };
-  var registrar = Components.manager.QueryInterface(AM_Ci.nsIComponentRegistrar);
-  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
-                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
+  });
+  gAppInfo = tmp.getAppInfo();
 }
 
 function getManifestURIForBundle(file) {
   if (file.isDirectory()) {
     file.append("install.rdf");
     if (file.exists()) {
       return NetUtil.newURI(file);
     }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js
@@ -62,17 +62,18 @@ function pathHandler(metadata, response)
   // so do the same here.
   if ("@mozilla.org/xpcom/mac-utils;1" in Components.classes) {
     var macutils = Components.classes["@mozilla.org/xpcom/mac-utils;1"]
                              .getService(Components.interfaces.nsIMacUtils);
     if (macutils.isUniversalBinary)
       ABI += "-u-" + macutils.architecturesInBinary;
   }
   do_check_eq(metadata.queryString,
-              "xpcshell@tests.mozilla.org&1&XPCShell&1&2007010101&" +
+              "xpcshell@tests.mozilla.org&1&XPCShell&1&" +
+              gAppInfo.appBuildID + "&" +
               "XPCShell_" + ABI + "&locale&updatechannel&" +
               gOSVersion + "&1.9&distribution&distribution-version");
   gBlocklist.observe(null, "quit-application", "");
   gBlocklist.observe(null, "xpcom-shutdown", "");
   testserver.stop(do_test_finished);
 }
 
 function run_test() {