summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--test/lib/tracepointchecker.rb118
-rw-r--r--test/runner.rb15
3 files changed, 126 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 740c57167b..3193d6838b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Fri Jun 20 17:15:43 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/lib/tracepointchecker.rb: add to check TracePoint healthiness.
+
+ * test/runner.rb: use it.
+
Fri Jun 20 07:26:44 2014 Koichi Sasada <ko1@atdot.net>
* test/ruby/test_settracefunc.rb: rewrite tests with
diff --git a/test/lib/tracepointchecker.rb b/test/lib/tracepointchecker.rb
new file mode 100644
index 0000000000..f90611b536
--- /dev/null
+++ b/test/lib/tracepointchecker.rb
@@ -0,0 +1,118 @@
+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
+
+class ::Test::Unit::TestCase
+ include TracePointChecker::ZombieTraceHunter
+end
+
+# TracePointChecker.start verbose: false
diff --git a/test/runner.rb b/test/runner.rb
index 3a8eb78add..aa249a53d5 100644
--- a/test/runner.rb
+++ b/test/runner.rb
@@ -16,27 +16,16 @@ end
ENV["GEM_SKIP"] = ENV["GEM_HOME"] = ENV["GEM_PATH"] = "".freeze
require_relative 'profile_test_all' if ENV.has_key?('RUBY_TEST_ALL_PROFILE')
+require_relative 'lib/tracepointchecker'
module Test::Unit
module ZombieHunter
-
- def before_setup
- @tracepoint_captured_stat = TracePoint.stat.map{|k, (activated, deleted)| [k, activated]}
- end
-
def after_teardown
super
assert_empty(Process.waitall)
-
- # 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
end
end
+
class TestCase
include ZombieHunter
end