summaryrefslogtreecommitdiff
path: root/test/ruby/test_thread_queue.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_thread_queue.rb')
-rw-r--r--test/ruby/test_thread_queue.rb205
1 files changed, 152 insertions, 53 deletions
diff --git a/test/ruby/test_thread_queue.rb b/test/ruby/test_thread_queue.rb
index 13c839ab50..9a41be8b1a 100644
--- a/test/ruby/test_thread_queue.rb
+++ b/test/ruby/test_thread_queue.rb
@@ -8,17 +8,26 @@ class TestThreadQueue < Test::Unit::TestCase
SizedQueue = Thread::SizedQueue
def test_queue_initialized
- assert_raise(TypeError) {
+ assert_raise_with_message(TypeError, /\bQueue.* not initialized/) {
Queue.allocate.push(nil)
}
end
def test_sized_queue_initialized
- assert_raise(TypeError) {
+ assert_raise_with_message(TypeError, /\bSizedQueue.* not initialized/) {
SizedQueue.allocate.push(nil)
}
end
+ def test_freeze
+ assert_raise(TypeError) {
+ Queue.new.freeze
+ }
+ assert_raise(TypeError) {
+ SizedQueue.new(5).freeze
+ }
+ end
+
def test_queue
grind(5, 1000, 15, Queue)
end
@@ -54,15 +63,37 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal 0, to_workers.size
end
+ def test_queue_initialize
+ e = Class.new do
+ include Enumerable
+ def initialize(list) @list = list end
+ def each(&block) @list.each(&block) end
+ end
+
+ all_assertions_foreach(nil,
+ [Array, "Array"],
+ [e, "Enumerable"],
+ [Struct.new(:to_a), "Array-like"],
+ ) do |a, type|
+ q = Thread::Queue.new(a.new([1,2,3]))
+ assert_equal(3, q.size, type)
+ assert_not_predicate(q, :empty?, type)
+ assert_equal(1, q.pop, type)
+ assert_equal(2, q.pop, type)
+ assert_equal(3, q.pop, type)
+ assert_predicate(q, :empty?, type)
+ end
+ end
+
def test_sized_queue_initialize
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
assert_equal 1, q.max
- assert_raise(ArgumentError) { SizedQueue.new(0) }
- assert_raise(ArgumentError) { SizedQueue.new(-1) }
+ assert_raise(ArgumentError) { Thread::SizedQueue.new(0) }
+ assert_raise(ArgumentError) { Thread::SizedQueue.new(-1) }
end
def test_sized_queue_assign_max
- q = SizedQueue.new(2)
+ q = Thread::SizedQueue.new(2)
assert_equal(2, q.max)
q.max = 1
assert_equal(1, q.max)
@@ -82,37 +113,90 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_queue_pop_interrupt
- q = Queue.new
+ q = Thread::Queue.new
t1 = Thread.new { q.pop }
sleep 0.01 until t1.stop?
t1.kill.join
assert_equal(0, q.num_waiting)
end
+ def test_queue_pop_timeout
+ q = Thread::Queue.new
+ q << 1
+ assert_equal 1, q.pop(timeout: 1)
+
+ t1 = Thread.new { q.pop(timeout: 1) }
+ assert_equal t1, t1.join(2)
+ assert_nil t1.value
+
+ t2 = Thread.new { q.pop(timeout: 0.1) }
+ assert_equal t2, t2.join(1)
+ assert_nil t2.value
+ ensure
+ t1&.kill&.join
+ t2&.kill&.join
+ end
+
def test_queue_pop_non_block
- q = Queue.new
+ q = Thread::Queue.new
assert_raise_with_message(ThreadError, /empty/) do
q.pop(true)
end
end
def test_sized_queue_pop_interrupt
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
t1 = Thread.new { q.pop }
sleep 0.01 until t1.stop?
t1.kill.join
assert_equal(0, q.num_waiting)
end
+ def test_sized_queue_pop_timeout
+ q = Thread::SizedQueue.new(1)
+
+ q << 1
+ assert_equal 1, q.pop(timeout: 1)
+
+ t1 = Thread.new { q.pop(timeout: 1) }
+ assert_equal t1, t1.join(2)
+ assert_nil t1.value
+
+ t2 = Thread.new { q.pop(timeout: 0.1) }
+ assert_equal t2, t2.join(1)
+ assert_nil t2.value
+ ensure
+ t1&.kill&.join
+ t2&.kill&.join
+ end
+
def test_sized_queue_pop_non_block
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
assert_raise_with_message(ThreadError, /empty/) do
q.pop(true)
end
end
+ def test_sized_queue_push_timeout
+ q = Thread::SizedQueue.new(1)
+
+ q << 1
+ assert_equal 1, q.size
+
+ t1 = Thread.new { q.push(2, timeout: 1) }
+ assert_equal t1, t1.join(2)
+ assert_nil t1.value
+
+ t2 = Thread.new { q.push(2, timeout: 0.1) }
+ assert_equal t2, t2.join(1)
+ assert_nil t2.value
+ ensure
+ t1&.kill&.join
+ t2&.kill&.join
+ end
+
def test_sized_queue_push_interrupt
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
q.push(1)
assert_raise_with_message(ThreadError, /full/) do
q.push(2, true)
@@ -120,7 +204,7 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_sized_queue_push_non_block
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
q.push(1)
t1 = Thread.new { q.push(2) }
sleep 0.01 until t1.stop?
@@ -129,16 +213,18 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_thr_kill
+ omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM
+
bug5343 = '[ruby-core:39634]'
Dir.mktmpdir {|d|
timeout = 60
total_count = 250
begin
- assert_normal_exit(<<-"_eom", bug5343, **{:timeout => timeout, :chdir=>d})
+ assert_normal_exit(<<-"_eom", bug5343, timeout: timeout, chdir: d)
+ r, w = IO.pipe
#{total_count}.times do |i|
- open("test_thr_kill_count", "w") {|f| f.puts i }
- queue = Queue.new
- r, w = IO.pipe
+ File.open("test_thr_kill_count", "w") {|f| f.puts i }
+ queue = Thread::Queue.new
th = Thread.start {
queue.push(nil)
r.read 1
@@ -149,27 +235,33 @@ class TestThreadQueue < Test::Unit::TestCase
end
_eom
rescue Timeout::Error
+ # record load average:
+ uptime = `uptime` rescue nil
+ if uptime && /(load average: [\d.]+),/ =~ uptime
+ la = " (#{$1})"
+ end
+
count = File.read("#{d}/test_thr_kill_count").to_i
- flunk "only #{count}/#{total_count} done in #{timeout} seconds."
+ flunk "only #{count}/#{total_count} done in #{timeout} seconds.#{la}"
end
}
end
def test_queue_push_return_value
- q = Queue.new
+ q = Thread::Queue.new
retval = q.push(1)
assert_same q, retval
end
def test_queue_clear_return_value
- q = Queue.new
+ q = Thread::Queue.new
retval = q.clear
assert_same q, retval
end
def test_sized_queue_clear
- # Fill queue, then test that SizedQueue#clear wakes up all waiting threads
- sq = SizedQueue.new(2)
+ # Fill queue, then test that Thread::SizedQueue#clear wakes up all waiting threads
+ sq = Thread::SizedQueue.new(2)
2.times { sq << 1 }
t1 = Thread.new do
@@ -190,19 +282,19 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_sized_queue_push_return_value
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
retval = q.push(1)
assert_same q, retval
end
def test_sized_queue_clear_return_value
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
retval = q.clear
assert_same q, retval
end
def test_sized_queue_throttle
- q = SizedQueue.new(1)
+ q = Thread::SizedQueue.new(1)
i = 0
consumer = Thread.new do
while q.pop
@@ -225,7 +317,7 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_queue_thread_raise
- q = Queue.new
+ q = Thread::Queue.new
th1 = Thread.new do
begin
q.pop
@@ -255,7 +347,7 @@ class TestThreadQueue < Test::Unit::TestCase
def test_dup
bug9440 = '[ruby-core:59961] [Bug #9440]'
- q = Queue.new
+ q = Thread::Queue.new
assert_raise(NoMethodError, bug9440) do
q.dup
end
@@ -265,12 +357,12 @@ class TestThreadQueue < Test::Unit::TestCase
def test_dump
bug9674 = '[ruby-core:61677] [Bug #9674]'
- q = Queue.new
+ q = Thread::Queue.new
assert_raise_with_message(TypeError, /#{Queue}/, bug9674) do
Marshal.dump(q)
end
- sq = SizedQueue.new(1)
+ sq = Thread::SizedQueue.new(1)
assert_raise_with_message(TypeError, /#{SizedQueue}/, bug9674) do
Marshal.dump(sq)
end
@@ -282,12 +374,12 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_close
- [->{Queue.new}, ->{SizedQueue.new 3}].each do |qcreate|
+ [->{Thread::Queue.new}, ->{Thread::SizedQueue.new 3}].each do |qcreate|
q = qcreate.call
assert_equal false, q.closed?
q << :something
assert_equal q, q.close
- assert q.closed?
+ assert_predicate q, :closed?
assert_raise_with_message(ClosedQueueError, /closed/){q << :nothing}
assert_equal q.pop, :something
assert_nil q.pop
@@ -321,15 +413,15 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_queue_close_wakeup
- close_wakeup(15, 18){Queue.new}
+ close_wakeup(15, 18){Thread::Queue.new}
end
def test_size_queue_close_wakeup
- close_wakeup(5, 8){SizedQueue.new 9}
+ close_wakeup(5, 8){Thread::SizedQueue.new 9}
end
def test_sized_queue_one_closed_interrupt
- q = SizedQueue.new 1
+ q = Thread::SizedQueue.new 1
q << :one
t1 = Thread.new {
Thread.current.report_on_exception = false
@@ -341,12 +433,12 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal 1, q.size
assert_equal :one, q.pop
- assert q.empty?, "queue not empty"
+ assert_empty q
end
# make sure that shutdown state is handled properly by empty? for the non-blocking case
def test_empty_non_blocking
- q = SizedQueue.new 3
+ q = Thread::SizedQueue.new 3
3.times{|i| q << i}
# these all block cos the queue is full
@@ -372,13 +464,13 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_sized_queue_closed_push_non_blocking
- q = SizedQueue.new 7
+ q = Thread::SizedQueue.new 7
q.close
assert_raise_with_message(ClosedQueueError, /queue closed/){q.push(non_block=true)}
end
def test_blocked_pushers
- q = SizedQueue.new 3
+ q = Thread::SizedQueue.new 3
prod_threads = 6.times.map do |i|
thr = Thread.new{
Thread.current.report_on_exception = false
@@ -424,9 +516,9 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_deny_pushers
- [->{Queue.new}, ->{SizedQueue.new 3}].each do |qcreate|
+ [->{Thread::Queue.new}, ->{Thread::SizedQueue.new 3}].each do |qcreate|
q = qcreate[]
- synq = Queue.new
+ synq = Thread::Queue.new
prod_threads = 20.times.map do |i|
Thread.new {
synq.pop
@@ -444,7 +536,7 @@ class TestThreadQueue < Test::Unit::TestCase
# size should account for waiting pushers during shutdown
def sized_queue_size_close
- q = SizedQueue.new 4
+ q = Thread::SizedQueue.new 4
4.times{|i| q << i}
Thread.new{ q << 5 }
Thread.new{ q << 6 }
@@ -456,7 +548,7 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_blocked_pushers_empty
- q = SizedQueue.new 3
+ q = Thread::SizedQueue.new 3
prod_threads = 6.times.map do |i|
Thread.new{
Thread.current.report_on_exception = false
@@ -475,7 +567,7 @@ class TestThreadQueue < Test::Unit::TestCase
assert_equal 0, q.size
assert_equal 3, ary.size
- ary.each{|e| assert [0,1,2,3,4,5].include?(e)}
+ ary.each{|e| assert_include [0,1,2,3,4,5], e}
assert_nil q.pop
prod_threads.each{|t|
@@ -488,14 +580,14 @@ class TestThreadQueue < Test::Unit::TestCase
# test thread wakeup on one-element SizedQueue with close
def test_one_element_sized_queue
- q = SizedQueue.new 1
+ q = Thread::SizedQueue.new 1
t = Thread.new{ q.pop }
q.close
assert_nil t.value
end
def test_close_twice
- [->{Queue.new}, ->{SizedQueue.new 3}].each do |qcreate|
+ [->{Thread::Queue.new}, ->{Thread::SizedQueue.new 3}].each do |qcreate|
q = qcreate[]
q.close
assert_nothing_raised(ClosedQueueError){q.close}
@@ -503,14 +595,19 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_queue_close_multi_multi
- q = SizedQueue.new rand(800..1200)
+ q = Thread::SizedQueue.new rand(800..1200)
count_items = rand(3000..5000)
count_producers = rand(10..20)
+ # ensure threads do not start running too soon and complete before we check status
+ mutex = Mutex.new
+ mutex.lock
+
producers = count_producers.times.map do
Thread.new do
- sleep(rand / 100)
+ mutex.lock
+ mutex.unlock
count_items.times{|i| q << [i,"#{i} for #{Thread.current.inspect}"]}
end
end
@@ -528,9 +625,11 @@ class TestThreadQueue < Test::Unit::TestCase
# No dead or finished threads, give up to 10 seconds to start running
t = Time.now
- Thread.pass until Time.now - t > 10 || (consumers + producers).all?{|thr| thr.status =~ /\A(?:run|sleep)\z/}
+ Thread.pass until Time.now - t > 10 || (consumers + producers).all?{|thr| thr.status.to_s =~ /\A(?:run|sleep)\z/}
+
+ assert (consumers + producers).all?{|thr| thr.status.to_s =~ /\A(?:run|sleep)\z/}, 'no threads running'
- assert (consumers + producers).all?{|thr| thr.status =~ /\A(?:run|sleep)\z/}, 'no threads running'
+ mutex.unlock
# just exercising the concurrency of the support methods.
counter = Thread.new do
@@ -558,14 +657,14 @@ class TestThreadQueue < Test::Unit::TestCase
def test_queue_with_trap
if ENV['APPVEYOR'] == 'True' && RUBY_PLATFORM.match?(/mswin/)
- skip 'This test fails too often on AppVeyor vs140'
+ omit 'This test fails too often on AppVeyor vs140'
end
if RUBY_PLATFORM.match?(/mingw/)
- skip 'This test fails too often on MinGW'
+ omit 'This test fails too often on MinGW'
end
assert_in_out_err([], <<-INPUT, %w(INT INT exit), [])
- q = Queue.new
+ q = Thread::Queue.new
trap(:INT){
q.push 'INT'
}
@@ -582,8 +681,8 @@ class TestThreadQueue < Test::Unit::TestCase
end
def test_fork_while_queue_waiting
- q = Queue.new
- sq = SizedQueue.new(1)
+ q = Thread::Queue.new
+ sq = Thread::SizedQueue.new(1)
thq = Thread.new { q.pop }
thsq = Thread.new { sq.pop }
Thread.pass until thq.stop? && thsq.stop?