1 # frozen_string_literal: false
5 class TestTimeout < Test::Unit::TestCase
7 def test_work_is_done_in_same_thread_as_caller
8 assert_equal Thread.current, Timeout.timeout(10){ Thread.current }
11 def test_work_is_done_in_same_fiber_as_caller
12 require 'fiber' # needed for ruby 3.0 and lower
13 assert_equal Fiber.current, Timeout.timeout(10){ Fiber.current }
16 def test_non_timing_out_code_is_successful
17 assert_nothing_raised do
18 assert_equal :ok, Timeout.timeout(1){ :ok }
22 def test_allows_zero_seconds
23 assert_nothing_raised do
24 assert_equal :ok, Timeout.timeout(0){:ok}
28 def test_allows_nil_seconds
29 assert_nothing_raised do
30 assert_equal :ok, Timeout.timeout(nil){:ok}
41 assert_nothing_raised do
42 assert_equal :ok, c.new.test
47 assert_equal [5, :ok], Timeout.timeout(5){|s| [s, :ok] }
52 assert_raise(Timeout::Error, "[ruby-dev:32935]") {
53 Timeout.timeout(0.01) { q.pop }
58 assert_raise(Timeout::Error) do
59 Timeout.timeout(0.1) {
65 def test_nested_timeout
67 assert_raise(Timeout::Error) do
68 Timeout.timeout(0.1) {
78 class MyNewErrorOuter < StandardError; end
79 class MyNewErrorInner < StandardError; end
82 # - raise new(message) if exc.equal?(e)
83 # + raise new(message) if exc.class == e.class
84 def test_nested_timeout_error_identity
86 Timeout.timeout(0.1, MyNewErrorOuter) {
87 Timeout.timeout(1, MyNewErrorInner) {
92 assert e.class == MyNewErrorOuter
97 # - raise new(message) if exc.equal?(e)
98 # + raise new(message) if exc.class == e.class
99 def test_nested_timeout_which_error_bubbles_up
100 raised_exception = nil
102 Timeout.timeout(0.1) {
104 raise Timeout::ExitException.new("inner message")
107 rescue Exception => e
111 assert_equal 'inner message', raised_exception.message
114 def test_cannot_convert_into_time_interval
115 bug3168 = '[ruby-dev:41010]'
116 def (n = Object.new).zero?; false; end
117 assert_raise(TypeError, bug3168) {Timeout.timeout(n) { sleep 0.1 }}
120 def test_skip_rescue_standarderror
122 assert_raise_with_message(Timeout::Error, /execution expired/) do
123 Timeout.timeout 0.01 do
127 flunk "should not see any exception but saw #{e.inspect}"
133 def test_raises_exception_internally
135 assert_raise_with_message(Timeout::Error, /execution expired/) do
136 Timeout.timeout 0.01 do
139 rescue Exception => exc
145 assert_equal Timeout::ExitException, e.class
149 exc = Class.new(RuntimeError)
151 assert_nothing_raised(exc) do
152 Timeout.timeout 0.01, exc do
159 assert_raise_with_message(exc, 'execution expired') {raise e if e}
162 def test_custom_exception
163 bug9354 = '[ruby-core:59511] [Bug #9354]'
164 err = Class.new(StandardError) do
165 def initialize(msg) super end
167 assert_nothing_raised(ArgumentError, bug9354) do
168 assert_equal(:ok, Timeout.timeout(100, err) {:ok})
170 assert_raise_with_message(err, 'execution expired') do
171 Timeout.timeout 0.01, err do
175 assert_raise_with_message(err, /connection to ruby-lang.org expired/) do
176 Timeout.timeout 0.01, err, "connection to ruby-lang.org expired" do
182 def test_exit_exception
183 assert_raise_with_message(Timeout::Error, "boon") do
184 Timeout.timeout(10, Timeout::Error) do
185 raise Timeout::Error, "boon"
190 def test_raise_with_message
191 bug17812 = '[ruby-core:103502] [Bug #17812]: Timeout::Error doesn\'t let two-argument raise() set a new message'
192 exc = Timeout::Error.new('foo')
193 assert_raise_with_message(Timeout::Error, 'bar', bug17812) do
198 def test_enumerator_next
199 bug9380 = '[ruby-dev:47872] [Bug #9380]: timeout in Enumerator#next'
200 e = (o=Object.new).to_enum
204 assert_raise_with_message(Timeout::Error, 'execution expired', bug9380) do
205 Timeout.timeout(0.01) {e.next}
209 def test_handle_interrupt
210 bug11344 = '[ruby-dev:49179] [Bug #11344]'
212 assert_raise(Timeout::Error) {
213 Thread.handle_interrupt(Timeout::ExitException => :never) {
214 Timeout.timeout(0.01) {
217 Thread.handle_interrupt(Timeout::ExitException => :on_blocking) {
227 omit 'fork not supported' unless Process.respond_to?(:fork)
232 r = Timeout.timeout(0.01) { sleep 5 }
234 rescue Timeout::Error
242 assert_equal 'timeout', r.read
247 assert_separately(%w[-rtimeout], <<-'end;')
250 tg.add(Thread.current)
251 Timeout.timeout(10){}
254 assert_equal [].to_s, tg.list.to_s
258 # https://github.com/ruby/timeout/issues/24
259 def test_handling_enclosed_threadgroup
260 assert_separately(%w[-rtimeout], <<-'end;')
263 group = ThreadGroup.new
267 assert_equal 42, Timeout.timeout(1) { 42 }