diff options
Diffstat (limited to 'test/ruby/test_thread_queue.rb')
-rw-r--r-- | test/ruby/test_thread_queue.rb | 173 |
1 files changed, 122 insertions, 51 deletions
diff --git a/test/ruby/test_thread_queue.rb b/test/ruby/test_thread_queue.rb index 6185abff9f..545bf98888 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 @@ -66,7 +75,7 @@ class TestThreadQueue < Test::Unit::TestCase [e, "Enumerable"], [Struct.new(:to_a), "Array-like"], ) do |a, type| - q = Queue.new(a.new([1,2,3])) + 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) @@ -77,14 +86,14 @@ class TestThreadQueue < Test::Unit::TestCase 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) @@ -104,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) @@ -142,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? @@ -151,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 = EnvUtil.apply_timeout_scale(60) + 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 @@ -178,20 +242,20 @@ class TestThreadQueue < Test::Unit::TestCase 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 @@ -212,19 +276,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 @@ -247,7 +311,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 @@ -277,7 +341,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 @@ -287,12 +351,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 @@ -304,7 +368,7 @@ 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 @@ -343,15 +407,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 @@ -368,7 +432,7 @@ class TestThreadQueue < Test::Unit::TestCase # 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 @@ -394,13 +458,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 @@ -446,9 +510,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 @@ -466,7 +530,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 } @@ -478,7 +542,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 @@ -510,14 +574,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} @@ -525,14 +589,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 @@ -550,9 +619,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 @@ -580,14 +651,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' } @@ -604,8 +675,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? |