summaryrefslogtreecommitdiff
path: root/test/dtrace
diff options
context:
space:
mode:
Diffstat (limited to 'test/dtrace')
-rw-r--r--test/dtrace/dummy.rb1
-rw-r--r--test/dtrace/helper.rb33
-rw-r--r--test/dtrace/test_array_create.rb35
-rw-r--r--test/dtrace/test_function_entry.rb58
-rw-r--r--test/dtrace/test_gc.rb26
-rw-r--r--test/dtrace/test_hash_create.rb52
-rw-r--r--test/dtrace/test_load.rb52
-rw-r--r--test/dtrace/test_object_create_start.rb35
-rw-r--r--test/dtrace/test_raise.rb29
-rw-r--r--test/dtrace/test_require.rb34
-rw-r--r--test/dtrace/test_singleton_function.rb55
-rw-r--r--test/dtrace/test_string.rb27
12 files changed, 437 insertions, 0 deletions
diff --git a/test/dtrace/dummy.rb b/test/dtrace/dummy.rb
new file mode 100644
index 0000000000..e85614228c
--- /dev/null
+++ b/test/dtrace/dummy.rb
@@ -0,0 +1 @@
+# this is a dummy file used by test/dtrace/test_require.rb
diff --git a/test/dtrace/helper.rb b/test/dtrace/helper.rb
new file mode 100644
index 0000000000..ef691b5e32
--- /dev/null
+++ b/test/dtrace/helper.rb
@@ -0,0 +1,33 @@
+require 'minitest/autorun'
+require 'tempfile'
+
+module DTrace
+ class TestCase < MiniTest::Unit::TestCase
+ INCLUDE = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+ def setup
+ skip "must be setuid 0 to run dtrace tests" unless Process.euid == 0
+ end
+
+ def trap_probe d_program, ruby_program
+ d = Tempfile.new('probe.d')
+ d.write d_program
+ d.flush
+
+ rb = Tempfile.new('probed.rb')
+ rb.write ruby_program
+ rb.flush
+
+ d_path = d.path
+ rb_path = rb.path
+
+ cmd = "dtrace -q -s #{d_path} -c '#{Gem.ruby} -I#{INCLUDE} #{rb_path}'"
+ probes = IO.popen(cmd) do |io|
+ io.readlines
+ end
+ d.close(true)
+ rb.close(true)
+ yield(d_path, rb_path, probes)
+ end
+ end
+end
diff --git a/test/dtrace/test_array_create.rb b/test/dtrace/test_array_create.rb
new file mode 100644
index 0000000000..22d52d4393
--- /dev/null
+++ b/test/dtrace/test_array_create.rb
@@ -0,0 +1,35 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_function_entry.rb b/test/dtrace/test_function_entry.rb
new file mode 100644
index 0000000000..b9ba0477f7
--- /dev/null
+++ b/test/dtrace/test_function_entry.rb
@@ -0,0 +1,58 @@
+require 'dtrace/helper'
+
+module DTrace
+ class TestFunctionEntry < TestCase
+ def test_function_entry
+ probe = <<-eoprobe
+ruby$target:::function-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:::function-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
+
+ private
+ def ruby_program
+ <<-eoruby
+ class Foo
+ def foo; end
+ end
+ x = Foo.new
+ 10.times { x.foo }
+ eoruby
+ end
+ end
+end
diff --git a/test/dtrace/test_gc.rb b/test/dtrace/test_gc.rb
new file mode 100644
index 0000000000..24251c1a68
--- /dev/null
+++ b/test/dtrace/test_gc.rb
@@ -0,0 +1,26 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_hash_create.rb b/test/dtrace/test_hash_create.rb
new file mode 100644
index 0000000000..6f6738195a
--- /dev/null
+++ b/test/dtrace/test_hash_create.rb
@@ -0,0 +1,52 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_load.rb b/test/dtrace/test_load.rb
new file mode 100644
index 0000000000..8ac7e39119
--- /dev/null
+++ b/test/dtrace/test_load.rb
@@ -0,0 +1,52 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_object_create_start.rb b/test/dtrace/test_object_create_start.rb
new file mode 100644
index 0000000000..756b3b3545
--- /dev/null
+++ b/test/dtrace/test_object_create_start.rb
@@ -0,0 +1,35 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_raise.rb b/test/dtrace/test_raise.rb
new file mode 100644
index 0000000000..fedae8e1a7
--- /dev/null
+++ b/test/dtrace/test_raise.rb
@@ -0,0 +1,29 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_require.rb b/test/dtrace/test_require.rb
new file mode 100644
index 0000000000..c50037e334
--- /dev/null
+++ b/test/dtrace/test_require.rb
@@ -0,0 +1,34 @@
+require 'dtrace/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
diff --git a/test/dtrace/test_singleton_function.rb b/test/dtrace/test_singleton_function.rb
new file mode 100644
index 0000000000..98fe7d3a77
--- /dev/null
+++ b/test/dtrace/test_singleton_function.rb
@@ -0,0 +1,55 @@
+require 'dtrace/helper'
+
+module DTrace
+ class TestSingletonFunctionEntry < TestCase
+ def test_entry
+ probe = <<-eoprobe
+ruby$target:::function-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 == '#<Class: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:::function-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 == '#<Class: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
diff --git a/test/dtrace/test_string.rb b/test/dtrace/test_string.rb
new file mode 100644
index 0000000000..ca8453d38d
--- /dev/null
+++ b/test/dtrace/test_string.rb
@@ -0,0 +1,27 @@
+require 'dtrace/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