comparison tests/run-tests.py @ 24967:00790cc2b753

run-test: ensure the test ports are available before launching test I'm running into a systematic issue because there is always some port taken in the 1500-wide range of ports used by the test (3 for each test file).
author Pierre-Yves David <pierre-yves.david@fb.com>
date Thu, 07 May 2015 17:14:00 -0700
parents cecbe207cebd
children 2dadd81c68fb
comparison
equal deleted inserted replaced
24966:554d6fcc3c84 24967:00790cc2b753
47 import optparse 47 import optparse
48 import os 48 import os
49 import shutil 49 import shutil
50 import subprocess 50 import subprocess
51 import signal 51 import signal
52 import socket
52 import sys 53 import sys
53 import tempfile 54 import tempfile
54 import time 55 import time
55 import random 56 import random
56 import re 57 import re
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