Bug 1460914 - [xpcshell] Use nsIPrefService.readUserPrefsFromFile to set prefs, r=ted
☠☠ backed out by ba1fcb7618ef ☠ ☠
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Thu, 25 Oct 2018 15:22:44 +0000
changeset 443144 9e438c55a2481de116f871a195d73666138cb3bb
parent 443143 dfa7c7907860d2b5841f85ae28c6b11edd8550aa
child 443145 a2161aab4e4ed8cf7cf69c1fc281e87915a561da
push id34942
push usercsabou@mozilla.com
push dateFri, 26 Oct 2018 21:55:19 +0000
treeherdermozilla-central@cffa05ba11d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1460914
milestone65.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 1460914 - [xpcshell] Use nsIPrefService.readUserPrefsFromFile to set prefs, r=ted This uses nsIPrefService.readUserPrefsFromFile to set preferences from a user.js passed in via the python harness. This allows us to use the profiles under testing/profiles like all the other harnesses and will make setting prefs in xpcshell easier to use and understand. Differential Revision: https://phabricator.services.mozilla.com/D9716
python/mozbuild/mozbuild/action/test_archive.py
testing/mozbase/mozprofile/mozprofile/profile.py
testing/profiles/profiles.json
testing/profiles/xpcshell/user.js
testing/xpcshell/head.js
testing/xpcshell/remotexpcshelltests.py
testing/xpcshell/runxpcshelltests.py
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -534,16 +534,22 @@ ARCHIVE_FILES = {
             'dest': 'xpcshell',
         },
         {
             'source': buildconfig.topobjdir,
             'base': 'build',
             'pattern': 'automation.py',
             'dest': 'xpcshell',
         },
