New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thread.report_on_exception and Thread#report_on_exception #517

Merged
merged 2 commits into from Oct 15, 2017
Jump to file or symbol
Failed to load files and symbols.
+85 −51
Diff settings

Always

Just for now

Viewing a subset of changes. View all
Prev

Enable Thread.report_on_exception = true by default in ruby/spec

* Fix most specs to catch expected exceptions early and not wait until
  the exception pops out of the Thread.
  • Loading branch information...
eregon committed Oct 15, 2017
commit a238a179afe2db653531e6e3beae84cc97d21b38
Copy path View file
@@ -33,14 +33,9 @@
# related to this ML thread.
it "raises a ThreadError when used recursively" do
m = Mutex.new
th = Thread.new do
m.lock
m.lock
-> {
m.lock
end
lambda do
th.join
end.should raise_error(ThreadError)
}.should raise_error(ThreadError)
end
end
@@ -9,12 +9,12 @@
it "raises a RuntimeError if the thread is frozen" do
running = false
t = Thread.new do
Thread.pass until running
t.freeze
t[:foo] = "bar"
-> {
t[:foo] = "bar"
}.should raise_error(RuntimeError, /frozen/)
end
running = true
lambda { t.join }.should raise_error(RuntimeError)
t.join
end
it "raises exceptions on the wrong type of keys" do
@@ -120,7 +120,10 @@ def self.status_of_killed_thread
end
def self.status_of_thread_with_uncaught_exception
t = Thread.new { raise "error" }
t = Thread.new {
Thread.current.report_on_exception = false
raise "error"
}
begin
t.join
rescue RuntimeError
@@ -159,6 +162,7 @@ def self.status_of_dying_thread_after_sleep
def self.dying_thread_ensures(kill_method_name=:kill)
Thread.new do
Thread.current.report_on_exception = false
begin
Thread.current.send(kill_method_name)
ensure
@@ -169,6 +173,7 @@ def self.dying_thread_ensures(kill_method_name=:kill)
def self.dying_thread_with_outer_ensure(kill_method_name=:kill)
Thread.new do
Thread.current.report_on_exception = false
begin
begin
Thread.current.send(kill_method_name)
Copy path View file
@@ -46,7 +46,10 @@
end
it "raises any exceptions encountered in the thread body" do
t = Thread.new { raise NotImplementedError.new("Just kidding") }
t = Thread.new {
Thread.current.report_on_exception = false
raise NotImplementedError.new("Just kidding")
}
lambda { t.join }.should raise_error(NotImplementedError)
end
Copy path View file
@@ -51,6 +51,7 @@
it "is captured and raised by Thread#value" do
t = Thread.new do
Thread.current.report_on_exception = false
sleep
end
@@ -62,6 +63,7 @@
it "raises a RuntimeError when called with no arguments inside rescue" do
t = Thread.new do
Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -113,6 +115,7 @@
it "can go unhandled" do
t = Thread.new do
Thread.current.report_on_exception = false
loop { Thread.pass }
end
@@ -123,6 +126,7 @@
it "raises the given argument even when there is an active exception" do
raised = false
t = Thread.new do
Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -142,6 +146,7 @@
it "raises a RuntimeError when called with no arguments inside rescue" do
raised = false
t = Thread.new do
Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -164,6 +169,7 @@
it "raises a RuntimeError when called with no arguments inside rescue" do
t = Thread.new do
Thread.current.report_on_exception = false
begin
1/0
rescue ZeroDivisionError
@@ -3,7 +3,7 @@
ruby_version_is "2.4" do
describe "Thread.report_on_exception" do
it "defaults to false" do
Thread.report_on_exception.should == false
ruby_exe("p Thread.report_on_exception").should == "false\n"
end
end
Copy path View file
@@ -7,7 +7,10 @@
end
it "re-raises an error for an uncaught exception" do
t = Thread.new { raise "Hello" }
t = Thread.new {
Thread.current.report_on_exception = false
raise "Hello"
}
lambda { t.value }.should raise_error(RuntimeError, "Hello")
end
Copy path View file
@@ -63,15 +63,14 @@
describe "from another thread" do
it "raises a LocalJumpError when getting the value from another thread" do
ScratchPad << :a
thread_with_break = Thread.new do
ScratchPad << :b
break :break
ScratchPad << :c
begin
break :break
rescue LocalJumpError => e
e
end
end
lambda { thread_with_break.value }.should raise_error(LocalJumpError)
ScratchPad.recorded.should == [:a, :b]
thread_with_break.value.should be_an_instance_of(LocalJumpError)
end
end
end
Copy path View file
@@ -24,7 +24,14 @@ def r; return; end
describe "in a Thread" do
it "raises a LocalJumpError if used to exit a thread" do
lambda { Thread.new { return }.join }.should raise_error(LocalJumpError)
t = Thread.new {
begin
return
rescue LocalJumpError => e
e
end
}
t.value.should be_an_instance_of(LocalJumpError)
end
end
Copy path View file
@@ -68,13 +68,14 @@ def throw_method(handler, val)
lambda { catch(:different) { throw :test, 5 } }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if used to exit a thread" do
lambda {
catch(:what) do
Thread.new {
it "raises an UncaughtThrowError if used to exit a thread" do
catch(:what) do
t = Thread.new {
-> {
throw :what
}.join
end
}.should raise_error(ArgumentError)
}.should raise_error(UncaughtThrowError)
}
t.join
end
end
end
@@ -48,14 +48,15 @@
end
it "can be interrupted by Thread#raise" do
t = Thread.new { @server.accept }
t = Thread.new {
-> {
@server.accept
}.should raise_error(Exception, "interrupted")
}
Thread.pass while t.status and t.status != "sleep"
# raise in thread, ensure the raise happens
ex = Exception.new
t.raise ex
lambda { t.join }.should raise_error(Exception)
t.raise Exception, "interrupted"
t.join
end
it "raises an IOError if the socket is closed" do
@@ -48,14 +48,14 @@
it "can be interrupted by Thread#raise" do
t = Thread.new {
@server.accept
-> {
@server.accept
}.should raise_error(Exception, "interrupted")
}
Thread.pass while t.status and t.status != "sleep"
# raise in thread, ensure the raise happens
ex = Exception.new
t.raise ex
lambda { t.join }.should raise_error(Exception)
Thread.pass while t.status and t.status != "sleep"
t.raise Exception, "interrupted"
t.join
end
end
end
Copy path View file
@@ -78,8 +78,11 @@ def call_capi_rb_thread_wakeup
end
it "handles throwing an exception in the thread" do
proc = lambda { |x| raise "my error" }
thr = @t.rb_thread_create(proc, nil)
prc = lambda { |x|
Thread.current.report_on_exception = false
raise "my error"
}
thr = @t.rb_thread_create(prc, nil)
thr.should be_kind_of(Thread)
lambda {
Copy path View file
@@ -10,13 +10,13 @@
end
it "raises a FiberError if invoked from a different Thread" do
fiber = Fiber.new { }
lambda do
Thread.new do
fiber = Fiber.new { 42 }
Thread.new do
-> {
fiber.resume
end.join
end.should raise_error(FiberError)
fiber.resume
}.should raise_error(FiberError)
end.join
fiber.resume.should == 42
end
it "passes control to the beginning of the block on first invocation" do
Copy path View file
@@ -3,6 +3,17 @@
dir = "fixtures/code"
CODE_LOADING_DIR = use_realpath ? File.realpath(dir, root) : File.expand_path(dir, root)
# Enable Thread.report_on_exception by default to catch thread errors earlier
if Thread.respond_to? :report_on_exception=
Thread.report_on_exception = true
else
class Thread
def report_on_exception=(value)
raise "shim Thread#report_on_exception used with true" if value
end
end
end
# Running directly with ruby some_spec.rb
unless ENV['MSPEC_RUNNER']
begin
ProTip! Use n and p to navigate between commits in a pull request.