From dbd239a7aafd2c19fad795b5c453c79eefa1ec87 Mon Sep 17 00:00:00 2001 From: akr Date: Tue, 27 May 2014 03:24:52 +0000 Subject: * test/lib/minitest/unit.rb: Show leaked file descriptors. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- test/lib/minitest/unit.rb | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'test/lib/minitest') diff --git a/test/lib/minitest/unit.rb b/test/lib/minitest/unit.rb index 54f34d55f7..25160340db 100644 --- a/test/lib/minitest/unit.rb +++ b/test/lib/minitest/unit.rb @@ -932,6 +932,7 @@ module MiniTest } threads = find_threads + fds = find_fds tempfiles = find_tempfiles assertions = filtered_test_methods.map { |method| @@ -949,6 +950,8 @@ module MiniTest threads = check_thread_leak inst, threads, find_threads + fds = check_fd_leak inst, fds, find_fds + # find_tempfiles is too slow to run for each test method. #tempfiles = check_tempfile_leak inst, tempfiles, find_tempfiles @@ -984,6 +987,60 @@ module MiniTest live2 end + def find_fds + fd_dir = "/proc/#{$$}/fd" + if File.directory?(fd_dir) + Dir.entries(fd_dir).grep(/\A\d+\z/).map(&:to_i).sort + else + [] + end + end + + def check_fd_leak(inst, live1, live2) + name = "#{inst.class}\##{inst.__name__}" + fd_closed = live1 - live2 + if !fd_closed.empty? + fd_closed.each {|fd| + puts "Closed file descriptor: #{name}: #{fd}" + } + end + fd_leaked = live2 - live1 + if !fd_leaked.empty? + h = {} + ObjectSpace.each_object(IO) {|io| + begin + fd = io.fileno + rescue IOError # closed IO object + next + end + (h[fd] ||= []) << io + } + fd_leaked.each {|fd| + str = '' + if h[fd] + str << ' :' + h[fd].map {|io| + s = ' ' + io.inspect + s << "(not-autoclose)" if !io.autoclose? + s + }.each {|s| + str << s + } + end + puts "Leaked file descriptor: #{name}: #{fd}#{str}" + } + h.each {|fd, ios| + next if ios.length <= 1 + list = ios.map {|io| [io, io.autoclose?] } + if 1 < list.count {|io, autoclose| autoclose } + str = list.map {|io, autoclose| " #{io.inspect}" + (autoclose ? "(autoclose)" : "") }.sort.join + puts "Multiple autoclose IO object for a file descriptor:#{str}" + end + } + end + live2 + end + def find_tempfiles if defined? Tempfile ObjectSpace.each_object(Tempfile).find_all {|t| -- cgit v1.2.3