summaryrefslogtreecommitdiff
path: root/spec/bundler
diff options
context:
space:
mode:
authorAndrew Haines <andrew@haines.org.nz>2021-07-15 11:36:46 +0100
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2021-07-27 09:25:55 +0900
commit705b1bdef2caf1bee052384b3c62c201f4fa5479 (patch)
tree49528530f5ffaa4a3d354aed7f3a5acd808ba353 /spec/bundler
parentc8172d0b96aa91b421e77ca0bedc3f12ad8c5fdc (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.rb47
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