ci: Account for pre-existing children in process leak checks
This commit is contained in:
parent
552819e765
commit
8276b81b7d
|
@ -1,4 +1,5 @@
|
|||
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
|
@ -11,6 +12,7 @@ import threading
|
|||
import time
|
||||
import traceback
|
||||
|
||||
import psutil
|
||||
import unittest2
|
||||
|
||||
import mitogen.core
|
||||
|
@ -67,7 +69,6 @@ def get_fd_count():
|
|||
"""
|
||||
Return the number of FDs open by this process.
|
||||
"""
|
||||
import psutil
|
||||
return psutil.Process().num_fds()
|
||||
|
||||
|
||||
|
@ -334,6 +335,10 @@ class TestCase(unittest2.TestCase):
|
|||
# Broker() instantiations in setUp() etc.
|
||||
mitogen.fork.on_fork()
|
||||
cls._fd_count_before = get_fd_count()
|
||||
# Ignore children started by external packages - in particular
|
||||
# multiprocessing.resource_tracker.main()`, started when some Ansible
|
||||
# versions instantiate a `multithreading.Lock()`.
|
||||
cls._children_before = frozenset(psutil.Process().children())
|
||||
super(TestCase, cls).setUpClass()
|
||||
|
||||
ALLOWED_THREADS = set([
|
||||
|
@ -361,7 +366,10 @@ class TestCase(unittest2.TestCase):
|
|||
def _teardown_check_fds(self):
|
||||
mitogen.core.Latch._on_fork()
|
||||
if get_fd_count() != self._fd_count_before:
|
||||
import os; os.system('lsof +E -w -p %s | grep -vw mem' % (os.getpid(),))
|
||||
if sys.platform == 'linux':
|
||||
os.system('lsof +E -w -p %i | grep -vw mem' % (os.getpid(),))
|
||||
else:
|
||||
os.system('lsof -w -p %i | grep -vw mem' % (os.getpid(),))
|
||||
assert 0, "%s leaked FDs. Count before: %s, after: %s" % (
|
||||
self, self._fd_count_before, get_fd_count(),
|
||||
)
|
||||
|
@ -374,19 +382,33 @@ class TestCase(unittest2.TestCase):
|
|||
if self.no_zombie_check:
|
||||
return
|
||||
|
||||
# pid=0: Wait for any child process in the same process group as us.
|
||||
# WNOHANG: Don't block if no processes ready to report status.
|
||||
try:
|
||||
pid, status = os.waitpid(0, os.WNOHANG)
|
||||
except OSError:
|
||||
return # ECHILD
|
||||
except OSError as e:
|
||||
# ECHILD: there are no child processes in our group.
|
||||
if e.errno == errno.ECHILD:
|
||||
return
|
||||
raise
|
||||
|
||||
if pid:
|
||||
assert 0, "%s failed to reap subprocess %d (status %d)." % (
|
||||
self, pid, status
|
||||
)
|
||||
|
||||
print('')
|
||||
print('Children of unit test process:')
|
||||
os.system('ps uww --ppid ' + str(os.getpid()))
|
||||
children_after = frozenset(psutil.Process().children())
|
||||
children_leaked = children_after.difference(self._children_before)
|
||||
if not children_leaked:
|
||||
return
|
||||
|
||||
print('Leaked children of unit test process:')
|
||||
os.system('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
|
||||
% (','.join(str(p.pid) for p in children_leaked),))
|
||||
if self._children_before:
|
||||
print('Pre-existing children of unit test process:')
|
||||
os.system('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
|
||||
% (','.join(str(p.pid) for p in self._children_before),))
|
||||
assert 0, "%s leaked still-running subprocesses." % (self,)
|
||||
|
||||
def tearDown(self):
|
||||
|
|
Loading…
Reference in New Issue