Mercurial > hg
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 |