75 # zombies but it's pretty harmless even if we do. |
76 # zombies but it's pretty harmless even if we do. |
76 if sys.version_info < (2, 5): |
77 if sys.version_info < (2, 5): |
77 subprocess._cleanup = lambda: None |
78 subprocess._cleanup = lambda: None |
78 |
79 |
79 wifexited = getattr(os, "WIFEXITED", lambda x: False) |
80 wifexited = getattr(os, "WIFEXITED", lambda x: False) |
|
81 |
|
82 def checkportisavailable(port): |
|
83 """return true if a port seems free to bind on localhost""" |
|
84 try: |
|
85 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
86 s.bind(('localhost', port)) |
|
87 s.close() |
|
88 return True |
|
89 except socket.error, exc: |
|
90 if not exc.errno == errno.EADDRINUSE: |
|
91 raise |
|
92 return False |
80 |
93 |
81 closefds = os.name == 'posix' |
94 closefds = os.name == 'posix' |
82 def Popen4(cmd, wd, timeout, env=None): |
95 def Popen4(cmd, wd, timeout, env=None): |
83 processlock.acquire() |
96 processlock.acquire() |
84 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env, |
97 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env, |
1606 self._tmpbinddir = None |
1619 self._tmpbinddir = None |
1607 self._pythondir = None |
1620 self._pythondir = None |
1608 self._coveragefile = None |
1621 self._coveragefile = None |
1609 self._createdfiles = [] |
1622 self._createdfiles = [] |
1610 self._hgpath = None |
1623 self._hgpath = None |
|
1624 self._portoffset = 0 |
|
1625 self._ports = {} |
1611 |
1626 |
1612 def run(self, args, parser=None): |
1627 def run(self, args, parser=None): |
1613 """Run the test suite.""" |
1628 """Run the test suite.""" |
1614 oldmask = os.umask(022) |
1629 oldmask = os.umask(022) |
1615 try: |
1630 try: |
1810 if failed: |
1825 if failed: |
1811 return 1 |
1826 return 1 |
1812 if warned: |
1827 if warned: |
1813 return 80 |
1828 return 80 |
1814 |
1829 |
|
1830 def _getport(self, count): |
|
1831 port = self._ports.get(count) # do we have a cached entry? |
|
1832 if port is None: |
|
1833 port = self.options.port + self._portoffset |
|
1834 portneeded = 3 |
|
1835 # above 100 tries we just give up and let test reports failure |
|
1836 for tries in xrange(100): |
|
1837 allfree = True |
|
1838 for idx in xrange(portneeded): |
|
1839 if not checkportisavailable(port + idx): |
|
1840 allfree = False |
|
1841 break |
|
1842 self._portoffset += portneeded |
|
1843 if allfree: |
|
1844 break |
|
1845 self._ports[count] = port |
|
1846 return port |
|
1847 |
1815 def _gettest(self, test, count): |
1848 def _gettest(self, test, count): |
1816 """Obtain a Test by looking at its filename. |
1849 """Obtain a Test by looking at its filename. |
1817 |
1850 |
1818 Returns a Test instance. The Test may not be runnable if it doesn't |
1851 Returns a Test instance. The Test may not be runnable if it doesn't |
1819 map to a known type. |
1852 map to a known type. |
1831 |
1864 |
1832 t = testcls(refpath, tmpdir, |
1865 t = testcls(refpath, tmpdir, |
1833 keeptmpdir=self.options.keep_tmpdir, |
1866 keeptmpdir=self.options.keep_tmpdir, |
1834 debug=self.options.debug, |
1867 debug=self.options.debug, |
1835 timeout=self.options.timeout, |
1868 timeout=self.options.timeout, |
1836 startport=self.options.port + count * 3, |
1869 startport=self._getport(count), |
1837 extraconfigopts=self.options.extra_config_opt, |
1870 extraconfigopts=self.options.extra_config_opt, |
1838 py3kwarnings=self.options.py3k_warnings, |
1871 py3kwarnings=self.options.py3k_warnings, |
1839 shell=self.options.shell) |
1872 shell=self.options.shell) |
1840 t.should_reload = True |
1873 t.should_reload = True |
1841 return t |
1874 return t |