11
2+ import errno
23import logging
34import os
45import random
1112import time
1213import traceback
1314
15+ import psutil
1416import unittest2
1517
1618import mitogen .core
@@ -67,7 +69,6 @@ def get_fd_count():
6769 """
6870 Return the number of FDs open by this process.
6971 """
70- import psutil
7172 return psutil .Process ().num_fds ()
7273
7374
@@ -334,6 +335,10 @@ def setUpClass(cls):
334335 # Broker() instantiations in setUp() etc.
335336 mitogen .fork .on_fork ()
336337 cls ._fd_count_before = get_fd_count ()
338+ # Ignore children started by external packages - in particular
339+ # multiprocessing.resource_tracker.main()`, started when some Ansible
340+ # versions instantiate a `multithreading.Lock()`.
341+ cls ._children_before = frozenset (psutil .Process ().children ())
337342 super (TestCase , cls ).setUpClass ()
338343
339344 ALLOWED_THREADS = set ([
@@ -361,7 +366,10 @@ def _teardown_check_threads(self):
361366 def _teardown_check_fds (self ):
362367 mitogen .core .Latch ._on_fork ()
363368 if get_fd_count () != self ._fd_count_before :
364- import os ; os .system ('lsof +E -w -p %s | grep -vw mem' % (os .getpid (),))
369+ if sys .platform == 'linux' :
370+ os .system ('lsof +E -w -p %i | grep -vw mem' % (os .getpid (),))
371+ else :
372+ os .system ('lsof -w -p %i | grep -vw mem' % (os .getpid (),))
365373 assert 0 , "%s leaked FDs. Count before: %s, after: %s" % (
366374 self , self ._fd_count_before , get_fd_count (),
367375 )
@@ -374,19 +382,33 @@ def _teardown_check_zombies(self):
374382 if self .no_zombie_check :
375383 return
376384
385+ # pid=0: Wait for any child process in the same process group as us.
386+ # WNOHANG: Don't block if no processes ready to report status.
377387 try :
378388 pid , status = os .waitpid (0 , os .WNOHANG )
379- except OSError :
380- return # ECHILD
389+ except OSError as e :
390+ # ECHILD: there are no child processes in our group.
391+ if e .errno == errno .ECHILD :
392+ return
393+ raise
381394
382395 if pid :
383396 assert 0 , "%s failed to reap subprocess %d (status %d)." % (
384397 self , pid , status
385398 )
386399
387- print ('' )
388- print ('Children of unit test process:' )
389- os .system ('ps uww --ppid ' + str (os .getpid ()))
400+ children_after = frozenset (psutil .Process ().children ())
401+ children_leaked = children_after .difference (self ._children_before )
402+ if not children_leaked :
403+ return
404+
405+ print ('Leaked children of unit test process:' )
406+ os .system ('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
407+ % (',' .join (str (p .pid ) for p in children_leaked ),))
408+ if self ._children_before :
409+ print ('Pre-existing children of unit test process:' )
410+ os .system ('ps -o "user,pid,%%cpu,%%mem,vsz,rss,tty,stat,start,time,command" -ww -p %s'
411+ % (',' .join (str (p .pid ) for p in self ._children_before ),))
390412 assert 0 , "%s leaked still-running subprocesses." % (self ,)
391413
392414 def tearDown (self ):
0 commit comments