summaryrefslogtreecommitdiff
path: root/jni/ruby/test/dtrace
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/dtrace
Fresh start
Diffstat (limited to 'jni/ruby/test/dtrace')
-rw-r--r--jni/ruby/test/dtrace/dummy.rb1
-rw-r--r--jni/ruby/test/dtrace/helper.rb50
-rw-r--r--jni/ruby/test/dtrace/test_array_create.rb35
-rw-r--r--jni/ruby/test/dtrace/test_cmethod.rb49
-rw-r--r--jni/ruby/test/dtrace/test_function_entry.rb87
-rw-r--r--jni/ruby/test/dtrace/test_gc.rb26
-rw-r--r--jni/ruby/test/dtrace/test_hash_create.rb52
-rw-r--r--jni/ruby/test/dtrace/test_load.rb52
-rw-r--r--jni/ruby/test/dtrace/test_method_cache.rb28
-rw-r--r--jni/ruby/test/dtrace/test_object_create_start.rb35
-rw-r--r--jni/ruby/test/dtrace/test_raise.rb29
-rw-r--r--jni/ruby/test/dtrace/test_require.rb34
-rw-r--r--jni/ruby/test/dtrace/test_singleton_function.rb55
-rw-r--r--jni/ruby/test/dtrace/test_string.rb27
14 files changed, 560 insertions, 0 deletions
diff --git a/jni/ruby/test/dtrace/dummy.rb b/jni/ruby/test/dtrace/dummy.rb
new file mode 100644
index 0000000..e856142
--- /dev/null
+++ b/jni/ruby/test/dtrace/dummy.rb
@@ -0,0 +1 @@
+# this is a dummy file used by test/dtrace/test_require.rb
diff --git a/jni/ruby/test/dtrace/helper.rb b/jni/ruby/test/dtrace/helper.rb
new file mode 100644
index 0000000..ccc7081
--- /dev/null
+++ b/jni/ruby/test/dtrace/helper.rb
@@ -0,0 +1,50 @@
+# -*- coding: us-ascii -*-
+require 'test/unit'
+require 'tempfile'
+
+if Process.euid == 0
+ ok = true
+elsif (sudo = ENV["SUDO"]) and !sudo.empty? and (`#{sudo} echo ok` rescue false)
+ ok = true
+else
+ ok = false
+end
+ok &= (`dtrace -V` rescue false)
+module DTrace
+ class TestCase < Test::Unit::TestCase
+ INCLUDE = File.expand_path('..', File.dirname(__FILE__))
+
+ def trap_probe d_program, ruby_program
+ d = Tempfile.new(%w'probe .d')
+ d.write d_program
+ d.flush
+
+ rb = Tempfile.new(%w'probed .rb')
+ rb.write ruby_program
+ rb.flush
+
+ d_path = d.path
+ rb_path = rb.path
+
+ cmd = ["dtrace", "-q", "-s", d_path, "-c", "#{EnvUtil.rubybin} -I#{INCLUDE} #{rb_path}"]
+ if sudo = @@sudo
+ [RbConfig::CONFIG["LIBPATHENV"], "RUBY", "RUBYOPT"].each do |name|
+ if name and val = ENV[name]
+ cmd.unshift("#{name}=#{val}")
+ end
+ end
+ cmd.unshift(sudo)
+ end
+ probes = IO.popen(cmd, err: [:child, :out]) do |io|
+ io.readlines
+ end
+ d.close(true)
+ rb.close(true)
+ yield(d_path, rb_path, probes)
+ end
+ end
+end if ok
+
+if ok
+ DTrace::TestCase.class_variable_set(:@@sudo, sudo)
+end
diff --git a/jni/ruby/test/dtrace/test_array_create.rb b/jni/ruby/test/dtrace/test_array_create.rb
new file mode 100644
index 0000000..d849bcc
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_array_create.rb
@@ -0,0 +1,35 @@
+require_relative 'helper'
+
+module DTrace
+ class TestArrayCreate < TestCase
+ def test_lit
+ trap_probe(probe, '[]') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '0'
+ }
+ assert_equal([rbfile], saw.map { |line| line[1] })
+ assert_equal(['1'], saw.map { |line| line[2] })
+ }
+ end
+
+ def test_many_lit
+ trap_probe(probe, '[1,2,3,4]') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '4' && line == '1'
+ }
+ assert_operator saw.length, :>, 0
+ }
+ end
+
+ private
+ def probe type = 'array'
+ <<-eoprobe
+ruby$target:::#{type}-create
+/arg1/
+{
+ printf("%d %s %d\\n", arg0, copyinstr(arg1), arg2);
+}
+ eoprobe
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_cmethod.rb b/jni/ruby/test/dtrace/test_cmethod.rb
new file mode 100644
index 0000000..0a9107f
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_cmethod.rb
@@ -0,0 +1,49 @@
+require_relative 'helper'
+
+module DTrace
+ class TestCMethod < TestCase
+ def test_entry
+ probe = <<-eoprobe
+ruby$target:::cmethod-entry
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row[1] == 'times'
+ }
+
+ assert_equal 1, foo_calls.length
+ }
+ end
+
+ def test_exit
+ probe = <<-eoprobe
+ruby$target:::cmethod-return
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row[1] == 'times'
+ }
+
+ assert_equal 1, foo_calls.length
+ }
+ end
+
+ def ruby_program
+ <<-eoruby
+ class Foo
+ def self.foo; end
+ end
+ 10.times { Foo.foo }
+ eoruby
+ end
+ end
+end if defined?(DTrace::TestCase)
+
diff --git a/jni/ruby/test/dtrace/test_function_entry.rb b/jni/ruby/test/dtrace/test_function_entry.rb
new file mode 100644
index 0000000..74aee64
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_function_entry.rb
@@ -0,0 +1,87 @@
+require_relative 'helper'
+
+module DTrace
+ class TestFunctionEntry < TestCase
+ def test_function_entry
+ probe = <<-eoprobe
+ruby$target:::method-entry
+/arg0 && arg1 && arg2/
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row.first == 'Foo' && row[1] == 'foo'
+ }
+
+ assert_equal 10, foo_calls.length
+ line = '2'
+ foo_calls.each { |f| assert_equal line, f[3] }
+ foo_calls.each { |f| assert_equal rb_file, f[2] }
+ }
+ end
+
+ def test_function_return
+ probe = <<-eoprobe
+ruby$target:::method-return
+/arg0 && arg1 && arg2/
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row.first == 'Foo' && row[1] == 'foo'
+ }
+
+ assert_equal 10, foo_calls.length
+ line = '2'
+ foo_calls.each { |f| assert_equal line, f[3] }
+ foo_calls.each { |f| assert_equal rb_file, f[2] }
+ }
+ end
+
+ def test_return_from_raise
+ program = <<-eoruby
+ class Foo
+ def bar; raise; end
+ def baz
+ bar
+ rescue
+ end
+ end
+
+ Foo.new.baz
+ eoruby
+
+ probe = <<-eoprobe
+ruby$target:::method-return
+/arg0 && arg1 && arg2/
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row.first == 'Foo' && row[1] == 'bar'
+ }
+ assert foo_calls.any?
+ }
+ end
+
+ private
+ def ruby_program
+ <<-eoruby
+ class Foo
+ def foo; end
+ end
+ x = Foo.new
+ 10.times { x.foo }
+ eoruby
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_gc.rb b/jni/ruby/test/dtrace/test_gc.rb
new file mode 100644
index 0000000..2f58a11
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_gc.rb
@@ -0,0 +1,26 @@
+require_relative 'helper'
+
+module DTrace
+ class TestGC < TestCase
+ %w{
+ gc-mark-begin
+ gc-mark-end
+ gc-sweep-begin
+ gc-sweep-end
+ }.each do |probe_name|
+ define_method(:"test_#{probe_name.gsub(/-/, '_')}") do
+ probe = "ruby$target:::#{probe_name} { printf(\"#{probe_name}\\n\"); }"
+
+ trap_probe(probe, ruby_program) { |_, _, saw|
+ assert_operator saw.length, :>, 0
+ }
+
+ end
+ end
+
+ private
+ def ruby_program
+ "100000.times { Object.new }"
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_hash_create.rb b/jni/ruby/test/dtrace/test_hash_create.rb
new file mode 100644
index 0000000..2cceded
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_hash_create.rb
@@ -0,0 +1,52 @@
+require_relative 'helper'
+
+module DTrace
+ class TestHashCreate < TestCase
+ def test_hash_new
+ trap_probe(probe, 'Hash.new') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '0'
+ }
+ assert_operator saw.length, :>, 0
+ }
+ end
+
+ def test_hash_lit
+ trap_probe(probe, '{}') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '0'
+ }
+ assert_operator saw.length, :>, 0
+ }
+ end
+
+ def test_hash_lit_elements
+ trap_probe(probe, '{ :foo => :bar }') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '2'
+ }
+ assert_operator saw.length, :>, 0
+ }
+ end
+
+ def test_hash_lit_elements_string
+ trap_probe(probe, '{ :foo => :bar, :bar => "baz" }') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |num, file, line|
+ file == rbfile && num == '4'
+ }
+ assert_operator saw.length, :>, 0
+ }
+ end
+
+ private
+ def probe
+ <<-eoprobe
+ruby$target:::hash-create
+/arg1/
+{
+ printf("%d %s %d\\n", arg0, copyinstr(arg1), arg2);
+}
+ eoprobe
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_load.rb b/jni/ruby/test/dtrace/test_load.rb
new file mode 100644
index 0000000..cceb0c2
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_load.rb
@@ -0,0 +1,52 @@
+require_relative 'helper'
+require 'tempfile'
+
+module DTrace
+ class TestLoad < TestCase
+ def setup
+ super
+ @rbfile = Tempfile.new(['omg', 'rb'])
+ @rbfile.write 'x = 10'
+ end
+
+ def teardown
+ super
+ @rbfile.close(true) if @rbfile
+ end
+
+ def test_load_entry
+ probe = <<-eoprobe
+ruby$target:::load-entry
+{
+ printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2);
+}
+ eoprobe
+ trap_probe(probe, program) { |dpath, rbpath, saw|
+ saw = saw.map(&:split).find_all { |loaded, _, _|
+ loaded == @rbfile.path
+ }
+ assert_equal 10, saw.length
+ }
+ end
+
+ def test_load_return
+ probe = <<-eoprobe
+ruby$target:::load-return
+{
+ printf("%s\\n", copyinstr(arg0));
+}
+ eoprobe
+ trap_probe(probe, program) { |dpath, rbpath, saw|
+ saw = saw.map(&:split).find_all { |loaded, _, _|
+ loaded == @rbfile.path
+ }
+ assert_equal 10, saw.length
+ }
+ end
+
+ private
+ def program
+ "10.times { load '#{@rbfile.path}' }"
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_method_cache.rb b/jni/ruby/test/dtrace/test_method_cache.rb
new file mode 100644
index 0000000..d8ddf45
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_method_cache.rb
@@ -0,0 +1,28 @@
+require_relative 'helper'
+
+module DTrace
+ class TestMethodCacheClear < TestCase
+ def test_method_cache_clear
+ trap_probe(probe, <<-code) do |_,rbfile,lines|
+ class String; end
+ class String; def abc() end end
+ class Object; def abc() end end
+ code
+ assert_not_includes lines, "String #{rbfile} 1\n"
+ assert_includes lines, "String #{rbfile} 2\n"
+ assert_includes lines, "global #{rbfile} 3\n"
+ end
+ end
+
+ private
+ def probe
+ <<-eoprobe
+ruby$target:::method-cache-clear
+/arg1/
+{
+ printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2);
+}
+ eoprobe
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_object_create_start.rb b/jni/ruby/test/dtrace/test_object_create_start.rb
new file mode 100644
index 0000000..2be9611
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_object_create_start.rb
@@ -0,0 +1,35 @@
+require_relative 'helper'
+
+module DTrace
+ class TestObjectCreateStart < TestCase
+ def test_object_create_start
+ trap_probe(probe, '10.times { Object.new }') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |_, file, _|
+ file == rbfile
+ }
+ assert_equal 10, saw.length
+ }
+ end
+
+ def test_object_create_start_name
+ trap_probe(probe, 'Hash.new') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |klass, file, line|
+ file == rbfile
+ }
+ assert_equal(%w{ Hash }, saw.map(&:first))
+ assert_equal([rbfile], saw.map { |line| line[1] })
+ assert_equal(['1'], saw.map { |line| line[2] })
+ }
+ end
+
+ private
+ def probe
+ <<-eoprobe
+ruby$target:::object-create
+{
+ printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2);
+}
+ eoprobe
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_raise.rb b/jni/ruby/test/dtrace/test_raise.rb
new file mode 100644
index 0000000..48fdbf1
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_raise.rb
@@ -0,0 +1,29 @@
+require_relative 'helper'
+
+module DTrace
+ class TestRaise < TestCase
+ def test_raise
+ probe = <<-eoprobe
+ruby$target:::raise
+{
+ printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2);
+}
+ eoprobe
+ trap_probe(probe, program) { |dpath, rbpath, saw|
+ saw = saw.map(&:split).find_all { |_, source_file, _|
+ source_file == rbpath
+ }
+ assert_equal 10, saw.length
+ saw.each do |klass, _, source_line|
+ assert_equal 'RuntimeError', klass
+ assert_equal '1', source_line
+ end
+ }
+ end
+
+ private
+ def program
+ '10.times { raise rescue nil }'
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_require.rb b/jni/ruby/test/dtrace/test_require.rb
new file mode 100644
index 0000000..46a1d76
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_require.rb
@@ -0,0 +1,34 @@
+require_relative 'helper'
+
+module DTrace
+ class TestRequire < TestCase
+ def test_require_entry
+ probe = <<-eoprobe
+ruby$target:::require-entry
+{
+ printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2);
+}
+ eoprobe
+ trap_probe(probe, ruby_program) { |d_file, rb_file, saw|
+ required = saw.map { |s| s.split }.find_all do |(required, _)|
+ required == 'dtrace/dummy'
+ end
+ assert_equal 10, required.length
+ }
+ end
+
+ def test_require_return
+ probe = <<-eoprobe
+ruby$target:::require-return
+{
+ printf("%s\\n", copyinstr(arg0));
+}
+ eoprobe
+ end
+
+ private
+ def ruby_program
+ "10.times { require 'dtrace/dummy' }"
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_singleton_function.rb b/jni/ruby/test/dtrace/test_singleton_function.rb
new file mode 100644
index 0000000..9e118f6
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_singleton_function.rb
@@ -0,0 +1,55 @@
+require_relative 'helper'
+
+module DTrace
+ class TestSingletonFunctionEntry < TestCase
+ def test_entry
+ probe = <<-eoprobe
+ruby$target:::method-entry
+/strstr(copyinstr(arg0), "Foo") != NULL/
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row.first == 'Foo' && row[1] == 'foo'
+ }
+
+ assert_equal 10, foo_calls.length
+ line = '2'
+ foo_calls.each { |f| assert_equal line, f[3] }
+ foo_calls.each { |f| assert_equal rb_file, f[2] }
+ }
+ end
+
+ def test_exit
+ probe = <<-eoprobe
+ruby$target:::method-return
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row.first == 'Foo' && row[1] == 'foo'
+ }
+
+ assert_equal 10, foo_calls.length
+ line = '2'
+ foo_calls.each { |f| assert_equal line, f[3] }
+ foo_calls.each { |f| assert_equal rb_file, f[2] }
+ }
+ end
+
+ def ruby_program
+ <<-eoruby
+ class Foo
+ def self.foo; end
+ end
+ 10.times { Foo.foo }
+ eoruby
+ end
+ end
+end if defined?(DTrace::TestCase)
diff --git a/jni/ruby/test/dtrace/test_string.rb b/jni/ruby/test/dtrace/test_string.rb
new file mode 100644
index 0000000..873d5ac
--- /dev/null
+++ b/jni/ruby/test/dtrace/test_string.rb
@@ -0,0 +1,27 @@
+require_relative 'helper'
+
+module DTrace
+ class TestStringProbes < TestCase
+ def test_object_create_start_string_lit
+ trap_probe(probe, '"omglolwutbbq"') { |_,rbfile,saw|
+ saw = saw.map(&:split).find_all { |klass, file, line, len|
+ file == rbfile && len == '12' && line == '1'
+ }
+ assert_equal(%w{ String }, saw.map(&:first))
+ assert_equal([rbfile], saw.map { |line| line[1] })
+ assert_equal(['1'], saw.map { |line| line[2] })
+ }
+ end
+
+ private
+ def probe
+ <<-eoprobe
+ruby$target:::string-create
+/arg1/
+{
+ printf("String %s %d %d\\n", copyinstr(arg1), arg2, arg0);
+}
+ eoprobe
+ end
+ end
+end if defined?(DTrace::TestCase)