comparison tests/run-tests.py @ 24508:fbe2fb71a6e6

run-tests: move run into Test class Future patches will change how replacements work. Since the logic in run() is strongly tied to the operation of individual tests and since there is potential to make the implementation simpler by giving the function access to Test attributes, move it into Test.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 28 Mar 2015 14:08:25 -0700
parents a0668a587c04
children 27092bb70293
comparison
equal deleted inserted replaced
24507:a0668a587c04 24508:fbe2fb71a6e6
73 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24 73 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
74 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing 74 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing
75 # zombies but it's pretty harmless even if we do. 75 # zombies but it's pretty harmless even if we do.
76 if sys.version_info < (2, 5): 76 if sys.version_info < (2, 5):
77 subprocess._cleanup = lambda: None 77 subprocess._cleanup = lambda: None
78
79 wifexited = getattr(os, "WIFEXITED", lambda x: False)
78 80
79 closefds = os.name == 'posix' 81 closefds = os.name == 'posix'
80 def Popen4(cmd, wd, timeout, env=None): 82 def Popen4(cmd, wd, timeout, env=None):
81 processlock.acquire() 83 processlock.acquire()
82 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env, 84 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
718 def fail(self, msg): 720 def fail(self, msg):
719 # unittest differentiates between errored and failed. 721 # unittest differentiates between errored and failed.
720 # Failed is denoted by AssertionError (by default at least). 722 # Failed is denoted by AssertionError (by default at least).
721 raise AssertionError(msg) 723 raise AssertionError(msg)
722 724
725 def _runcommand(self, cmd, wd, replacements, env, debug=False,
726 timeout=None):
727 """Run command in a sub-process, capturing the output (stdout and
728 stderr).
729
730 Return a tuple (exitcode, output). output is None in debug mode.
731 """
732 if debug:
733 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
734 ret = proc.wait()
735 return (ret, None)
736
737 proc = Popen4(cmd, wd, timeout, env)
738 def cleanup():
739 terminate(proc)
740 ret = proc.wait()
741 if ret == 0:
742 ret = signal.SIGTERM << 8
743 killdaemons(env['DAEMON_PIDS'])
744 return ret
745
746 output = ''
747 proc.tochild.close()
748
749 try:
750 output = proc.fromchild.read()
751 except KeyboardInterrupt:
752 vlog('# Handling keyboard interrupt')
753 cleanup()
754 raise
755
756 ret = proc.wait()
757 if wifexited(ret):
758 ret = os.WEXITSTATUS(ret)
759
760 if proc.timeout:
761 ret = 'timeout'
762
763 if ret:
764 killdaemons(env['DAEMON_PIDS'])
765
766 for s, r in replacements:
767 output = re.sub(s, r, output)
768 return ret, output.splitlines(True)
769
723 class PythonTest(Test): 770 class PythonTest(Test):
724 """A Python-based test.""" 771 """A Python-based test."""
725 772
726 @property 773 @property
727 def refpath(self): 774 def refpath(self):
731 py3kswitch = self._py3kwarnings and ' -3' or '' 778 py3kswitch = self._py3kwarnings and ' -3' or ''
732 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, self.path) 779 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, self.path)
733 vlog("# Running", cmd) 780 vlog("# Running", cmd)
734 if os.name == 'nt': 781 if os.name == 'nt':
735 replacements.append((r'\r\n', '\n')) 782 replacements.append((r'\r\n', '\n'))
736 result = run(cmd, self._testtmp, replacements, env, 783 result = self._runcommand(cmd, self._testtmp, replacements, env,
737 debug=self._debug, timeout=self._timeout) 784 debug=self._debug, timeout=self._timeout)
738 if self._aborted: 785 if self._aborted:
739 raise KeyboardInterrupt() 786 raise KeyboardInterrupt()
740 787
741 return result 788 return result
742 789
779 f.close() 826 f.close()
780 827
781 cmd = '%s "%s"' % (self._shell, fname) 828 cmd = '%s "%s"' % (self._shell, fname)
782 vlog("# Running", cmd) 829 vlog("# Running", cmd)
783 830
784 exitcode, output = run(cmd, self._testtmp, replacements, env, 831 exitcode, output = self._runcommand(cmd, self._testtmp, replacements,
785 debug=self._debug, timeout=self._timeout) 832 env, debug=self._debug,
833 timeout=self._timeout)
786 834
787 if self._aborted: 835 if self._aborted:
788 raise KeyboardInterrupt() 836 raise KeyboardInterrupt()
789 837
790 # Do not merge output if skipped. Return hghave message instead. 838 # Do not merge output if skipped. Return hghave message instead.
1073 1121
1074 @staticmethod 1122 @staticmethod
1075 def _stringescape(s): 1123 def _stringescape(s):
1076 return TTest.ESCAPESUB(TTest._escapef, s) 1124 return TTest.ESCAPESUB(TTest._escapef, s)
1077 1125
1078
1079 wifexited = getattr(os, "WIFEXITED", lambda x: False)
1080 def run(cmd, wd, replacements, env, debug=False, timeout=None):
1081 """Run command in a sub-process, capturing the output (stdout and stderr).
1082 Return a tuple (exitcode, output). output is None in debug mode."""
1083 if debug:
1084 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
1085 ret = proc.wait()
1086 return (ret, None)
1087
1088 proc = Popen4(cmd, wd, timeout, env)
1089 def cleanup():
1090 terminate(proc)
1091 ret = proc.wait()
1092 if ret == 0:
1093 ret = signal.SIGTERM << 8
1094 killdaemons(env['DAEMON_PIDS'])
1095 return ret
1096
1097 output = ''
1098 proc.tochild.close()
1099
1100 try:
1101 output = proc.fromchild.read()
1102 except KeyboardInterrupt:
1103 vlog('# Handling keyboard interrupt')
1104 cleanup()
1105 raise
1106
1107 ret = proc.wait()
1108 if wifexited(ret):
1109 ret = os.WEXITSTATUS(ret)
1110
1111 if proc.timeout:
1112 ret = 'timeout'
1113
1114 if ret:
1115 killdaemons(env['DAEMON_PIDS'])
1116
1117 for s, r in replacements:
1118 output = re.sub(s, r, output)
1119 return ret, output.splitlines(True)
1120
1121 iolock = threading.RLock() 1126 iolock = threading.RLock()
1122 1127
1123 class SkipTest(Exception): 1128 class SkipTest(Exception):
1124 """Raised to indicate that a test is to be skipped.""" 1129 """Raised to indicate that a test is to be skipped."""
1125 1130