diff options
author | Andrew Haines <andrew@haines.org.nz> | 2021-07-15 11:36:46 +0100 |
---|---|---|
committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-07-27 09:25:55 +0900 |
commit | 705b1bdef2caf1bee052384b3c62c201f4fa5479 (patch) | |
tree | 49528530f5ffaa4a3d354aed7f3a5acd808ba353 /spec/bundler | |
parent | c8172d0b96aa91b421e77ca0bedc3f12ad8c5fdc (diff) |
[rubygems/rubygems] Fix interrupt handling in Bundler workers
The existing interrupt handling using `SharedHelpers.trap` fails when the previous
handler for a signal is not callable (for example, when it is the string "DEFAULT").
Instead, we now handle interrupts by aborting the process when worker threads are
running, and restore the previous handler after worker threads are finished.
Fixes #4764.
https://github.com/rubygems/rubygems/commit/b9f455d487
Diffstat (limited to 'spec/bundler')
-rw-r--r-- | spec/bundler/bundler/worker_spec.rb | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/spec/bundler/bundler/worker_spec.rb b/spec/bundler/bundler/worker_spec.rb index 2e5642709d..e4ebbd2932 100644 --- a/spec/bundler/bundler/worker_spec.rb +++ b/spec/bundler/bundler/worker_spec.rb @@ -19,4 +19,51 @@ RSpec.describe Bundler::Worker do end end end + + describe "handling interrupts" do + let(:status) do + pid = Process.fork do + $stderr.reopen File.new("/dev/null", "w") + Signal.trap "INT", previous_interrupt_handler + subject.enq "a" + subject.stop unless interrupt_before_stopping + Process.kill "INT", Process.pid + end + + Process.wait2(pid).last + end + + before do + skip "requires Process.fork" unless Process.respond_to?(:fork) + end + + context "when interrupted before stopping" do + let(:interrupt_before_stopping) { true } + let(:previous_interrupt_handler) { ->(*) { exit 0 } } + + it "aborts" do + expect(status.exitstatus).to eq(1) + end + end + + context "when interrupted after stopping" do + let(:interrupt_before_stopping) { false } + + context "when the previous interrupt handler was the default" do + let(:previous_interrupt_handler) { "DEFAULT" } + + it "uses the default interrupt handler" do + expect(status).to be_signaled + end + end + + context "when the previous interrupt handler was customized" do + let(:previous_interrupt_handler) { ->(*) { exit 42 } } + + it "restores the custom interrupt handler after stopping" do + expect(status.exitstatus).to eq(42) + end + end + end + end end |