comparison tests/run-tests.py @ 28620:759d167f75cf

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.
author Jun Wu <quark@fb.com>
date Sun, 20 Mar 2016 17:18:06 -0700
parents 9949950664cd
children 2e50eb6304bd
comparison
equal deleted inserted replaced
28619:695c666f42ff 28620:759d167f75cf
483 def __init__(self, path, tmpdir, keeptmpdir=False, 483 def __init__(self, path, tmpdir, keeptmpdir=False,
484 debug=False, 484 debug=False,
485 timeout=defaults['timeout'], 485 timeout=defaults['timeout'],
486 startport=defaults['port'], extraconfigopts=None, 486 startport=defaults['port'], extraconfigopts=None,
487 py3kwarnings=False, shell=None, hgcommand=None, 487 py3kwarnings=False, shell=None, hgcommand=None,
488 slowtimeout=defaults['slowtimeout']): 488 slowtimeout=defaults['slowtimeout'], usechg=False):
489 """Create a test from parameters. 489 """Create a test from parameters.
490 490
491 path is the full path to the file defining the test. 491 path is the full path to the file defining the test.
492 492
493 tmpdir is the main temporary directory to use for this test. 493 tmpdir is the main temporary directory to use for this test.
530 self._startport = startport 530 self._startport = startport
531 self._extraconfigopts = extraconfigopts or [] 531 self._extraconfigopts = extraconfigopts or []
532 self._py3kwarnings = py3kwarnings 532 self._py3kwarnings = py3kwarnings
533 self._shell = _bytespath(shell) 533 self._shell = _bytespath(shell)
534 self._hgcommand = hgcommand or b'hg' 534 self._hgcommand = hgcommand or b'hg'
535 self._usechg = usechg
535 536
536 self._aborted = False 537 self._aborted = False
537 self._daemonpids = [] 538 self._daemonpids = []
538 self._finished = None 539 self._finished = None
539 self._ret = None 540 self._ret = None
540 self._out = None 541 self._out = None
541 self._skipped = None 542 self._skipped = None
542 self._testtmp = None 543 self._testtmp = None
544 self._chgsockdir = None
543 545
544 # If we're not in --debug mode and reference output file exists, 546 # If we're not in --debug mode and reference output file exists,
545 # check test output against it. 547 # check test output against it.
546 if debug: 548 if debug:
547 self._refout = None # to match "out is None" 549 self._refout = None # to match "out is None"
574 os.mkdir(self._threadtmp) 576 os.mkdir(self._threadtmp)
575 except OSError as e: 577 except OSError as e:
576 if e.errno != errno.EEXIST: 578 if e.errno != errno.EEXIST:
577 raise 579 raise
578 580
579 self._testtmp = os.path.join(self._threadtmp, 581 name = os.path.basename(self.path)
580 os.path.basename(self.path)) 582 self._testtmp = os.path.join(self._threadtmp, name)
581 os.mkdir(self._testtmp) 583 os.mkdir(self._testtmp)
582 584
583 # Remove any previous output files. 585 # Remove any previous output files.
584 if os.path.exists(self.errpath): 586 if os.path.exists(self.errpath):
585 try: 587 try:
588 # We might have raced another test to clean up a .err 590 # We might have raced another test to clean up a .err
589 # file, so ignore ENOENT when removing a previous .err 591 # file, so ignore ENOENT when removing a previous .err
590 # file. 592 # file.
591 if e.errno != errno.ENOENT: 593 if e.errno != errno.ENOENT:
592 raise 594 raise
595
596 if self._usechg:
597 self._chgsockdir = os.path.join(self._threadtmp,
598 b'%s.chgsock' % name)
599 os.mkdir(self._chgsockdir)
593 600
594 def run(self, result): 601 def run(self, result):
595 """Run this test and report results against a TestResult instance.""" 602 """Run this test and report results against a TestResult instance."""
596 # This function is extremely similar to unittest.TestCase.run(). Once 603 # This function is extremely similar to unittest.TestCase.run(). Once
597 # we require Python 2.7 (or at least its version of unittest), this 604 # we require Python 2.7 (or at least its version of unittest), this
732 self._threadtmp.decode('utf-8'))) 739 self._threadtmp.decode('utf-8')))
733 else: 740 else:
734 shutil.rmtree(self._testtmp, True) 741 shutil.rmtree(self._testtmp, True)
735 shutil.rmtree(self._threadtmp, True) 742 shutil.rmtree(self._threadtmp, True)
736 743
744 if self._usechg:
745 # chgservers will stop automatically after they find the socket
746 # files are deleted
747 shutil.rmtree(self._chgsockdir, True)
748
737 if (self._ret != 0 or self._out != self._refout) and not self._skipped \ 749 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
738 and not self._debug and self._out: 750 and not self._debug and self._out:
739 f = open(self.errpath, 'wb') 751 f = open(self.errpath, 'wb')
740 for line in self._out: 752 for line in self._out:
741 f.write(line) 753 f.write(line)
820 832
821 # unset env related to hooks 833 # unset env related to hooks
822 for k in env.keys(): 834 for k in env.keys():
823 if k.startswith('HG_'): 835 if k.startswith('HG_'):
824 del env[k] 836 del env[k]
837
838 if self._usechg:
839 env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
825 840
826 return env 841 return env
827 842
828 def _createhgrc(self, path): 843 def _createhgrc(self, path):
829 """Create an hgrc file for this test.""" 844 """Create an hgrc file for this test."""
1908 self._pythondir = None 1923 self._pythondir = None
1909 self._coveragefile = None 1924 self._coveragefile = None
1910 self._createdfiles = [] 1925 self._createdfiles = []
1911 self._hgcommand = None 1926 self._hgcommand = None
1912 self._hgpath = None 1927 self._hgpath = None
1913 self._chgsockdir = None
1914 self._portoffset = 0 1928 self._portoffset = 0
1915 self._ports = {} 1929 self._ports = {}
1916 1930
1917 def run(self, args, parser=None): 1931 def run(self, args, parser=None):
1918 """Run the test suite.""" 1932 """Run the test suite."""
2033 self._bindir = os.path.join(self._installdir, b"bin") 2047 self._bindir = os.path.join(self._installdir, b"bin")
2034 self._hgcommand = b'hg' 2048 self._hgcommand = b'hg'
2035 self._tmpbindir = self._bindir 2049 self._tmpbindir = self._bindir
2036 self._pythondir = os.path.join(self._installdir, b"lib", b"python") 2050 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
2037 2051
2038 # set up crafted chg environment, then replace "hg" command by "chg" 2052 # set CHGHG, then replace "hg" command by "chg"
2039 chgbindir = self._bindir 2053 chgbindir = self._bindir
2040 if self.options.chg or self.options.with_chg: 2054 if self.options.chg or self.options.with_chg:
2041 self._chgsockdir = d = os.path.join(self._hgtmp, b'chgsock')
2042 os.mkdir(d)
2043 osenvironb[b'CHGSOCKNAME'] = os.path.join(d, b"server")
2044 osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand) 2055 osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand)
2045 if self.options.chg: 2056 if self.options.chg:
2046 self._hgcommand = b'chg' 2057 self._hgcommand = b'chg'
2047 elif self.options.with_chg: 2058 elif self.options.with_chg:
2048 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg)) 2059 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
2232 timeout=self.options.timeout, 2243 timeout=self.options.timeout,
2233 startport=self._getport(count), 2244 startport=self._getport(count),
2234 extraconfigopts=self.options.extra_config_opt, 2245 extraconfigopts=self.options.extra_config_opt,
2235 py3kwarnings=self.options.py3k_warnings, 2246 py3kwarnings=self.options.py3k_warnings,
2236 shell=self.options.shell, 2247 shell=self.options.shell,
2237 hgcommand=self._hgcommand) 2248 hgcommand=self._hgcommand,
2249 usechg=bool(self.options.with_chg or self.options.chg))
2238 t.should_reload = True 2250 t.should_reload = True
2239 return t 2251 return t
2240 2252
2241 def _cleanup(self): 2253 def _cleanup(self):
2242 """Clean up state from this test invocation.""" 2254 """Clean up state from this test invocation."""
2243 if self._chgsockdir:
2244 self._killchgdaemons()
2245
2246 if self.options.keep_tmpdir: 2255 if self.options.keep_tmpdir:
2247 return 2256 return
2248 2257
2249 vlog("# Cleaning up HGTMP", self._hgtmp) 2258 vlog("# Cleaning up HGTMP", self._hgtmp)
2250 shutil.rmtree(self._hgtmp, True) 2259 shutil.rmtree(self._hgtmp, True)
2458 sys.stdout.buffer.write(out) 2467 sys.stdout.buffer.write(out)
2459 else: 2468 else:
2460 sys.stdout.write(out) 2469 sys.stdout.write(out)
2461 sys.exit(1) 2470 sys.exit(1)
2462 2471
2463 def _killchgdaemons(self):
2464 """Kill all background chg command servers spawned by tests"""
2465 for f in os.listdir(self._chgsockdir):
2466 if '.' in f:
2467 continue
2468 os.unlink(os.path.join(self._chgsockdir, f))
2469
2470 def _outputcoverage(self): 2472 def _outputcoverage(self):
2471 """Produce code coverage output.""" 2473 """Produce code coverage output."""
2472 from coverage import coverage 2474 from coverage import coverage
2473 2475
2474 vlog('# Producing coverage report') 2476 vlog('# Producing coverage report')