diff --git a/lib/parallel_tests.rb b/lib/parallel_tests.rb index 33ad3f69..df99842e 100644 --- a/lib/parallel_tests.rb +++ b/lib/parallel_tests.rb @@ -56,8 +56,8 @@ def pid_file_path ENV.fetch('PARALLEL_PID_FILE') end - def stop_all_processes - pids.all.each { |pid| Process.kill(:INT, pid) } + def stop_all_processes(signal) + pids.all.each { |pid| Process.kill(signal, pid) } rescue Errno::ESRCH, Errno::EPERM # Process already terminated, do nothing end diff --git a/lib/parallel_tests/cli.rb b/lib/parallel_tests/cli.rb index d53fbef5..0521ccc9 100644 --- a/lib/parallel_tests/cli.rb +++ b/lib/parallel_tests/cli.rb @@ -7,8 +7,11 @@ module ParallelTests class CLI + SIGNALS = %w[INT TERM] def run(argv) - Signal.trap("INT") { handle_interrupt } + SIGNALS.each do |signal| + Signal.trap(signal) { handle_interrupt(signal) } + end options = parse_options!(argv) @@ -28,7 +31,7 @@ def run(argv) private - def handle_interrupt + def handle_interrupt(signal) @graceful_shutdown_attempted ||= false Kernel.exit if @graceful_shutdown_attempted @@ -46,7 +49,7 @@ def handle_interrupt # using Thread workaround https://github.com/ddollar/foreman/issues/332 Thread.new do if Gem.win_platform? || ((child_pid = ParallelTests.pids.all.first) && Process.getpgid(child_pid) != Process.pid) - ParallelTests.stop_all_processes + ParallelTests.stop_all_processes(signal) end end diff --git a/spec/integration_spec.rb b/spec/integration_spec.rb index a51069a3..24d566ac 100644 --- a/spec/integration_spec.rb +++ b/spec/integration_spec.rb @@ -722,6 +722,21 @@ class A < Spinach::FeatureSteps expect(result).to_not include("Should not get here either") end + it "passes on term signal to child processes", unless: Gem.win_platform? do + timeout = 2 + write( + "spec/test_spec.rb", + "sleep #{timeout}; describe { specify { p 'Should not get here' }; specify { p 'Should not get here either'} }" + ) + pid = nil + Thread.new { sleep timeout - 1.0; Process.kill("TERM", pid) } + result = run_tests(["spec"], processes: 2, type: 'rspec', fail: true) { |io| pid = io.pid } + + expect(result).to include("RSpec is shutting down") + expect(result).to_not include("Should not get here") + expect(result).to_not include("Should not get here either") + end + # Process.kill on Windows doesn't work as expected. It kills all process group instead of just one process. it "exits immediately if another int signal is received", unless: Gem.win_platform? do timeout = 2