mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 3e92b635fb
			
		
	
	
		3e92b635fb
		
	
	
	
	
		
			
			When you change this to true, you may need to add more tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53141 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			119 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: false
 | |
| module TracePointChecker
 | |
|   STATE = {
 | |
|     count: 0,
 | |
|     running: false,
 | |
|   }
 | |
| 
 | |
|   module ZombieTraceHunter
 | |
|     def before_setup
 | |
|       @tracepoint_captured_stat = TracePoint.stat.map{|k, (activated, _deleted)| [k, activated]}
 | |
| 
 | |
|       super
 | |
|     end
 | |
| 
 | |
|     def after_teardown
 | |
|       super
 | |
| 
 | |
|       # detect zombie traces.
 | |
|       assert_equal(
 | |
|         @tracepoint_captured_stat,
 | |
|         TracePoint.stat.map{|k, (activated, _deleted)| [k, activated]},
 | |
|         "The number of active trace events was changed"
 | |
|       )
 | |
|       # puts "TracePoint - deleted: #{deleted}" if deleted > 0
 | |
| 
 | |
|       TracePointChecker.check if STATE[:running]
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   MAIN_THREAD = Thread.current
 | |
|   TRACES = []
 | |
| 
 | |
|   def self.prefix event
 | |
|     case event
 | |
|     when :call, :return
 | |
|       :n
 | |
|     when :c_call, :c_return
 | |
|       :c
 | |
|     when :b_call, :b_return
 | |
|       :b
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def self.clear_call_stack
 | |
|     Thread.current[:call_stack] = []
 | |
|   end
 | |
| 
 | |
|   def self.call_stack
 | |
|     stack = Thread.current[:call_stack]
 | |
|     stack = clear_call_stack unless stack
 | |
|     stack
 | |
|   end
 | |
| 
 | |
|   def self.verbose_out label, method
 | |
|     puts label => call_stack, :count => STATE[:count], :method => method
 | |
|   end
 | |
| 
 | |
|   def self.method_label tp
 | |
|     "#{prefix(tp.event)}##{tp.method_id}"
 | |
|   end
 | |
| 
 | |
|   def self.start verbose: false, stop_at_failure: false
 | |
|     call_events = %i(a_call)
 | |
|     return_events = %i(a_return)
 | |
|     clear_call_stack
 | |
| 
 | |
|     STATE[:running] = true
 | |
| 
 | |
|     TRACES << TracePoint.new(*call_events){|tp|
 | |
|       next if Thread.current != MAIN_THREAD
 | |
| 
 | |
|       method = method_label(tp)
 | |
|       call_stack.push method
 | |
|       STATE[:count] += 1
 | |
| 
 | |
|       verbose_out :psuh, method if verbose
 | |
|     }
 | |
| 
 | |
|     TRACES << TracePoint.new(*return_events){|tp|
 | |
|       next if Thread.current != MAIN_THREAD
 | |
|       STATE[:count] += 1
 | |
| 
 | |
|       method = "#{prefix(tp.event)}##{tp.method_id}"
 | |
|       verbose_out :pop1, method if verbose
 | |
| 
 | |
|       stored_method = call_stack.pop
 | |
|       next if stored_method.nil?
 | |
| 
 | |
|       verbose_out :pop2, method if verbose
 | |
| 
 | |
|       if stored_method != method
 | |
|         stop if stop_at_failure
 | |
|         RubyVM::SDR() if defined? RubyVM::SDR()
 | |
|         call_stack.clear
 | |
|         raise "#{stored_method} is expected, but #{method} (count: #{STATE[:count]})"
 | |
|       end
 | |
|     }
 | |
| 
 | |
|     TRACES.each{|trace| trace.enable}
 | |
|   end
 | |
| 
 | |
|   def self.stop
 | |
|     STATE[:running] = true
 | |
|     TRACES.each{|trace| trace.disable}
 | |
|     TRACES.clear
 | |
|   end
 | |
| 
 | |
|   def self.check
 | |
|     TRACES.each{|trace|
 | |
|       raise "trace #{trace} should not be deactivated" unless trace.enabled?
 | |
|     }
 | |
|   end
 | |
| end if defined?(TracePoint.stat)
 | |
| 
 | |
| class ::Test::Unit::TestCase
 | |
|   include TracePointChecker::ZombieTraceHunter
 | |
| end if defined?(TracePointChecker)
 | |
| 
 | |
| # TracePointChecker.start verbose: false
 |