Mercurial > hg
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') |