[前][次][番号順一覧][スレッド一覧]

ruby-changes:34184

From: akr <ko1@a...>
Date: Sat, 31 May 2014 08:32:35 +0900 (JST)
Subject: [ruby-changes:34184] akr:r46265 (trunk): * test/lib/minitest/unit.rb: Check Tempfile leaks for each test method

akr	2014-05-31 08:32:19 +0900 (Sat, 31 May 2014)

  New Revision: 46265

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?revision=46265&view=revision

  Log:
    * test/lib/minitest/unit.rb: Check Tempfile leaks for each test method
      again.

  Modified files:
    trunk/ChangeLog
    trunk/test/lib/minitest/unit.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 46264)
+++ ChangeLog	(revision 46265)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat May 31 08:31:41 2014  Tanaka Akira  <akr@f...>
+
+	* test/lib/minitest/unit.rb: Check Tempfile leaks for each test method
+	  again.
+
 Sat May 31 03:50:50 2014  Zachary Scott  <e@z...>
 
 	* lib/delegate.rb: [DOC] Document raise in Delegator class
Index: test/lib/minitest/unit.rb
===================================================================
--- test/lib/minitest/unit.rb	(revision 46264)
+++ test/lib/minitest/unit.rb	(revision 46265)
@@ -933,9 +933,7 @@ module MiniTest https://github.com/ruby/ruby/blob/trunk/test/lib/minitest/unit.rb#L933
         filter === m || filter === "#{suite}##{m}"
       }
 
-      threads = find_threads
-      fds = find_fds
-      tempfiles = find_tempfiles
+      leak_info = leak_check_init
 
       assertions = filtered_test_methods.map { |method|
         inst = suite.new method
@@ -950,43 +948,55 @@ module MiniTest https://github.com/ruby/ruby/blob/trunk/test/lib/minitest/unit.rb#L948
         print result
         puts if @verbose
 
-        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
+        leak_info = leak_check(inst, leak_info)
 
         inst._assertions
       }
 
-      tempfiles = check_tempfile_leak suite, tempfiles, find_tempfiles
-
       return assertions.size, assertions.inject(0) { |sum, n| sum + n }
     end
 
+    def leak_check_init
+      fd_info = find_fds
+      thread_info = find_threads
+      tempfile_info = find_tempfiles
+      [fd_info, thread_info, tempfile_info]
+    end
+
+    def leak_check(inst, info)
+      fd_info, thread_info, tempfile_info = info
+      leak_p_1, fd_info = check_fd_leak(inst, fd_info)
+      leak_p_2, thread_info = check_thread_leak(inst, thread_info)
+      leak_p_3, tempfile_info = check_tempfile_leak(inst, tempfile_info)
+      GC.start if leak_p_1 || leak_p_2 || leak_p_3
+      [fd_info, thread_info, tempfile_info]
+    end
+
     def find_threads
       Thread.list.find_all {|t|
         t != Thread.current && t.alive?
       }
     end
 
-    def check_thread_leak(inst, live1, live2)
+    def check_thread_leak(inst, live1)
+      live2 = find_threads
       thread_finished = live1 - live2
+      leak_p = false
       if !thread_finished.empty?
         list = thread_finished.map {|t| t.inspect }.sort
         list.each {|str|
           puts "Finished thread: #{inst.class}\##{inst.__name__}: #{str}"
         }
       end
-      thread_retained = live2 - live1
-      if !thread_retained.empty?
-        list = thread_retained.map {|t| t.inspect }.sort
+      thread_leaked = live2 - live1
+      if !thread_leaked.empty?
+        leak_p = true
+        list = thread_leaked.map {|t| t.inspect }.sort
         list.each {|str|
           puts "Leaked thread: #{inst.class}\##{inst.__name__}: #{str}"
         }
       end
-      live2
+      return leak_p, live2
     end
 
     def find_fds
@@ -1006,7 +1016,9 @@ module MiniTest https://github.com/ruby/ruby/blob/trunk/test/lib/minitest/unit.rb#L1016
       end
     end
 
-    def check_fd_leak(inst, live1, live2)
+    def check_fd_leak(inst, live1)
+      leak_p = false
+      live2 = find_fds
       name = "#{inst.class}\##{inst.__name__}"
       fd_closed = live1 - live2
       if !fd_closed.empty?
@@ -1016,6 +1028,7 @@ module MiniTest https://github.com/ruby/ruby/blob/trunk/test/lib/minitest/unit.rb#L1028
       end
       fd_leaked = live2 - live1
       if !fd_leaked.empty?
+        leak_p = true
         h = {}
         ObjectSpace.each_object(IO) {|io|
           begin
@@ -1047,37 +1060,58 @@ module MiniTest https://github.com/ruby/ruby/blob/trunk/test/lib/minitest/unit.rb#L1060
             puts "Multiple autoclose IO object for a file descriptor:#{str}"
           end
         }
-        h = nil
-        GC.start
       end
-      live2
+      return leak_p, live2
     end
 
-    def find_tempfiles
-      if defined? Tempfile
-        ObjectSpace.each_object(Tempfile).find_all {|t|
-          t.path
-        }
-      else
-        []
+    def extend_tempfile_counter
+      return if defined? ::MiniTest::TempfileCounter
+      m = Module.new {
+        @count = 0
+        class << self
+          attr_accessor :count
+        end
+
+        def new(data)
+          MiniTest::TempfileCounter.count += 1
+          super(data)
+        end
+      }
+      MiniTest.const_set(:TempfileCounter, m)
+
+      class << Tempfile::Remover
+        prepend MiniTest::TempfileCounter
       end
     end
 
-    def check_tempfile_leak(obj, live1, live2)
-      if obj.respond_to?(:__name__)
-        name = "#{obj.class}\##{obj.__name__}"
+    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
-        name = obj.name
+        tempfiles = ObjectSpace.each_object(Tempfile).find_all {|t| t.path }
+        [count, tempfiles]
       end
-      tempfile_retained = live2 - live1
-      if !tempfile_retained.empty?
-        list = tempfile_retained.map {|t| t.inspect }.sort
+    end
+
+    def check_tempfile_leak(inst, info)
+      return false, info unless defined? Tempfile
+      count1, initial_tempfiles = info
+      count2, current_tempfiles = find_tempfiles(count1)
+      leak_p = false
+      tempfiles_leaked = current_tempfiles - initial_tempfiles
+      if !tempfiles_leaked.empty?
+        name = "#{inst.class}\##{inst.__name__}"
+        leak_p = true
+        list = tempfiles_leaked.map {|t| t.inspect }.sort
         list.each {|str|
           puts "Leaked tempfile: #{name}: #{str}"
         }
-        tempfile_retained.each {|t| t.close! }
+        tempfiles_leaked.each {|t| t.close! }
       end
-      live2
+      return leak_p, [count2, initial_tempfiles]
     end
 
     ##

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]