tests/run-tests.py
changeset 25041 09c71e3da704
parent 25040 6b8c48cfb85e
child 25042 201823c50610
equal deleted inserted replaced
25040:6b8c48cfb85e 25041:09c71e3da704
   126         threading.Thread(target=t).start()
   126         threading.Thread(target=t).start()
   127 
   127 
   128     return p
   128     return p
   129 
   129 
   130 PYTHON = sys.executable.replace('\\', '/')
   130 PYTHON = sys.executable.replace('\\', '/')
   131 IMPL_PATH = 'PYTHONPATH'
   131 IMPL_PATH = b'PYTHONPATH'
   132 if 'java' in sys.platform:
   132 if 'java' in sys.platform:
   133     IMPL_PATH = 'JYTHONPATH'
   133     IMPL_PATH = b'JYTHONPATH'
   134 
   134 
   135 defaults = {
   135 defaults = {
   136     'jobs': ('HGTEST_JOBS', 1),
   136     'jobs': ('HGTEST_JOBS', 1),
   137     'timeout': ('HGTEST_TIMEOUT', 180),
   137     'timeout': ('HGTEST_TIMEOUT', 180),
   138     'port': ('HGTEST_PORT', 20059),
   138     'port': ('HGTEST_PORT', 20059),
   151             if warn:
   151             if warn:
   152                 print("warning: no such %s file: %s" % (listtype, filename))
   152                 print("warning: no such %s file: %s" % (listtype, filename))
   153             continue
   153             continue
   154 
   154 
   155         for line in f.readlines():
   155         for line in f.readlines():
   156             line = line.split('#', 1)[0].strip()
   156             line = line.split(b'#', 1)[0].strip()
   157             if line:
   157             if line:
   158                 entries[line] = filename
   158                 entries[line] = filename
   159 
   159 
   160         f.close()
   160         f.close()
   161     return entries
   161     return entries
   261                 os.access(options.with_hg, os.X_OK)):
   261                 os.access(options.with_hg, os.X_OK)):
   262             parser.error('--with-hg must specify an executable hg script')
   262             parser.error('--with-hg must specify an executable hg script')
   263         if not os.path.basename(options.with_hg) == 'hg':
   263         if not os.path.basename(options.with_hg) == 'hg':
   264             sys.stderr.write('warning: --with-hg should specify an hg script\n')
   264             sys.stderr.write('warning: --with-hg should specify an hg script\n')
   265     if options.local:
   265     if options.local:
   266         testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
   266         testdir = os.path.dirname(os.path.realpath(sys.argv[0]).encode('utf-8'))
   267         hgbin = os.path.join(os.path.dirname(testdir), 'hg')
   267         hgbin = os.path.join(os.path.dirname(testdir), b'hg')
   268         if os.name != 'nt' and not os.access(hgbin, os.X_OK):
   268         if os.name != 'nt' and not os.access(hgbin, os.X_OK):
   269             parser.error('--local specified, but %r not found or not executable'
   269             parser.error('--local specified, but %r not found or not executable'
   270                          % hgbin)
   270                          % hgbin)
   271         options.with_hg = hgbin
   271         options.with_hg = hgbin
   272 
   272 
   664         Test output needs to be normalized so it can be compared to expected
   664         Test output needs to be normalized so it can be compared to expected
   665         output. This function defines how some of that normalization will
   665         output. This function defines how some of that normalization will
   666         occur.
   666         occur.
   667         """
   667         """
   668         r = [
   668         r = [
   669             (r':%s\b' % self._startport, ':$HGPORT'),
   669             (br':%d\b' % self._startport, b':$HGPORT'),
   670             (r':%s\b' % (self._startport + 1), ':$HGPORT1'),
   670             (br':%d\b' % (self._startport + 1), b':$HGPORT1'),
   671             (r':%s\b' % (self._startport + 2), ':$HGPORT2'),
   671             (br':%d\b' % (self._startport + 2), b':$HGPORT2'),
   672             (r'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
   672             (br'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
   673              r'\1 (glob)'),
   673              br'\1 (glob)'),
   674             ]
   674             ]
   675 
   675 
   676         if os.name == 'nt':
   676         if os.name == 'nt':
   677             r.append(
   677             r.append(
   678                 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
   678                 (b''.join(c.isalpha() and b'[%s%s]' % (c.lower(), c.upper()) or
   679                     c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c
   679                     c in b'/\\' and br'[/\\]' or c.isdigit() and c or b'\\' + c
   680                     for c in self._testtmp), '$TESTTMP'))
   680                     for c in self._testtmp), b'$TESTTMP'))
   681         else:
   681         else:
   682             r.append((re.escape(self._testtmp), '$TESTTMP'))
   682             r.append((re.escape(self._testtmp), b'$TESTTMP'))
   683 
   683 
   684         return r
   684         return r
   685 
   685 
   686     def _getenv(self):
   686     def _getenv(self):
   687         """Obtain environment variables to use during test execution."""
   687         """Obtain environment variables to use during test execution."""
   835 class TTest(Test):
   835 class TTest(Test):
   836     """A "t test" is a test backed by a .t file."""
   836     """A "t test" is a test backed by a .t file."""
   837 
   837 
   838     SKIPPED_PREFIX = 'skipped: '
   838     SKIPPED_PREFIX = 'skipped: '
   839     FAILED_PREFIX = 'hghave check failed: '
   839     FAILED_PREFIX = 'hghave check failed: '
   840     NEEDESCAPE = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
   840     NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
   841 
   841 
   842     ESCAPESUB = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
   842     ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
   843     ESCAPEMAP = dict((chr(i), r'\x%02x' % i) for i in range(256))
   843     ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
   844     ESCAPEMAP.update({'\\': '\\\\', '\r': r'\r'})
   844     ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
   845 
   845 
   846     @property
   846     @property
   847     def refpath(self):
   847     def refpath(self):
   848         return os.path.join(self._testdir, self.name)
   848         return os.path.join(self._testdir, self.bname)
   849 
   849 
   850     def _run(self, env):
   850     def _run(self, env):
   851         f = open(self.path, 'rb')
   851         f = open(self.path, 'rb')
   852         lines = f.readlines()
   852         lines = f.readlines()
   853         f.close()
   853         f.close()
   854 
   854 
   855         salt, script, after, expected = self._parsetest(lines)
   855         salt, script, after, expected = self._parsetest(lines)
   856 
   856 
   857         # Write out the generated script.
   857         # Write out the generated script.
   858         fname = '%s.sh' % self._testtmp
   858         fname = b'%s.sh' % self._testtmp
   859         f = open(fname, 'wb')
   859         f = open(fname, 'wb')
   860         for l in script:
   860         for l in script:
   861             f.write(l)
   861             f.write(l)
   862         f.close()
   862         f.close()
   863 
   863 
   864         cmd = '%s "%s"' % (self._shell, fname)
   864         cmd = b'%s "%s"' % (self._shell, fname)
   865         vlog("# Running", cmd)
   865         vlog("# Running", cmd)
   866 
   866 
   867         exitcode, output = self._runcommand(cmd, env)
   867         exitcode, output = self._runcommand(cmd, env)
   868 
   868 
   869         if self._aborted:
   869         if self._aborted:
   876 
   876 
   877         return self._processoutput(exitcode, output, salt, after, expected)
   877         return self._processoutput(exitcode, output, salt, after, expected)
   878 
   878 
   879     def _hghave(self, reqs):
   879     def _hghave(self, reqs):
   880         # TODO do something smarter when all other uses of hghave are gone.
   880         # TODO do something smarter when all other uses of hghave are gone.
   881         tdir = self._testdir.replace('\\', '/')
   881         tdir = self._testdir.replace(b'\\', b'/')
   882         proc = Popen4('%s -c "%s/hghave %s"' %
   882         proc = Popen4(b'%s -c "%s/hghave %s"' %
   883                       (self._shell, tdir, ' '.join(reqs)),
   883                       (self._shell, tdir, b' '.join(reqs)),
   884                       self._testtmp, 0, self._getenv())
   884                       self._testtmp, 0, self._getenv())
   885         stdout, stderr = proc.communicate()
   885         stdout, stderr = proc.communicate()
   886         ret = proc.wait()
   886         ret = proc.wait()
   887         if wifexited(ret):
   887         if wifexited(ret):
   888             ret = os.WEXITSTATUS(ret)
   888             ret = os.WEXITSTATUS(ret)
   894 
   894 
   895     def _parsetest(self, lines):
   895     def _parsetest(self, lines):
   896         # We generate a shell script which outputs unique markers to line
   896         # We generate a shell script which outputs unique markers to line
   897         # up script results with our source. These markers include input
   897         # up script results with our source. These markers include input
   898         # line number and the last return code.
   898         # line number and the last return code.
   899         salt = "SALT" + str(time.time())
   899         salt = b"SALT%d" % time.time()
   900         def addsalt(line, inpython):
   900         def addsalt(line, inpython):
   901             if inpython:
   901             if inpython:
   902                 script.append('%s %d 0\n' % (salt, line))
   902                 script.append(b'%s %d 0\n' % (salt, line))
   903             else:
   903             else:
   904                 script.append('echo %s %s $?\n' % (salt, line))
   904                 script.append(b'echo %s %d $?\n' % (salt, line))
   905 
   905 
   906         script = []
   906         script = []
   907 
   907 
   908         # After we run the shell script, we re-unify the script output
   908         # After we run the shell script, we re-unify the script output
   909         # with non-active parts of the source, with synchronization by our
   909         # with non-active parts of the source, with synchronization by our
  1018             lout, lcmd = l, None
  1018             lout, lcmd = l, None
  1019             if salt in l:
  1019             if salt in l:
  1020                 lout, lcmd = l.split(salt, 1)
  1020                 lout, lcmd = l.split(salt, 1)
  1021 
  1021 
  1022             if lout:
  1022             if lout:
  1023                 if not lout.endswith('\n'):
  1023                 if not lout.endswith(b'\n'):
  1024                     lout += ' (no-eol)\n'
  1024                     lout += b' (no-eol)\n'
  1025 
  1025 
  1026                 # Find the expected output at the current position.
  1026                 # Find the expected output at the current position.
  1027                 el = None
  1027                 el = None
  1028                 if expected.get(pos, None):
  1028                 if expected.get(pos, None):
  1029                     el = expected[pos].pop(0)
  1029                     el = expected[pos].pop(0)
  1038                         r = '' # Warn only this line.
  1038                         r = '' # Warn only this line.
  1039                     else:
  1039                     else:
  1040                         log('\ninfo, unknown linematch result: %r\n' % r)
  1040                         log('\ninfo, unknown linematch result: %r\n' % r)
  1041                         r = False
  1041                         r = False
  1042                 if r:
  1042                 if r:
  1043                     postout.append('  ' + el)
  1043                     postout.append(b'  ' + el)
  1044                 else:
  1044                 else:
  1045                     if self.NEEDESCAPE(lout):
  1045                     if self.NEEDESCAPE(lout):
  1046                         lout = TTest._stringescape('%s (esc)\n' %
  1046                         lout = TTest._stringescape(b'%s (esc)\n' %
  1047                                                    lout.rstrip('\n'))
  1047                                                    lout.rstrip(b'\n'))
  1048                     postout.append('  ' + lout) # Let diff deal with it.
  1048                     postout.append(b'  ' + lout) # Let diff deal with it.
  1049                     if r != '': # If line failed.
  1049                     if r != '': # If line failed.
  1050                         warnonly = 3 # for sure not
  1050                         warnonly = 3 # for sure not
  1051                     elif warnonly == 1: # Is "not yet" and line is warn only.
  1051                     elif warnonly == 1: # Is "not yet" and line is warn only.
  1052                         warnonly = 2 # Yes do warn.
  1052                         warnonly = 2 # Yes do warn.
  1053 
  1053 
  1054             if lcmd:
  1054             if lcmd:
  1055                 # Add on last return code.
  1055                 # Add on last return code.
  1056                 ret = int(lcmd.split()[1])
  1056                 ret = int(lcmd.split()[1])
  1057                 if ret != 0:
  1057                 if ret != 0:
  1058                     postout.append('  [%s]\n' % ret)
  1058                     postout.append(b'  [%d]\n' % ret)
  1059                 if pos in after:
  1059                 if pos in after:
  1060                     # Merge in non-active test bits.
  1060                     # Merge in non-active test bits.
  1061                     postout += after.pop(pos)
  1061                     postout += after.pop(pos)
  1062                 pos = int(lcmd.split()[0])
  1062                 pos = int(lcmd.split()[0])
  1063 
  1063 
  1072     @staticmethod
  1072     @staticmethod
  1073     def rematch(el, l):
  1073     def rematch(el, l):
  1074         try:
  1074         try:
  1075             # use \Z to ensure that the regex matches to the end of the string
  1075             # use \Z to ensure that the regex matches to the end of the string
  1076             if os.name == 'nt':
  1076             if os.name == 'nt':
  1077                 return re.match(el + r'\r?\n\Z', l)
  1077                 return re.match(el + br'\r?\n\Z', l)
  1078             return re.match(el + r'\n\Z', l)
  1078             return re.match(el + br'\n\Z', l)
  1079         except re.error:
  1079         except re.error:
  1080             # el is an invalid regex
  1080             # el is an invalid regex
  1081             return False
  1081             return False
  1082 
  1082 
  1083     @staticmethod
  1083     @staticmethod
  1084     def globmatch(el, l):
  1084     def globmatch(el, l):
  1085         # The only supported special characters are * and ? plus / which also
  1085         # The only supported special characters are * and ? plus / which also
  1086         # matches \ on windows. Escaping of these characters is supported.
  1086         # matches \ on windows. Escaping of these characters is supported.
  1087         if el + '\n' == l:
  1087         if el + b'\n' == l:
  1088             if os.altsep:
  1088             if os.altsep:
  1089                 # matching on "/" is not needed for this line
  1089                 # matching on "/" is not needed for this line
  1090                 for pat in checkcodeglobpats:
  1090                 for pat in checkcodeglobpats:
  1091                     if pat.match(el):
  1091                     if pat.match(el):
  1092                         return True
  1092                         return True
  1093                 return '-glob'
  1093                 return b'-glob'
  1094             return True
  1094             return True
  1095         i, n = 0, len(el)
  1095         i, n = 0, len(el)
  1096         res = ''
  1096         res = b''
  1097         while i < n:
  1097         while i < n:
  1098             c = el[i]
  1098             c = el[i:i + 1]
  1099             i += 1
  1099             i += 1
  1100             if c == '\\' and i < n and el[i] in '*?\\/':
  1100             if c == b'\\' and i < n and el[i:i + 1] in b'*?\\/':
  1101                 res += el[i - 1:i + 1]
  1101                 res += el[i - 1:i + 1]
  1102                 i += 1
  1102                 i += 1
  1103             elif c == '*':
  1103             elif c == b'*':
  1104                 res += '.*'
  1104                 res += b'.*'
  1105             elif c == '?':
  1105             elif c == b'?':
  1106                 res += '.'
  1106                 res += b'.'
  1107             elif c == '/' and os.altsep:
  1107             elif c == b'/' and os.altsep:
  1108                 res += '[/\\\\]'
  1108                 res += b'[/\\\\]'
  1109             else:
  1109             else:
  1110                 res += re.escape(c)
  1110                 res += re.escape(c)
  1111         return TTest.rematch(res, l)
  1111         return TTest.rematch(res, l)
  1112 
  1112 
  1113     @staticmethod
  1113     @staticmethod
  1114     def linematch(el, l):
  1114     def linematch(el, l):
  1115         if el == l: # perfect match (fast)
  1115         if el == l: # perfect match (fast)
  1116             return True
  1116             return True
  1117         if el:
  1117         if el:
  1118             if el.endswith(" (esc)\n"):
  1118             if el.endswith(b" (esc)\n"):
  1119                 el = el[:-7].decode('string-escape') + '\n'
  1119                 el = el[:-7].decode('string-escape') + '\n'
  1120             if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
  1120                 if sys.version_info[0] == 3:
       
  1121                     el.encode('utf-8')
       
  1122             if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
  1121                 return True
  1123                 return True
  1122             if el.endswith(" (re)\n"):
  1124             if el.endswith(b" (re)\n"):
  1123                 return TTest.rematch(el[:-6], l)
  1125                 return TTest.rematch(el[:-6], l)
  1124             if el.endswith(" (glob)\n"):
  1126             if el.endswith(b" (glob)\n"):
  1125                 # ignore '(glob)' added to l by 'replacements'
  1127                 # ignore '(glob)' added to l by 'replacements'
  1126                 if l.endswith(" (glob)\n"):
  1128                 if l.endswith(b" (glob)\n"):
  1127                     l = l[:-8] + "\n"
  1129                     l = l[:-8] + b"\n"
  1128                 return TTest.globmatch(el[:-8], l)
  1130                 return TTest.globmatch(el[:-8], l)
  1129             if os.altsep and l.replace('\\', '/') == el:
  1131             if os.altsep and l.replace(b'\\', b'/') == el:
  1130                 return '+glob'
  1132                 return b'+glob'
  1131         return False
  1133         return False
  1132 
  1134 
  1133     @staticmethod
  1135     @staticmethod
  1134     def parsehghaveoutput(lines):
  1136     def parsehghaveoutput(lines):
  1135         '''Parse hghave log lines.
  1137         '''Parse hghave log lines.
  1385         num_tests = [0]
  1387         num_tests = [0]
  1386         for test in self._tests:
  1388         for test in self._tests:
  1387             def get():
  1389             def get():
  1388                 num_tests[0] += 1
  1390                 num_tests[0] += 1
  1389                 if getattr(test, 'should_reload', False):
  1391                 if getattr(test, 'should_reload', False):
  1390                     return self._loadtest(test.name, num_tests[0])
  1392                     return self._loadtest(test.bname, num_tests[0])
  1391                 return test
  1393                 return test
  1392             if not os.path.exists(test.path):
  1394             if not os.path.exists(test.path):
  1393                 result.addSkip(test, "Doesn't exist")
  1395                 result.addSkip(test, "Doesn't exist")
  1394                 continue
  1396                 continue
  1395 
  1397 
  1601     Tests rely on a lot of state. This object holds it for them.
  1603     Tests rely on a lot of state. This object holds it for them.
  1602     """
  1604     """
  1603 
  1605 
  1604     # Programs required to run tests.
  1606     # Programs required to run tests.
  1605     REQUIREDTOOLS = [
  1607     REQUIREDTOOLS = [
  1606         os.path.basename(sys.executable),
  1608         os.path.basename(sys.executable).encode('utf-8'),
  1607         'diff',
  1609         b'diff',
  1608         'grep',
  1610         b'grep',
  1609         'unzip',
  1611         b'unzip',
  1610         'gunzip',
  1612         b'gunzip',
  1611         'bunzip2',
  1613         b'bunzip2',
  1612         'sed',
  1614         b'sed',
  1613     ]
  1615     ]
  1614 
  1616 
  1615     # Maps file extensions to test class.
  1617     # Maps file extensions to test class.
  1616     TESTTYPES = [
  1618     TESTTYPES = [
  1617         ('.py', PythonTest),
  1619         (b'.py', PythonTest),
  1618         ('.t', TTest),
  1620         (b'.t', TTest),
  1619     ]
  1621     ]
  1620 
  1622 
  1621     def __init__(self):
  1623     def __init__(self):
  1622         self.options = None
  1624         self.options = None
  1623         self._hgroot = None
  1625         self._hgroot = None
  1637         """Run the test suite."""
  1639         """Run the test suite."""
  1638         oldmask = os.umask(0o22)
  1640         oldmask = os.umask(0o22)
  1639         try:
  1641         try:
  1640             parser = parser or getparser()
  1642             parser = parser or getparser()
  1641             options, args = parseargs(args, parser)
  1643             options, args = parseargs(args, parser)
       
  1644             args = [a.encode('utf-8') for a in args]
  1642             self.options = options
  1645             self.options = options
  1643 
  1646 
  1644             self._checktools()
  1647             self._checktools()
  1645             tests = self.findtests(args)
  1648             tests = self.findtests(args)
  1646             return self._run(tests)
  1649             return self._run(tests)
  1650     def _run(self, tests):
  1653     def _run(self, tests):
  1651         if self.options.random:
  1654         if self.options.random:
  1652             random.shuffle(tests)
  1655             random.shuffle(tests)
  1653         else:
  1656         else:
  1654             # keywords for slow tests
  1657             # keywords for slow tests
  1655             slow = 'svn gendoc check-code-hg'.split()
  1658             slow = b'svn gendoc check-code-hg'.split()
  1656             def sortkey(f):
  1659             def sortkey(f):
  1657                 # run largest tests first, as they tend to take the longest
  1660                 # run largest tests first, as they tend to take the longest
  1658                 try:
  1661                 try:
  1659                     val = -os.stat(f).st_size
  1662                     val = -os.stat(f).st_size
  1660                 except OSError as e:
  1663                 except OSError as e:
  1665                     if kw in f:
  1668                     if kw in f:
  1666                         val *= 10
  1669                         val *= 10
  1667                 return val
  1670                 return val
  1668             tests.sort(key=sortkey)
  1671             tests.sort(key=sortkey)
  1669 
  1672 
  1670         self._testdir = os.environ['TESTDIR'] = os.getcwd()
  1673         self._testdir = osenvironb[b'TESTDIR'] = getattr(
       
  1674             os, 'getcwdb', os.getcwd)()
  1671 
  1675 
  1672         if 'PYTHONHASHSEED' not in os.environ:
  1676         if 'PYTHONHASHSEED' not in os.environ:
  1673             # use a random python hash seed all the time
  1677             # use a random python hash seed all the time
  1674             # we do the randomness ourself to know what seed is used
  1678             # we do the randomness ourself to know what seed is used
  1675             os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
  1679             os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
  1676 
  1680 
  1677         if self.options.tmpdir:
  1681         if self.options.tmpdir:
  1678             self.options.keep_tmpdir = True
  1682             self.options.keep_tmpdir = True
  1679             tmpdir = self.options.tmpdir
  1683             tmpdir = self.options.tmpdir.encode('utf-8')
  1680             if os.path.exists(tmpdir):
  1684             if os.path.exists(tmpdir):
  1681                 # Meaning of tmpdir has changed since 1.3: we used to create
  1685                 # Meaning of tmpdir has changed since 1.3: we used to create
  1682                 # HGTMP inside tmpdir; now HGTMP is tmpdir.  So fail if
  1686                 # HGTMP inside tmpdir; now HGTMP is tmpdir.  So fail if
  1683                 # tmpdir already exists.
  1687                 # tmpdir already exists.
  1684                 print("error: temp dir %r already exists" % tmpdir)
  1688                 print("error: temp dir %r already exists" % tmpdir)
  1693         else:
  1697         else:
  1694             d = None
  1698             d = None
  1695             if os.name == 'nt':
  1699             if os.name == 'nt':
  1696                 # without this, we get the default temp dir location, but
  1700                 # without this, we get the default temp dir location, but
  1697                 # in all lowercase, which causes troubles with paths (issue3490)
  1701                 # in all lowercase, which causes troubles with paths (issue3490)
  1698                 d = os.getenv('TMP')
  1702                 d = osenvironb.get(b'TMP', None)
  1699             tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
  1703             # FILE BUG: mkdtemp works only on unicode in Python 3
  1700         self._hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
  1704             tmpdir = tempfile.mkdtemp('', 'hgtests.',
       
  1705                                       d and d.decode('utf-8')).encode('utf-8')
       
  1706 
       
  1707         self._hgtmp = osenvironb[b'HGTMP'] = (
       
  1708             os.path.realpath(tmpdir))
  1701 
  1709 
  1702         if self.options.with_hg:
  1710         if self.options.with_hg:
  1703             self._installdir = None
  1711             self._installdir = None
  1704             self._bindir = os.path.dirname(os.path.realpath(
  1712             self._bindir = os.path.dirname(os.path.realpath(
  1705                                            self.options.with_hg))
  1713                                            self.options.with_hg))
  1706             self._tmpbindir = os.path.join(self._hgtmp, 'install', 'bin')
  1714             self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
  1707             os.makedirs(self._tmpbindir)
  1715             os.makedirs(self._tmpbindir)
  1708 
  1716 
  1709             # This looks redundant with how Python initializes sys.path from
  1717             # This looks redundant with how Python initializes sys.path from
  1710             # the location of the script being executed.  Needed because the
  1718             # the location of the script being executed.  Needed because the
  1711             # "hg" specified by --with-hg is not the only Python script
  1719             # "hg" specified by --with-hg is not the only Python script
  1712             # executed in the test suite that needs to import 'mercurial'
  1720             # executed in the test suite that needs to import 'mercurial'
  1713             # ... which means it's not really redundant at all.
  1721             # ... which means it's not really redundant at all.
  1714             self._pythondir = self._bindir
  1722             self._pythondir = self._bindir
  1715         else:
  1723         else:
  1716             self._installdir = os.path.join(self._hgtmp, "install")
  1724             self._installdir = os.path.join(self._hgtmp, b"install")
  1717             self._bindir = os.environ["BINDIR"] = \
  1725             self._bindir = osenvironb[b"BINDIR"] = \
  1718                 os.path.join(self._installdir, "bin")
  1726                 os.path.join(self._installdir, b"bin")
  1719             self._tmpbindir = self._bindir
  1727             self._tmpbindir = self._bindir
  1720             self._pythondir = os.path.join(self._installdir, "lib", "python")
  1728             self._pythondir = os.path.join(self._installdir, b"lib", b"python")
  1721 
  1729 
  1722         os.environ["BINDIR"] = self._bindir
  1730         osenvironb[b"BINDIR"] = self._bindir
  1723         os.environ["PYTHON"] = PYTHON
  1731         os.environ["PYTHON"] = PYTHON
  1724 
  1732 
  1725         runtestdir = os.path.abspath(os.path.dirname(__file__))
  1733         fileb = __file__.encode('utf-8')
  1726         path = [self._bindir, runtestdir] + os.environ["PATH"].split(os.pathsep)
  1734         runtestdir = os.path.abspath(os.path.dirname(fileb))
       
  1735         if sys.version_info[0] == 3:
       
  1736             sepb = os.pathsep.encode('utf-8')
       
  1737         else:
       
  1738             sepb = os.pathsep
       
  1739         path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
  1727         if os.path.islink(__file__):
  1740         if os.path.islink(__file__):
  1728             # test helper will likely be at the end of the symlink
  1741             # test helper will likely be at the end of the symlink
  1729             realfile = os.path.realpath(__file__)
  1742             realfile = os.path.realpath(fileb)
  1730             realdir = os.path.abspath(os.path.dirname(realfile))
  1743             realdir = os.path.abspath(os.path.dirname(realfile))
  1731             path.insert(2, realdir)
  1744             path.insert(2, realdir)
  1732         if self._tmpbindir != self._bindir:
  1745         if self._tmpbindir != self._bindir:
  1733             path = [self._tmpbindir] + path
  1746             path = [self._tmpbindir] + path
  1734         os.environ["PATH"] = os.pathsep.join(path)
  1747         osenvironb[b"PATH"] = sepb.join(path)
  1735 
  1748 
  1736         # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
  1749         # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
  1737         # can run .../tests/run-tests.py test-foo where test-foo
  1750         # can run .../tests/run-tests.py test-foo where test-foo
  1738         # adds an extension to HGRC. Also include run-test.py directory to
  1751         # adds an extension to HGRC. Also include run-test.py directory to
  1739         # import modules like heredoctest.
  1752         # import modules like heredoctest.
  1740         pypath = [self._pythondir, self._testdir, runtestdir]
  1753         pypath = [self._pythondir, self._testdir, runtestdir]
  1741         # We have to augment PYTHONPATH, rather than simply replacing
  1754         # We have to augment PYTHONPATH, rather than simply replacing
  1742         # it, in case external libraries are only available via current
  1755         # it, in case external libraries are only available via current
  1743         # PYTHONPATH.  (In particular, the Subversion bindings on OS X
  1756         # PYTHONPATH.  (In particular, the Subversion bindings on OS X
  1744         # are in /opt/subversion.)
  1757         # are in /opt/subversion.)
  1745         oldpypath = os.environ.get(IMPL_PATH)
  1758         oldpypath = osenvironb.get(IMPL_PATH)
  1746         if oldpypath:
  1759         if oldpypath:
  1747             pypath.append(oldpypath)
  1760             pypath.append(oldpypath)
  1748         os.environ[IMPL_PATH] = os.pathsep.join(pypath)
  1761         osenvironb[IMPL_PATH] = sepb.join(pypath)
  1749 
  1762 
  1750         if self.options.pure:
  1763         if self.options.pure:
  1751             os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
  1764             os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
  1752 
  1765 
  1753         self._coveragefile = os.path.join(self._testdir, '.coverage')
  1766         self._coveragefile = os.path.join(self._testdir, b'.coverage')
  1754 
  1767 
  1755         vlog("# Using TESTDIR", self._testdir)
  1768         vlog("# Using TESTDIR", self._testdir)
  1756         vlog("# Using HGTMP", self._hgtmp)
  1769         vlog("# Using HGTMP", self._hgtmp)
  1757         vlog("# Using PATH", os.environ["PATH"])
  1770         vlog("# Using PATH", os.environ["PATH"])
  1758         vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
  1771         vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
  1759 
  1772 
  1760         try:
  1773         try:
  1761             return self._runtests(tests) or 0
  1774             return self._runtests(tests) or 0
  1762         finally:
  1775         finally:
  1763             time.sleep(.1)
  1776             time.sleep(.1)
  1772         if not args:
  1785         if not args:
  1773             if self.options.changed:
  1786             if self.options.changed:
  1774                 proc = Popen4('hg st --rev "%s" -man0 .' %
  1787                 proc = Popen4('hg st --rev "%s" -man0 .' %
  1775                               self.options.changed, None, 0)
  1788                               self.options.changed, None, 0)
  1776                 stdout, stderr = proc.communicate()
  1789                 stdout, stderr = proc.communicate()
  1777                 args = stdout.strip('\0').split('\0')
  1790                 args = stdout.strip(b'\0').split(b'\0')
  1778             else:
  1791             else:
  1779                 args = os.listdir('.')
  1792                 args = os.listdir(b'.')
  1780 
  1793 
  1781         return [t for t in args
  1794         return [t for t in args
  1782                 if os.path.basename(t).startswith('test-')
  1795                 if os.path.basename(t).startswith(b'test-')
  1783                     and (t.endswith('.py') or t.endswith('.t'))]
  1796                     and (t.endswith(b'.py') or t.endswith(b'.t'))]
  1784 
  1797 
  1785     def _runtests(self, tests):
  1798     def _runtests(self, tests):
  1786         try:
  1799         try:
  1787             if self._installdir:
  1800             if self._installdir:
  1788                 self._installhg()
  1801                 self._installhg()
  1867             if lctest.endswith(ext):
  1880             if lctest.endswith(ext):
  1868                 testcls = cls
  1881                 testcls = cls
  1869                 break
  1882                 break
  1870 
  1883 
  1871         refpath = os.path.join(self._testdir, test)
  1884         refpath = os.path.join(self._testdir, test)
  1872         tmpdir = os.path.join(self._hgtmp, 'child%d' % count)
  1885         tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
  1873 
  1886 
  1874         t = testcls(refpath, tmpdir,
  1887         t = testcls(refpath, tmpdir,
  1875                     keeptmpdir=self.options.keep_tmpdir,
  1888                     keeptmpdir=self.options.keep_tmpdir,
  1876                     debug=self.options.debug,
  1889                     debug=self.options.debug,
  1877                     timeout=self.options.timeout,
  1890                     timeout=self.options.timeout,
  1897                 pass
  1910                 pass
  1898 
  1911 
  1899     def _usecorrectpython(self):
  1912     def _usecorrectpython(self):
  1900         """Configure the environment to use the appropriate Python in tests."""
  1913         """Configure the environment to use the appropriate Python in tests."""
  1901         # Tests must use the same interpreter as us or bad things will happen.
  1914         # Tests must use the same interpreter as us or bad things will happen.
  1902         pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
  1915         pyexename = sys.platform == 'win32' and b'python.exe' or b'python'
  1903         if getattr(os, 'symlink', None):
  1916         if getattr(os, 'symlink', None):
  1904             vlog("# Making python executable in test path a symlink to '%s'" %
  1917             vlog("# Making python executable in test path a symlink to '%s'" %
  1905                  sys.executable)
  1918                  sys.executable)
  1906             mypython = os.path.join(self._tmpbindir, pyexename)
  1919             mypython = os.path.join(self._tmpbindir, pyexename)
  1907             try:
  1920             try:
  1965                ' install --force --prefix="%(prefix)s"'
  1978                ' install --force --prefix="%(prefix)s"'
  1966                ' --install-lib="%(libdir)s"'
  1979                ' --install-lib="%(libdir)s"'
  1967                ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
  1980                ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
  1968                % {'exe': sys.executable, 'py3': py3, 'pure': pure,
  1981                % {'exe': sys.executable, 'py3': py3, 'pure': pure,
  1969                   'compiler': compiler,
  1982                   'compiler': compiler,
  1970                   'base': os.path.join(self._hgtmp, "build"),
  1983                   'base': os.path.join(self._hgtmp, b"build"),
  1971                   'prefix': self._installdir, 'libdir': self._pythondir,
  1984                   'prefix': self._installdir, 'libdir': self._pythondir,
  1972                   'bindir': self._bindir,
  1985                   'bindir': self._bindir,
  1973                   'nohome': nohome, 'logfile': installerrs})
  1986                   'nohome': nohome, 'logfile': installerrs})
  1974 
  1987 
  1975         # setuptools requires install directories to exist.
  1988         # setuptools requires install directories to exist.