run-tests: use different chg socket directories for different tests
authorJun Wu <quark@fb.com>
Sun, 20 Mar 2016 17:18:06 -0700
changeset 28620 759d167f75cf
parent 28619 695c666f42ff
child 28621 d856e85a8a7a
run-tests: use different chg socket directories for different tests Before this patch, if --chg or --with-chg is specified, all tests are using the same chgserver socket. Since the chg client holds a lock when it starts a new server, and every test needs at least a new chg server due to different HGRCPATH affecting the confighash, the result is a lot of tests will be timed out if -j is large (for example, 50 or 100). This patch solves the issue by using different chg socket directories for different tests.
tests/run-tests.py
--- a/tests/run-tests.py	Mon Mar 21 20:56:46 2016 +0000
+++ b/tests/run-tests.py	Sun Mar 20 17:18:06 2016 -0700
@@ -485,7 +485,7 @@
                  timeout=defaults['timeout'],
                  startport=defaults['port'], extraconfigopts=None,
                  py3kwarnings=False, shell=None, hgcommand=None,
-                 slowtimeout=defaults['slowtimeout']):
+                 slowtimeout=defaults['slowtimeout'], usechg=False):
         """Create a test from parameters.
 
         path is the full path to the file defining the test.
@@ -532,6 +532,7 @@
         self._py3kwarnings = py3kwarnings
         self._shell = _bytespath(shell)
         self._hgcommand = hgcommand or b'hg'
+        self._usechg = usechg
 
         self._aborted = False
         self._daemonpids = []
@@ -540,6 +541,7 @@
         self._out = None
         self._skipped = None
         self._testtmp = None
+        self._chgsockdir = None
 
         # If we're not in --debug mode and reference output file exists,
         # check test output against it.
@@ -576,8 +578,8 @@
             if e.errno != errno.EEXIST:
                 raise
 
-        self._testtmp = os.path.join(self._threadtmp,
-                                     os.path.basename(self.path))
+        name = os.path.basename(self.path)
+        self._testtmp = os.path.join(self._threadtmp, name)
         os.mkdir(self._testtmp)
 
         # Remove any previous output files.
@@ -591,6 +593,11 @@
                 if e.errno != errno.ENOENT:
                     raise
 
+        if self._usechg:
+            self._chgsockdir = os.path.join(self._threadtmp,
+                                            b'%s.chgsock' % name)
+            os.mkdir(self._chgsockdir)
+
     def run(self, result):
         """Run this test and report results against a TestResult instance."""
         # This function is extremely similar to unittest.TestCase.run(). Once
@@ -734,6 +741,11 @@
             shutil.rmtree(self._testtmp, True)
             shutil.rmtree(self._threadtmp, True)
 
+        if self._usechg:
+            # chgservers will stop automatically after they find the socket
+            # files are deleted
+            shutil.rmtree(self._chgsockdir, True)
+
         if (self._ret != 0 or self._out != self._refout) and not self._skipped \
             and not self._debug and self._out:
             f = open(self.errpath, 'wb')
@@ -823,6 +835,9 @@
             if k.startswith('HG_'):
                 del env[k]
 
+        if self._usechg:
+            env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
+
         return env
 
     def _createhgrc(self, path):
@@ -1910,7 +1925,6 @@
         self._createdfiles = []
         self._hgcommand = None
         self._hgpath = None
-        self._chgsockdir = None
         self._portoffset = 0
         self._ports = {}
 
@@ -2035,12 +2049,9 @@
             self._tmpbindir = self._bindir
             self._pythondir = os.path.join(self._installdir, b"lib", b"python")
 
-        # set up crafted chg environment, then replace "hg" command by "chg"
+        # set CHGHG, then replace "hg" command by "chg"
         chgbindir = self._bindir
         if self.options.chg or self.options.with_chg:
-            self._chgsockdir = d = os.path.join(self._hgtmp, b'chgsock')
-            os.mkdir(d)
-            osenvironb[b'CHGSOCKNAME'] = os.path.join(d, b"server")
             osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand)
         if self.options.chg:
             self._hgcommand = b'chg'
@@ -2234,15 +2245,13 @@
                     extraconfigopts=self.options.extra_config_opt,
                     py3kwarnings=self.options.py3k_warnings,
                     shell=self.options.shell,
-                    hgcommand=self._hgcommand)
+                    hgcommand=self._hgcommand,
+                    usechg=bool(self.options.with_chg or self.options.chg))
         t.should_reload = True
         return t
 
     def _cleanup(self):
         """Clean up state from this test invocation."""
-        if self._chgsockdir:
-            self._killchgdaemons()
-
         if self.options.keep_tmpdir:
             return
 
@@ -2460,13 +2469,6 @@
                 sys.stdout.write(out)
             sys.exit(1)
 
-    def _killchgdaemons(self):
-        """Kill all background chg command servers spawned by tests"""
-        for f in os.listdir(self._chgsockdir):
-            if '.' in f:
-                continue
-            os.unlink(os.path.join(self._chgsockdir, f))
-
     def _outputcoverage(self):
         """Produce code coverage output."""
         from coverage import coverage