+        {
+            'source': buildconfig.topsrcdir,
+            'base': 'testing/profiles',
+            'pattern': '**',
+            'dest': 'xpcshell/profile_data',
+        },
     ],
     'updater-dep': [
         {
             'source': buildconfig.topobjdir,
             'base': '_tests/updater-dep',
             'pattern': '**',
             'dest': 'updater-dep',
         },
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -116,16 +116,19 @@ class BaseProfile(object):
             path = os.path.join(other, basename)
             try:
                 prefs = Preferences.read_json(path)
             except ValueError:
                 prefs = Preferences.read_prefs(path, interpolation=interpolation)
             self.set_preferences(prefs, filename=basename)
 
         extension_dir = os.path.join(other, 'extensions')
+        if not os.path.isdir(extension_dir):
+            return
+
         for basename in os.listdir(extension_dir):
             path = os.path.join(extension_dir, basename)
 
             if self.addons.is_addon(path):
                 self._addons.append(path)
                 self.addons.install(path)
 
     @classmethod
--- a/testing/profiles/profiles.json
+++ b/testing/profiles/profiles.json
@@ -1,9 +1,10 @@
 {
     "mochitest": ["common", "unittest"],
     "profileserver": ["common", "unittest", "profileserver"],
     "raptor": ["common", "perf", "raptor"],
     "reftest": ["common", "reftest"],
     "talos": ["common", "perf"],
     "valgrind": ["common", "unittest"],
+    "xpcshell": ["xpcshell"],
     "web-platform-tests": ["common", "unittest", "web-platform"]
 }
new file mode 100644
--- /dev/null
+++ b/testing/profiles/xpcshell/user.js
@@ -0,0 +1,2 @@
+// Base preferences file used by the xpcshell harness
+/* globals user_pref */
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -7,17 +7,18 @@
 /*
  * This file contains common code that is loaded before each test file(s).
  * See http://developer.mozilla.org/en/docs/Writing_xpcshell-based_unit_tests
  * for more information.
  */
 
 /* defined by the harness */
 /* globals _HEAD_FILES, _HEAD_JS_PATH, _JSDEBUGGER_PORT, _JSCOV_DIR,
-    _MOZINFO_JS_PATH, _TEST_FILE, _TEST_NAME, _TESTING_MODULES_DIR:true */
+    _MOZINFO_JS_PATH, _TEST_FILE, _TEST_NAME, _TESTING_MODULES_DIR:true,
+    _PREFS_FILE */
 
 /* defined by XPCShellImpl.cpp */
 /* globals load, sendCommand */
 
 /* must be defined by tests using do_await_remote_message/do_send_remote_message */
 /* globals Cc, Ci */
 
 /* may be defined in test files */
@@ -1474,16 +1475,21 @@ function run_next_test() {
     // Close the previous test do_test_pending call.
     do_test_finished(_gRunningTest.name);
   }
 }
 
 try {
   // Set global preferences
   if (runningInParent) {
+    let prefsFile = Cc["@mozilla.org/file/local;1"]
+      .createInstance(Ci.nsIFile);
+    prefsFile.initWithPath(_PREFS_FILE);
+    _Services.prefs.readUserPrefsFromFile(prefsFile);
+
     // Always use network provider for geolocation tests
     // so we bypass the OSX dialog raised by the corelocation provider
     _Services.prefs.setBoolPref("geo.provider.testing", true);
 
     // We need to avoid hitting the network with certain components.
     _Services.prefs.setCharPref("media.gmp-manager.url.override", "http://%(server)s/dummy-gmp-manager.xml");
     _Services.prefs.setCharPref("media.gmp-manager.updateEnabled", false);
     _Services.prefs.setCharPref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -343,16 +343,25 @@ class XPCShellRemote(xpcshell.XPCShellTe
             "echo xpcw: xpcshell \"$@\"\n",
             "%s/xpcshell \"$@\"\n" % self.remoteBinDir])
         f.close()
         remoteWrapper = posixpath.join(self.remoteBinDir, "xpcw")
         self.device.push(localWrapper, remoteWrapper)
         self.device.chmod(remoteWrapper, root=True)
         os.remove(localWrapper)
 
+    def buildPrefsFile(self):
+        super(XPCShellRemote, self).buildPrefsFile()
+
+        remotePrefsFile = posixpath.join(self.remoteTestRoot, 'user.js')
+        self.device.push(self.prefsFile, remotePrefsFile)
+        self.device.chmod(remotePrefsFile, root=True)
+        os.remove(self.prefsFile)
+        self.prefsFile = remotePrefsFile
+
     def buildEnvironment(self):
         self.buildCoreEnvironment()
         self.setLD_LIBRARY_PATH()
         self.env["MOZ_LINKER_CACHE"] = self.remoteBinDir
         if self.options['localAPK'] and self.appRoot:
             self.env["GRE_HOME"] = self.appRoot
         self.env["XPCSHELL_TEST_PROFILE_DIR"] = self.profileDir
         self.env["TMPDIR"] = self.remoteTmpDir
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -71,16 +71,17 @@ if os.path.isdir(mozbase):
         sys.path.append(os.path.join(mozbase, package))
 
 from manifestparser import TestManifest
 from manifestparser.filters import chunk_by_slice, tags, pathprefix
 from mozlog import commandline
 import mozcrash
 import mozfile
 import mozinfo
+from mozprofile import Profile
 from mozrunner.utils import get_stack_fixer_function
 
 # --------------------------------------------------------------
 
 # TODO: perhaps this should be in a more generally shared location?
 # This regex matches all of the C0 and C1 control characters
 # (U+0000 through U+001F; U+007F; U+0080 through U+009F),
 # except TAB (U+0009), CR (U+000D), LF (U+000A) and backslash (U+005C).
@@ -151,16 +152,17 @@ class XPCShellTestThread(Thread):
         self._rootTempDir = kwargs.get('tempDir')
         self.cleanup_dir_list = kwargs.get('cleanup_dir_list')
         self.pStdout = kwargs.get('pStdout')
         self.pStderr = kwargs.get('pStderr')
         self.keep_going = kwargs.get('keep_going')
         self.log = kwargs.get('log')
         self.app_dir_key = kwargs.get('app_dir_key')
         self.interactive = kwargs.get('interactive')
+        self.prefsFile = kwargs.get('prefsFile')
 
         # only one of these will be set to 1. adding them to the totals in
         # the harness
         self.passCount = 0
         self.todoCount = 0
         self.failCount = 0
 
         # Context for output processing
@@ -397,17 +399,16 @@ class XPCShellTestThread(Thread):
         """
         headfiles = self.getHeadFiles(self.test_object)
         cmdH = ", ".join(['"' + f.replace('\\', '/') + '"'
                          for f in headfiles])
 
         dbgport = 0 if self.jsDebuggerInfo is None else self.jsDebuggerInfo.port
 
         return [
-            '-e', 'const _SERVER_ADDR = "localhost"',
             '-e', 'const _HEAD_FILES = [%s];' % cmdH,
             '-e', 'const _JSDEBUGGER_PORT = %d;' % dbgport,
         ]
 
     def getHeadFiles(self, test):
         """Obtain lists of head- files.  Returns a list of head files.
         """
         def sanitize_list(s, kind):
@@ -443,16 +444,17 @@ class XPCShellTestThread(Thread):
             self.xpcshell,
             '-g', self.xrePath,
             '-a', self.appPath,
             '-r', self.httpdManifest,
             '-m',
             '-s',
             '-e', 'const _HEAD_JS_PATH = "%s";' % self.headJSPath,
             '-e', 'const _MOZINFO_JS_PATH = "%s";' % self.mozInfoJSPath,
+            '-e', 'const _PREFS_FILE = "%s";' % self.prefsFile.replace('\\', '\\\\'),
         ]
 
         if self.testingModulesDir:
             # Escape backslashes in string literal.
             sanitized = self.testingModulesDir.replace('\\', '\\\\')
             xpcsCmd.extend([
                 '-e',
                 'const _TESTING_MODULES_DIR = "%s";' % sanitized
@@ -939,16 +941,43 @@ class XPCShellTests(object):
         self.httpdJSPath = self.httpdJSPath.replace('\\', '/')
 
         self.httpdManifest = os.path.join(self.xrePath, 'components', 'httpd.manifest')
         self.httpdManifest = self.httpdManifest.replace('\\', '/')
 
         if self.mozInfo is None:
             self.mozInfo = os.path.join(self.testharnessdir, "mozinfo.json")
 
+    def buildPrefsFile(self):
+        # Create the prefs.js file
+        profile_data_dir = os.path.join(SCRIPT_DIR, 'profile_data')
+
+        # If possible, read profile data from topsrcdir. This prevents us from
+        # requiring a re-build to pick up newly added extensions in the
+        # <profile>/extensions directory.
+        if build:
+            path = os.path.join(build.topsrcdir, 'testing', 'profiles')
+            if os.path.isdir(path):
+                profile_data_dir = path
+
+        with open(os.path.join(profile_data_dir, 'profiles.json'), 'r') as fh:
+            base_profiles = json.load(fh)['xpcshell']
+
+        # values to use when interpolating preferences
+        interpolation = {
+            "server": "dummyserver",
+        }
+
+        profile = Profile(profile=self.tempDir, restore=False)
+        for name in base_profiles:
+            path = os.path.join(profile_data_dir, name)
+            profile.merge(path, interpolation=interpolation)
+
+        self.prefsFile = os.path.join(profile.profile, 'user.js')
+
     def buildCoreEnvironment(self):
         """
           Add environment variables likely to be used across all platforms, including
           remote systems.
         """
         # Make assertions fatal
         self.env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
         # Crash reporting interferes with debugging
@@ -1241,16 +1270,17 @@ class XPCShellTests(object):
         self.jscovdir = options.get('jscovdir')
 
         self.testCount = 0
         self.passCount = 0
         self.failCount = 0
         self.todoCount = 0
 
         self.setAbsPath()
+        self.buildPrefsFile()
         self.buildXpcsRunArgs()
 
         self.event = Event()
 
         if not self.updateMozinfo():
             return False
 
         self.stack_fixer_function = None
@@ -1311,17 +1341,18 @@ class XPCShellTests(object):
             'stack_fixer_function': self.stack_fixer_function,
             'event': self.event,
             'cleanup_dir_list': self.cleanup_dir_list,
             'pStdout': pStdout,
             'pStderr': pStderr,
             'keep_going': self.keepGoing,
             'log': self.log,
             'interactive': self.interactive,
-            'app_dir_key': appDirKey
+            'app_dir_key': appDirKey,
+            'prefsFile': self.prefsFile,
         }
 
         if self.sequential:
             # Allow user to kill hung xpcshell subprocess with SIGINT
             # when we are only running tests sequentially.
             signal.signal(signal.SIGINT, markGotSIGINT)
 
         if self.debuggerInfo: