##// END OF EJS Templates
Improve test suite robustness by cleaning up stale processes when possible.
Fernando Perez -
Show More
@@ -22,6 +22,7 b' will change in the future.'
22
22
23 import os
23 import os
24 import os.path as path
24 import os.path as path
25 import signal
25 import sys
26 import sys
26 import subprocess
27 import subprocess
27 import tempfile
28 import tempfile
@@ -148,8 +149,17 b' def make_exclude():'
148 class IPTester(object):
149 class IPTester(object):
149 """Call that calls iptest or trial in a subprocess.
150 """Call that calls iptest or trial in a subprocess.
150 """
151 """
152 #: string, name of test runner that will be called
153 runner = None
154 #: list, parameters for test runner
155 params = None
156 #: list, arguments of system call to be made to call test runner
157 call_args = None
158 #: list, process ids of subprocesses we start (for cleanup)
159 pids = None
160
151 def __init__(self,runner='iptest',params=None):
161 def __init__(self,runner='iptest',params=None):
152 """ """
162 """Create new test runner."""
153 if runner == 'iptest':
163 if runner == 'iptest':
154 # Find our own 'iptest' script OS-level entry point
164 # Find our own 'iptest' script OS-level entry point
155 try:
165 try:
@@ -172,6 +182,10 b' class IPTester(object):'
172 # Assemble call
182 # Assemble call
173 self.call_args = self.runner+self.params
183 self.call_args = self.runner+self.params
174
184
185 # Store pids of anything we start to clean up on deletion, if possible
186 # (on posix only, since win32 has no os.kill)
187 self.pids = []
188
175 if sys.platform == 'win32':
189 if sys.platform == 'win32':
176 def _run_cmd(self):
190 def _run_cmd(self):
177 # On Windows, use os.system instead of subprocess.call, because I
191 # On Windows, use os.system instead of subprocess.call, because I
@@ -183,7 +197,14 b' class IPTester(object):'
183 return os.system(' '.join(self.call_args))
197 return os.system(' '.join(self.call_args))
184 else:
198 else:
185 def _run_cmd(self):
199 def _run_cmd(self):
186 return subprocess.call(self.call_args)
200 subp = subprocess.Popen(self.call_args)
201 self.pids.append(subp.pid)
202 # If this fails, the pid will be left in self.pids and cleaned up
203 # later, but if the wait call succeeds, then we can clear the
204 # stored pid.
205 retcode = subp.wait()
206 self.pids.pop()
207 return retcode
187
208
188 def run(self):
209 def run(self):
189 """Run the stored commands"""
210 """Run the stored commands"""
@@ -194,6 +215,22 b' class IPTester(object):'
194 traceback.print_exc()
215 traceback.print_exc()
195 return 1 # signal failure
216 return 1 # signal failure
196
217
218 def __del__(self):
219 """Cleanup on exit by killing any leftover processes."""
220
221 if not hasattr(os, 'kill'):
222 return
223
224 for pid in self.pids:
225 try:
226 print 'Cleaning stale PID:', pid
227 os.kill(pid, signal.SIGKILL)
228 except OSError:
229 # This is just a best effort, if we fail or the process was
230 # really gone, ignore it.
231 pass
232
233
197
234
198 def make_runners():
235 def make_runners():
199 """Define the top-level packages that need to be tested.
236 """Define the top-level packages that need to be tested.
General Comments 0
You need to be logged in to leave comments. Login now