diff options
author | Hiroshi SHIBATA <[email protected]> | 2019-06-29 19:43:47 +0900 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2019-07-02 07:59:54 +0900 |
commit | c3c0e3f5c9444c197779cb242de46dfffda79dec (patch) | |
tree | 03866471345f8c9baa68d548340199408aa51405 /test/lib/leakchecker.rb | |
parent | 142617c8e1cad65fa483c5beb78ab40a99626a87 (diff) |
Move to tool/lib from test/lib.
Diffstat (limited to 'test/lib/leakchecker.rb')
-rw-r--r-- | test/lib/leakchecker.rb | 240 |
1 files changed, 0 insertions, 240 deletions
diff --git a/test/lib/leakchecker.rb b/test/lib/leakchecker.rb deleted file mode 100644 index af9200bf77..0000000000 --- a/test/lib/leakchecker.rb +++ /dev/null @@ -1,240 +0,0 @@ -# frozen_string_literal: true -class LeakChecker - def initialize - @fd_info = find_fds - @tempfile_info = find_tempfiles - @thread_info = find_threads - @env_info = find_env - @encoding_info = find_encodings - @old_verbose = $VERBOSE - end - - def check(test_name) - leaks = [ - check_fd_leak(test_name), - check_thread_leak(test_name), - check_tempfile_leak(test_name), - check_env(test_name), - check_encodings(test_name), - check_safe(test_name), - check_verbose(test_name), - ] - GC.start if leaks.any? - end - - def check_safe test_name - puts "#{test_name}: $SAFE == #{$SAFE}" unless $SAFE == 0 - end - - def check_verbose test_name - puts "#{test_name}: $VERBOSE == #{$VERBOSE}" unless @old_verbose == $VERBOSE - end - - def find_fds - if IO.respond_to?(:console) and (m = IO.method(:console)).arity.nonzero? - m[:close] - end - fd_dir = "/proc/self/fd" - if File.directory?(fd_dir) - fds = Dir.open(fd_dir) {|d| - a = d.grep(/\A\d+\z/, &:to_i) - if d.respond_to? :fileno - a -= [d.fileno] - end - a - } - fds.sort - else - [] - end - end - - def check_fd_leak(test_name) - leaked = false - live1 = @fd_info - live2 = find_fds - fd_closed = live1 - live2 - if !fd_closed.empty? - fd_closed.each {|fd| - puts "Closed file descriptor: #{test_name}: #{fd}" - } - end - fd_leaked = live2 - live1 - if !fd_leaked.empty? - leaked = true - h = {} - ObjectSpace.each_object(IO) {|io| - inspect = io.inspect - begin - autoclose = io.autoclose? - fd = io.fileno - rescue IOError # closed IO object - next - end - (h[fd] ||= []) << [io, autoclose, inspect] - } - fd_leaked.each {|fd| - str = ''.dup - if h[fd] - str << ' :' - h[fd].map {|io, autoclose, inspect| - s = ' ' + inspect - s << "(not-autoclose)" if !autoclose - s - }.sort.each {|s| - str << s - } - end - puts "Leaked file descriptor: #{test_name}: #{fd}#{str}" - } - #system("lsof -p #$$") if !fd_leaked.empty? - h.each {|fd, list| - next if list.length <= 1 - if 1 < list.count {|io, autoclose, inspect| autoclose } - str = list.map {|io, autoclose, inspect| " #{inspect}" + (autoclose ? "(autoclose)" : "") }.sort.join - puts "Multiple autoclose IO object for a file descriptor:#{str}" - end - } - end - @fd_info = live2 - return leaked - end - - def extend_tempfile_counter - return if defined? LeakChecker::TempfileCounter - m = Module.new { - @count = 0 - class << self - attr_accessor :count - end - - def new(data) - LeakChecker::TempfileCounter.count += 1 - super(data) - end - } - LeakChecker.const_set(:TempfileCounter, m) - - class << Tempfile::Remover - prepend LeakChecker::TempfileCounter - end - end - - def find_tempfiles(prev_count=-1) - return [prev_count, []] unless defined? Tempfile - extend_tempfile_counter - count = TempfileCounter.count - if prev_count == count - [prev_count, []] - else - tempfiles = ObjectSpace.each_object(Tempfile).find_all {|t| - t.instance_variable_defined?(:@tmpfile) and t.path - } - [count, tempfiles] - end - end - - def check_tempfile_leak(test_name) - return false unless defined? Tempfile - count1, initial_tempfiles = @tempfile_info - count2, current_tempfiles = find_tempfiles(count1) - leaked = false - tempfiles_leaked = current_tempfiles - initial_tempfiles - if !tempfiles_leaked.empty? - leaked = true - list = tempfiles_leaked.map {|t| t.inspect }.sort - list.each {|str| - puts "Leaked tempfile: #{test_name}: #{str}" - } - tempfiles_leaked.each {|t| t.close! } - end - @tempfile_info = [count2, initial_tempfiles] - return leaked - end - - def find_threads - Thread.list.find_all {|t| - t != Thread.current && t.alive? - } - end - - def check_thread_leak(test_name) - live1 = @thread_info - live2 = find_threads - thread_finished = live1 - live2 - leaked = false - if !thread_finished.empty? - list = thread_finished.map {|t| t.inspect }.sort - list.each {|str| - puts "Finished thread: #{test_name}: #{str}" - } - end - thread_leaked = live2 - live1 - if !thread_leaked.empty? - leaked = true - list = thread_leaked.map {|t| t.inspect }.sort - list.each {|str| - puts "Leaked thread: #{test_name}: #{str}" - } - end - @thread_info = live2 - return leaked - end - - def find_env - ENV.to_h - end - - def check_env(test_name) - old_env = @env_info - new_env = ENV.to_h - return false if old_env == new_env - (old_env.keys | new_env.keys).sort.each {|k| - if old_env.has_key?(k) - if new_env.has_key?(k) - if old_env[k] != new_env[k] - puts "Environment variable changed: #{test_name} : #{k.inspect} changed : #{old_env[k].inspect} -> #{new_env[k].inspect}" - end - else - puts "Environment variable changed: #{test_name} : #{k.inspect} deleted" - end - else - if new_env.has_key?(k) - puts "Environment variable changed: #{test_name} : #{k.inspect} added" - else - flunk "unreachable" - end - end - } - @env_info = new_env - return true - end - - def find_encodings - [Encoding.default_internal, Encoding.default_external] - end - - def check_encodings(test_name) - old_internal, old_external = @encoding_info - new_internal, new_external = find_encodings - leaked = false - if new_internal != old_internal - leaked = true - puts "Encoding.default_internal changed: #{test_name} : #{old_internal.inspect} to #{new_internal.inspect}" - end - if new_external != old_external - leaked = true - puts "Encoding.default_external changed: #{test_name} : #{old_external.inspect} to #{new_external.inspect}" - end - @encoding_info = [new_internal, new_external] - return leaked - end - - def puts(*a) - output = MiniTest::Unit.output - if defined?(output.set_encoding) - output.set_encoding(nil, nil) - end - output.puts(*a) - end -end |