* 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
This commit is contained in:
parent
2e5d698538
commit
dbd239a7aa
@ -1,3 +1,7 @@
|
|||||||
|
Tue May 27 12:24:22 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* test/lib/minitest/unit.rb: Show leaked file descriptors.
|
||||||
|
|
||||||
Tue May 27 11:12:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Tue May 27 11:12:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* io.c (rb_io_fileno, rb_io_inspect): non-modification does not
|
* io.c (rb_io_fileno, rb_io_inspect): non-modification does not
|
||||||
|
@ -932,6 +932,7 @@ module MiniTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
threads = find_threads
|
threads = find_threads
|
||||||
|
fds = find_fds
|
||||||
tempfiles = find_tempfiles
|
tempfiles = find_tempfiles
|
||||||
|
|
||||||
assertions = filtered_test_methods.map { |method|
|
assertions = filtered_test_methods.map { |method|
|
||||||
@ -949,6 +950,8 @@ module MiniTest
|
|||||||
|
|
||||||
threads = check_thread_leak inst, threads, find_threads
|
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.
|
# find_tempfiles is too slow to run for each test method.
|
||||||
#tempfiles = check_tempfile_leak inst, tempfiles, find_tempfiles
|
#tempfiles = check_tempfile_leak inst, tempfiles, find_tempfiles
|
||||||
|
|
||||||
@ -984,6 +987,60 @@ module MiniTest
|
|||||||
live2
|
live2
|
||||||
end
|
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
|
def find_tempfiles
|
||||||
if defined? Tempfile
|
if defined? Tempfile
|
||||||
ObjectSpace.each_object(Tempfile).find_all {|t|
|
ObjectSpace.each_object(Tempfile).find_all {|t|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user