summaryrefslogtreecommitdiff
path: root/test/ruby/test_thread.rb
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-23 15:22:13 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-23 15:22:13 +0000
commitf7ef694a712d8deccfba67a4860b0272e335f17a (patch)
treede1333bc139328e336cb974ab6f33644a72b97ea /test/ruby/test_thread.rb
parentc0d8e6cbf9d7e068e98ff2053bff18ee13e338df (diff)
* test/ruby/test_settracefunc.rb: add a test for set_trace_func.
* test/ruby/envutil.rb: move "rubyexec" method from test_rubyoptions.rb. * test/ruby/test_rubyoptions.rb: use rubyexec in envutil.rb. * test/ruby/test_thread.rb: add tests to achieve over 90% test coverage of thread.c. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16175 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test/ruby/test_thread.rb')
-rw-r--r--test/ruby/test_thread.rb360
1 files changed, 356 insertions, 4 deletions
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index feebd99f13..b03b60b72a 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -1,7 +1,12 @@
require 'test/unit'
require 'thread'
+require_relative 'envutil'
class TestThread < Test::Unit::TestCase
+ def ruby(*r, &b)
+ EnvUtil.rubyexec(*r, &b)
+ end
+
class Thread < ::Thread
def self.new(*)
th = super
@@ -97,6 +102,335 @@ class TestThread < Test::Unit::TestCase
assert_equal("exit.", result[/.*\Z/], '[ruby-dev:30653]')
}
end
+
+ def test_priority
+ c1 = c2 = 0
+ t1 = Thread.new { loop { c1 += 1 } }
+ t1.priority = -1
+ t2 = Thread.new { loop { c2 += 1 } }
+ t2.priority = -3
+ assert(-1, t1.priority)
+ assert(-3, t2.priority)
+ sleep 0.5
+ t1.kill
+ t2.kill
+ #assert(c1 > c2 * 2, "[ruby-dev:33124]")
+ end
+
+ def test_new
+ assert_raise(ThreadError) do
+ Thread.new
+ end
+
+ t1 = Thread.new { sleep }
+ assert_raise(ThreadError) do
+ t1.instance_eval { initialize { } }
+ end
+
+ t2 = Thread.new(&method(:sleep).to_proc)
+ assert_raise(ThreadError) do
+ t2.instance_eval { initialize { } }
+ end
+
+ ensure
+ t1.kill if t1
+ t2.kill if t2
+ end
+
+ def test_join
+ t = Thread.new { sleep }
+ assert_nil(t.join(0.5))
+
+ ensure
+ t.kill if t
+ end
+
+ def test_join2
+ t1 = Thread.new { sleep(1.5) }
+ t2 = Thread.new do
+ t1.join(1)
+ end
+ t3 = Thread.new do
+ sleep 0.5
+ t1.join
+ end
+ assert_nil(t2.value)
+ assert_equal(t1, t3.value)
+
+ ensure
+ t1.kill if t1
+ t2.kill if t2
+ t3.kill if t3
+ end
+
+ def test_kill_main_thread
+ ruby do |w, r, e|
+ w.puts "p 1"
+ w.puts "Thread.kill Thread.current"
+ w.puts "p 2"
+ w.close
+ assert_equal("1", r.read.chomp)
+ end
+ end
+
+ def test_exit
+ s = 0
+ Thread.new do
+ s += 1
+ Thread.exit
+ s += 2
+ end.join
+ assert_equal(1, s)
+ end
+
+ def test_wakeup
+ s = 0
+ t = Thread.new do
+ s += 1
+ Thread.stop
+ s += 1
+ end
+ sleep 0.5
+ assert_equal(1, s)
+ t.wakeup
+ sleep 0.5
+ assert_equal(2, s)
+ assert_raise(ThreadError) { t.wakeup }
+
+ ensure
+ t.kill if t
+ end
+
+ def test_stop
+ ruby do |w, r, e|
+ w.puts "begin"
+ w.puts " Thread.stop"
+ w.puts " p 1"
+ w.puts "rescue ThreadError"
+ w.puts " p 2"
+ w.puts "end"
+ w.close
+ assert_equal("2", r.read.chomp)
+ end
+ end
+
+ def test_list
+ ruby do |w, r, e|
+ w.puts "t1 = Thread.new { sleep }"
+ w.puts "t2 = Thread.new { loop { } }"
+ w.puts "t3 = Thread.new { }.join"
+ w.puts "p [Thread.current, t1, t2].sort_by {|t| t.object_id }"
+ w.puts "p Thread.list.sort_by {|t| t.object_id }"
+ w.close
+ assert_equal(r.gets, r.gets)
+ end
+ end
+
+ def test_main
+ ruby do |w, r, e|
+ w.puts "p Thread.main == Thread.current"
+ w.puts "Thread.new { p Thread.main == Thread.current }.join"
+ w.close
+ assert_equal("true", r.gets.chomp)
+ assert_equal("false", r.gets.chomp)
+ end
+ end
+
+ def test_abort_on_exception
+ ruby do |w, r, e|
+ w.puts "p Thread.abort_on_exception"
+ w.puts "begin"
+ w.puts " Thread.new { raise }"
+ w.puts " sleep 0.5"
+ w.puts " p 1"
+ w.puts "rescue"
+ w.puts " p 2"
+ w.puts "end"
+ w.close_write
+ assert_equal("false", r.gets.chomp)
+ assert_equal("1", r.gets.chomp)
+ assert_equal("", e.read)
+ end
+
+ ruby do |w, r, e|
+ w.puts "Thread.abort_on_exception = true"
+ w.puts "p Thread.abort_on_exception"
+ w.puts "begin"
+ w.puts " Thread.new { raise }"
+ w.puts " sleep 0.5"
+ w.puts " p 1"
+ w.puts "rescue"
+ w.puts " p 2"
+ w.puts "end"
+ w.close_write
+ assert_equal("true", r.gets.chomp)
+ assert_equal("2", r.gets.chomp)
+ assert_equal("", e.read)
+ end
+
+ ruby('-d') do |w, r, e|
+ w.puts "p Thread.abort_on_exception"
+ w.puts "begin"
+ w.puts " Thread.new { raise }"
+ w.puts " sleep 0.5"
+ w.puts " p 1"
+ w.puts "rescue"
+ w.puts " p 2"
+ w.puts "end"
+ w.close_write
+ assert_equal("false", r.gets.chomp)
+ assert_equal("2", r.gets.chomp)
+ assert_not_equal("", e.read)
+ end
+
+ ruby do |w, r, e|
+ w.puts "p Thread.abort_on_exception"
+ w.puts "begin"
+ w.puts " t = Thread.new { sleep 0.5; raise }"
+ w.puts " t.abort_on_exception = true"
+ w.puts " p t.abort_on_exception"
+ w.puts " sleep 1"
+ w.puts " p 1"
+ w.puts "rescue"
+ w.puts " p 2"
+ w.puts "end"
+ w.close_write
+ assert_equal("false", r.gets.chomp)
+ assert_equal("true", r.gets.chomp)
+ assert_equal("2", r.gets.chomp)
+ assert_equal("", e.read)
+ end
+ end
+
+ def test_status_and_stop_p
+ a = ::Thread.new { raise("die now") }
+ b = Thread.new { Thread.stop }
+ c = Thread.new { Thread.exit }
+ d = Thread.new { sleep }
+ e = Thread.current
+ sleep 0.5
+ d.kill
+
+ assert_equal(nil, a.status)
+ assert_equal("sleep", b.status)
+ assert_equal(false, c.status)
+ assert_match(/^#<TestThread::Thread:.* dead>$/, c.inspect)
+ assert_equal("aborting", d.status)
+ assert_equal("run", e.status)
+
+ assert(a.stop?)
+ assert(b.stop?)
+ assert(c.stop?)
+ assert(!d.stop?)
+ assert(!e.stop?)
+
+ ensure
+ a.kill if a
+ b.kill if b
+ c.kill if c
+ d.kill if d
+ end
+
+ def test_safe_level
+ t = Thread.new { $SAFE = 3; sleep }
+ sleep 0.5
+ assert_equal(0, Thread.current.safe_level)
+ assert_equal(3, t.safe_level)
+
+ ensure
+ t.kill if t
+ end
+
+ def test_thread_local
+ t = Thread.new { sleep }
+
+ assert_equal(false, t.key?(:foo))
+
+ t["foo"] = "foo"
+ t["bar"] = "bar"
+ t["baz"] = "baz"
+
+ assert_equal(true, t.key?(:foo))
+ assert_equal(true, t.key?("foo"))
+ assert_equal(false, t.key?(:qux))
+ assert_equal(false, t.key?("qux"))
+
+ assert_equal([:foo, :bar, :baz], t.keys)
+
+ ensure
+ t.kill if t
+ end
+
+ def test_thread_local_security
+ t = Thread.new { sleep }
+
+ assert_raise(SecurityError) do
+ Thread.new { $SAFE = 4; t[:foo] }.join
+ end
+
+ assert_raise(SecurityError) do
+ Thread.new { $SAFE = 4; t[:foo] = :baz }.join
+ end
+
+ assert_raise(RuntimeError) do
+ Thread.new do
+ Thread.current[:foo] = :bar
+ Thread.current.freeze
+ Thread.current[:foo] = :baz
+ end.join
+ end
+ end
+
+ def test_select_wait
+ assert_nil(IO.select(nil, nil, nil, 1))
+ t = Thread.new do
+ assert_nil(IO.select(nil, nil, nil, nil))
+ end
+ sleep 0.5
+ t.kill
+ end
+
+ def test_mutex_deadlock
+ m = Mutex.new
+ m.synchronize do
+ assert_raise(ThreadError) do
+ m.synchronize do
+ assert(false)
+ end
+ end
+ end
+ end
+
+ def test_mutex_interrupt
+ m = Mutex.new
+ m.lock
+ t = Thread.new do
+ m.lock
+ :foo
+ end
+ sleep 0.5
+ t.kill
+ assert_nil(t.value)
+ end
+
+ def test_mutex_illegal_unlock
+ m = Mutex.new
+ m.lock
+ assert_raise(ThreadError) do
+ Thread.new do
+ m.unlock
+ end.join
+ end
+ end
+
+ def test_recursive_error
+ o = Object.new
+ def o.inspect
+ Thread.current[:__recursive_key__][:inspect] = nil
+ super
+ end
+ assert_raise(TypeError) { [o].inspect }
+ end
end
class TestThreadGroup < Test::Unit::TestCase
@@ -110,25 +444,43 @@ class TestThreadGroup < Test::Unit::TestCase
def test_frozen_thgroup
thgrp = ThreadGroup.new
+
+ t = Thread.new{1}
Thread.new{
thgrp.add(Thread.current)
thgrp.freeze
assert_raise(ThreadError) do
Thread.new{1}.join
end
+ assert_raise(ThreadError) do
+ thgrp.add(t)
+ end
+ assert_raise(ThreadError) do
+ ThreadGroup.new.add Thread.current
+ end
}.join
+ t.join
end
def test_enclosed_thgroup
thgrp = ThreadGroup.new
- thgrp.enclose
+ assert_equal(false, thgrp.enclosed?)
+
+ t = Thread.new{1}
Thread.new{
- assert_raise(ThreadError) do
- thgrp.add(Thread.current)
- end
+ thgrp.add(Thread.current)
+ thgrp.enclose
+ assert_equal(true, thgrp.enclosed?)
assert_nothing_raised do
Thread.new{1}.join
end
+ assert_raise(ThreadError) do
+ thgrp.add t
+ end
+ assert_raise(ThreadError) do
+ ThreadGroup.new.add Thread.current
+ end
}.join
+ t.join
end
end