tests/run-tests.py
changeset 21534 3ece55d16044
parent 21533 aecac8059c00
child 21535 ab7e224bc089
equal deleted inserted replaced
21533:aecac8059c00 21534:3ece55d16044
  1336         ('.t', TTest),
  1336         ('.t', TTest),
  1337     ]
  1337     ]
  1338 
  1338 
  1339     def __init__(self):
  1339     def __init__(self):
  1340         self.options = None
  1340         self.options = None
  1341         self.testdir = None
  1341         self._testdir = None
  1342         self.hgtmp = None
  1342         self._hgtmp = None
  1343         self.inst = None
  1343         self._installdir = None
  1344         self.bindir = None
  1344         self._bindir = None
  1345         self.tmpbinddir = None
  1345         self._tmpbinddir = None
  1346         self.pythondir = None
  1346         self._pythondir = None
  1347         self.coveragefile = None
  1347         self._coveragefile = None
  1348         self._createdfiles = []
  1348         self._createdfiles = []
  1349         self._hgpath = None
  1349         self._hgpath = None
  1350 
  1350 
  1351     def run(self, args, parser=None):
  1351     def run(self, args, parser=None):
  1352         """Run the test suite."""
  1352         """Run the test suite."""
  1380                     if kw in f:
  1380                     if kw in f:
  1381                         val *= 10
  1381                         val *= 10
  1382                 return val
  1382                 return val
  1383             tests.sort(key=sortkey)
  1383             tests.sort(key=sortkey)
  1384 
  1384 
  1385         self.testdir = os.environ['TESTDIR'] = os.getcwd()
  1385         self._testdir = os.environ['TESTDIR'] = os.getcwd()
  1386 
  1386 
  1387         if 'PYTHONHASHSEED' not in os.environ:
  1387         if 'PYTHONHASHSEED' not in os.environ:
  1388             # use a random python hash seed all the time
  1388             # use a random python hash seed all the time
  1389             # we do the randomness ourself to know what seed is used
  1389             # we do the randomness ourself to know what seed is used
  1390             os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
  1390             os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
  1410             if os.name == 'nt':
  1410             if os.name == 'nt':
  1411                 # without this, we get the default temp dir location, but
  1411                 # without this, we get the default temp dir location, but
  1412                 # in all lowercase, which causes troubles with paths (issue3490)
  1412                 # in all lowercase, which causes troubles with paths (issue3490)
  1413                 d = os.getenv('TMP')
  1413                 d = os.getenv('TMP')
  1414             tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
  1414             tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
  1415         self.hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
  1415         self._hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
  1416 
  1416 
  1417         if self.options.with_hg:
  1417         if self.options.with_hg:
  1418             self.inst = None
  1418             self._installdir = None
  1419             self.bindir = os.path.dirname(os.path.realpath(
  1419             self._bindir = os.path.dirname(os.path.realpath(
  1420                                           self.options.with_hg))
  1420                                            self.options.with_hg))
  1421             self.tmpbindir = os.path.join(self.hgtmp, 'install', 'bin')
  1421             self._tmpbindir = os.path.join(self._hgtmp, 'install', 'bin')
  1422             os.makedirs(self.tmpbindir)
  1422             os.makedirs(self._tmpbindir)
  1423 
  1423 
  1424             # This looks redundant with how Python initializes sys.path from
  1424             # This looks redundant with how Python initializes sys.path from
  1425             # the location of the script being executed.  Needed because the
  1425             # the location of the script being executed.  Needed because the
  1426             # "hg" specified by --with-hg is not the only Python script
  1426             # "hg" specified by --with-hg is not the only Python script
  1427             # executed in the test suite that needs to import 'mercurial'
  1427             # executed in the test suite that needs to import 'mercurial'
  1428             # ... which means it's not really redundant at all.
  1428             # ... which means it's not really redundant at all.
  1429             self.pythondir = self.bindir
  1429             self._pythondir = self._bindir
  1430         else:
  1430         else:
  1431             self.inst = os.path.join(self.hgtmp, "install")
  1431             self._installdir = os.path.join(self._hgtmp, "install")
  1432             self.bindir = os.environ["BINDIR"] = os.path.join(self.inst,
  1432             self._bindir = os.environ["BINDIR"] = \
  1433                                                               "bin")
  1433                 os.path.join(self._installdir, "bin")
  1434             self.tmpbindir = self.bindir
  1434             self._tmpbindir = self._bindir
  1435             self.pythondir = os.path.join(self.inst, "lib", "python")
  1435             self._pythondir = os.path.join(self._installdir, "lib", "python")
  1436 
  1436 
  1437         os.environ["BINDIR"] = self.bindir
  1437         os.environ["BINDIR"] = self._bindir
  1438         os.environ["PYTHON"] = PYTHON
  1438         os.environ["PYTHON"] = PYTHON
  1439 
  1439 
  1440         path = [self.bindir] + os.environ["PATH"].split(os.pathsep)
  1440         path = [self._bindir] + os.environ["PATH"].split(os.pathsep)
  1441         if self.tmpbindir != self.bindir:
  1441         if self._tmpbindir != self._bindir:
  1442             path = [self.tmpbindir] + path
  1442             path = [self._tmpbindir] + path
  1443         os.environ["PATH"] = os.pathsep.join(path)
  1443         os.environ["PATH"] = os.pathsep.join(path)
  1444 
  1444 
  1445         # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
  1445         # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
  1446         # can run .../tests/run-tests.py test-foo where test-foo
  1446         # can run .../tests/run-tests.py test-foo where test-foo
  1447         # adds an extension to HGRC. Also include run-test.py directory to
  1447         # adds an extension to HGRC. Also include run-test.py directory to
  1448         # import modules like heredoctest.
  1448         # import modules like heredoctest.
  1449         pypath = [self.pythondir, self.testdir,
  1449         pypath = [self._pythondir, self._testdir,
  1450                   os.path.abspath(os.path.dirname(__file__))]
  1450                   os.path.abspath(os.path.dirname(__file__))]
  1451         # We have to augment PYTHONPATH, rather than simply replacing
  1451         # We have to augment PYTHONPATH, rather than simply replacing
  1452         # it, in case external libraries are only available via current
  1452         # it, in case external libraries are only available via current
  1453         # PYTHONPATH.  (In particular, the Subversion bindings on OS X
  1453         # PYTHONPATH.  (In particular, the Subversion bindings on OS X
  1454         # are in /opt/subversion.)
  1454         # are in /opt/subversion.)
  1455         oldpypath = os.environ.get(IMPL_PATH)
  1455         oldpypath = os.environ.get(IMPL_PATH)
  1456         if oldpypath:
  1456         if oldpypath:
  1457             pypath.append(oldpypath)
  1457             pypath.append(oldpypath)
  1458         os.environ[IMPL_PATH] = os.pathsep.join(pypath)
  1458         os.environ[IMPL_PATH] = os.pathsep.join(pypath)
  1459 
  1459 
  1460         self.coveragefile = os.path.join(self.testdir, '.coverage')
  1460         self._coveragefile = os.path.join(self._testdir, '.coverage')
  1461 
  1461 
  1462         vlog("# Using TESTDIR", self.testdir)
  1462         vlog("# Using TESTDIR", self._testdir)
  1463         vlog("# Using HGTMP", self.hgtmp)
  1463         vlog("# Using HGTMP", self._hgtmp)
  1464         vlog("# Using PATH", os.environ["PATH"])
  1464         vlog("# Using PATH", os.environ["PATH"])
  1465         vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
  1465         vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
  1466 
  1466 
  1467         try:
  1467         try:
  1468             return self._runtests(tests) or 0
  1468             return self._runtests(tests) or 0
  1489                 if os.path.basename(t).startswith('test-')
  1489                 if os.path.basename(t).startswith('test-')
  1490                     and (t.endswith('.py') or t.endswith('.t'))]
  1490                     and (t.endswith('.py') or t.endswith('.t'))]
  1491 
  1491 
  1492     def _runtests(self, tests):
  1492     def _runtests(self, tests):
  1493         try:
  1493         try:
  1494             if self.inst:
  1494             if self._installdir:
  1495                 self._installhg()
  1495                 self._installhg()
  1496                 self._checkhglib("Testing")
  1496                 self._checkhglib("Testing")
  1497             else:
  1497             else:
  1498                 self._usecorrectpython()
  1498                 self._usecorrectpython()
  1499 
  1499 
  1510             tests = [self._gettest(t, i) for i, t in enumerate(tests)]
  1510             tests = [self._gettest(t, i) for i, t in enumerate(tests)]
  1511 
  1511 
  1512             failed = False
  1512             failed = False
  1513             warned = False
  1513             warned = False
  1514 
  1514 
  1515             suite = TestSuite(self.testdir,
  1515             suite = TestSuite(self._testdir,
  1516                               jobs=self.options.jobs,
  1516                               jobs=self.options.jobs,
  1517                               whitelist=self.options.whitelisted,
  1517                               whitelist=self.options.whitelisted,
  1518                               blacklist=self.options.blacklist,
  1518                               blacklist=self.options.blacklist,
  1519                               retest=self.options.retest,
  1519                               retest=self.options.retest,
  1520                               keywords=self.options.keywords,
  1520                               keywords=self.options.keywords,
  1549         for ext, cls in self.TESTTYPES:
  1549         for ext, cls in self.TESTTYPES:
  1550             if lctest.endswith(ext):
  1550             if lctest.endswith(ext):
  1551                 testcls = cls
  1551                 testcls = cls
  1552                 break
  1552                 break
  1553 
  1553 
  1554         refpath = os.path.join(self.testdir, test)
  1554         refpath = os.path.join(self._testdir, test)
  1555         tmpdir = os.path.join(self.hgtmp, 'child%d' % count)
  1555         tmpdir = os.path.join(self._hgtmp, 'child%d' % count)
  1556 
  1556 
  1557         return testcls(refpath, tmpdir,
  1557         return testcls(refpath, tmpdir,
  1558                        keeptmpdir=self.options.keep_tmpdir,
  1558                        keeptmpdir=self.options.keep_tmpdir,
  1559                        debug=self.options.debug,
  1559                        debug=self.options.debug,
  1560                        timeout=self.options.timeout,
  1560                        timeout=self.options.timeout,
  1567         """Clean up state from this test invocation."""
  1567         """Clean up state from this test invocation."""
  1568 
  1568 
  1569         if self.options.keep_tmpdir:
  1569         if self.options.keep_tmpdir:
  1570             return
  1570             return
  1571 
  1571 
  1572         vlog("# Cleaning up HGTMP", self.hgtmp)
  1572         vlog("# Cleaning up HGTMP", self._hgtmp)
  1573         shutil.rmtree(self.hgtmp, True)
  1573         shutil.rmtree(self._hgtmp, True)
  1574         for f in self._createdfiles:
  1574         for f in self._createdfiles:
  1575             try:
  1575             try:
  1576                 os.remove(f)
  1576                 os.remove(f)
  1577             except OSError:
  1577             except OSError:
  1578                 pass
  1578                 pass
  1582         # same interpreter or bad things will happen.
  1582         # same interpreter or bad things will happen.
  1583         pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
  1583         pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
  1584         if getattr(os, 'symlink', None):
  1584         if getattr(os, 'symlink', None):
  1585             vlog("# Making python executable in test path a symlink to '%s'" %
  1585             vlog("# Making python executable in test path a symlink to '%s'" %
  1586                  sys.executable)
  1586                  sys.executable)
  1587             mypython = os.path.join(self.tmpbindir, pyexename)
  1587             mypython = os.path.join(self._tmpbindir, pyexename)
  1588             try:
  1588             try:
  1589                 if os.readlink(mypython) == sys.executable:
  1589                 if os.readlink(mypython) == sys.executable:
  1590                     return
  1590                     return
  1591                 os.unlink(mypython)
  1591                 os.unlink(mypython)
  1592             except OSError, err:
  1592             except OSError, err:
  1638                ' install --force --prefix="%(prefix)s"'
  1638                ' install --force --prefix="%(prefix)s"'
  1639                ' --install-lib="%(libdir)s"'
  1639                ' --install-lib="%(libdir)s"'
  1640                ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
  1640                ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
  1641                % {'exe': sys.executable, 'py3': py3, 'pure': pure,
  1641                % {'exe': sys.executable, 'py3': py3, 'pure': pure,
  1642                   'compiler': compiler,
  1642                   'compiler': compiler,
  1643                   'base': os.path.join(self.hgtmp, "build"),
  1643                   'base': os.path.join(self._hgtmp, "build"),
  1644                   'prefix': self.inst, 'libdir': self.pythondir,
  1644                   'prefix': self._installdir, 'libdir': self._pythondir,
  1645                   'bindir': self.bindir,
  1645                   'bindir': self._bindir,
  1646                   'nohome': nohome, 'logfile': installerrs})
  1646                   'nohome': nohome, 'logfile': installerrs})
  1647         vlog("# Running", cmd)
  1647         vlog("# Running", cmd)
  1648         if os.system(cmd) == 0:
  1648         if os.system(cmd) == 0:
  1649             if not self.options.verbose:
  1649             if not self.options.verbose:
  1650                 os.remove(installerrs)
  1650                 os.remove(installerrs)
  1652             f = open(installerrs)
  1652             f = open(installerrs)
  1653             for line in f:
  1653             for line in f:
  1654                 print line,
  1654                 print line,
  1655             f.close()
  1655             f.close()
  1656             sys.exit(1)
  1656             sys.exit(1)
  1657         os.chdir(self.testdir)
  1657         os.chdir(self._testdir)
  1658 
  1658 
  1659         self._usecorrectpython()
  1659         self._usecorrectpython()
  1660 
  1660 
  1661         if self.options.py3k_warnings and not self.options.anycoverage:
  1661         if self.options.py3k_warnings and not self.options.anycoverage:
  1662             vlog("# Updating hg command to enable Py3k Warnings switch")
  1662             vlog("# Updating hg command to enable Py3k Warnings switch")
  1663             f = open(os.path.join(self.bindir, 'hg'), 'r')
  1663             f = open(os.path.join(self._bindir, 'hg'), 'r')
  1664             lines = [line.rstrip() for line in f]
  1664             lines = [line.rstrip() for line in f]
  1665             lines[0] += ' -3'
  1665             lines[0] += ' -3'
  1666             f.close()
  1666             f.close()
  1667             f = open(os.path.join(self.bindir, 'hg'), 'w')
  1667             f = open(os.path.join(self._bindir, 'hg'), 'w')
  1668             for line in lines:
  1668             for line in lines:
  1669                 f.write(line + '\n')
  1669                 f.write(line + '\n')
  1670             f.close()
  1670             f.close()
  1671 
  1671 
  1672         hgbat = os.path.join(self.bindir, 'hg.bat')
  1672         hgbat = os.path.join(self._bindir, 'hg.bat')
  1673         if os.path.isfile(hgbat):
  1673         if os.path.isfile(hgbat):
  1674             # hg.bat expects to be put in bin/scripts while run-tests.py
  1674             # hg.bat expects to be put in bin/scripts while run-tests.py
  1675             # installation layout put it in bin/ directly. Fix it
  1675             # installation layout put it in bin/ directly. Fix it
  1676             f = open(hgbat, 'rb')
  1676             f = open(hgbat, 'rb')
  1677             data = f.read()
  1677             data = f.read()
  1684                 f.close()
  1684                 f.close()
  1685             else:
  1685             else:
  1686                 print 'WARNING: cannot fix hg.bat reference to python.exe'
  1686                 print 'WARNING: cannot fix hg.bat reference to python.exe'
  1687 
  1687 
  1688         if self.options.anycoverage:
  1688         if self.options.anycoverage:
  1689             custom = os.path.join(self.testdir, 'sitecustomize.py')
  1689             custom = os.path.join(self._testdir, 'sitecustomize.py')
  1690             target = os.path.join(self.pythondir, 'sitecustomize.py')
  1690             target = os.path.join(self._pythondir, 'sitecustomize.py')
  1691             vlog('# Installing coverage trigger to %s' % target)
  1691             vlog('# Installing coverage trigger to %s' % target)
  1692             shutil.copyfile(custom, target)
  1692             shutil.copyfile(custom, target)
  1693             rc = os.path.join(self.testdir, '.coveragerc')
  1693             rc = os.path.join(self._testdir, '.coveragerc')
  1694             vlog('# Installing coverage rc to %s' % rc)
  1694             vlog('# Installing coverage rc to %s' % rc)
  1695             os.environ['COVERAGE_PROCESS_START'] = rc
  1695             os.environ['COVERAGE_PROCESS_START'] = rc
  1696             fn = os.path.join(self.inst, '..', '.coverage')
  1696             fn = os.path.join(self._installdir, '..', '.coverage')
  1697             os.environ['COVERAGE_FILE'] = fn
  1697             os.environ['COVERAGE_FILE'] = fn
  1698 
  1698 
  1699     def _checkhglib(self, verb):
  1699     def _checkhglib(self, verb):
  1700         """Ensure that the 'mercurial' package imported by python is
  1700         """Ensure that the 'mercurial' package imported by python is
  1701         the one we expect it to be.  If not, print a warning to stderr."""
  1701         the one we expect it to be.  If not, print a warning to stderr."""
  1702         expecthg = os.path.join(self.pythondir, 'mercurial')
  1702         expecthg = os.path.join(self._pythondir, 'mercurial')
  1703         actualhg = self._gethgpath()
  1703         actualhg = self._gethgpath()
  1704         if os.path.abspath(actualhg) != os.path.abspath(expecthg):
  1704         if os.path.abspath(actualhg) != os.path.abspath(expecthg):
  1705             sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
  1705             sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
  1706                              '         (expected %s)\n'
  1706                              '         (expected %s)\n'
  1707                              % (verb, actualhg, expecthg))
  1707                              % (verb, actualhg, expecthg))
  1720 
  1720 
  1721         return self._hgpath
  1721         return self._hgpath
  1722 
  1722 
  1723     def _outputcoverage(self):
  1723     def _outputcoverage(self):
  1724         vlog('# Producing coverage report')
  1724         vlog('# Producing coverage report')
  1725         os.chdir(self.pythondir)
  1725         os.chdir(self._pythondir)
  1726 
  1726 
  1727         def covrun(*args):
  1727         def covrun(*args):
  1728             cmd = 'coverage %s' % ' '.join(args)
  1728             cmd = 'coverage %s' % ' '.join(args)
  1729             vlog('# Running: %s' % cmd)
  1729             vlog('# Running: %s' % cmd)
  1730             os.system(cmd)
  1730             os.system(cmd)
  1731 
  1731 
  1732         covrun('-c')
  1732         covrun('-c')
  1733         omit = ','.join(os.path.join(x, '*') for x in
  1733         omit = ','.join(os.path.join(x, '*') for x in
  1734                         [self.bindir, self.testdir])
  1734                         [self._bindir, self._testdir])
  1735         covrun('-i', '-r', '"--omit=%s"' % omit) # report
  1735         covrun('-i', '-r', '"--omit=%s"' % omit) # report
  1736         if self.options.htmlcov:
  1736         if self.options.htmlcov:
  1737             htmldir = os.path.join(self.testdir, 'htmlcov')
  1737             htmldir = os.path.join(self._testdir, 'htmlcov')
  1738             covrun('-i', '-b', '"--directory=%s"' % htmldir,
  1738             covrun('-i', '-b', '"--directory=%s"' % htmldir,
  1739                    '"--omit=%s"' % omit)
  1739                    '"--omit=%s"' % omit)
  1740         if self.options.annotate:
  1740         if self.options.annotate:
  1741             adir = os.path.join(self.testdir, 'annotated')
  1741             adir = os.path.join(self._testdir, 'annotated')
  1742             if not os.path.isdir(adir):
  1742             if not os.path.isdir(adir):
  1743                 os.mkdir(adir)
  1743                 os.mkdir(adir)
  1744             covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
  1744             covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
  1745 
  1745 
  1746     def _findprogram(self, program):
  1746     def _findprogram(self, program):