summaryrefslogtreecommitdiff
path: root/spec/mspec/lib/mspec/runner/actions/timeout.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/mspec/lib/mspec/runner/actions/timeout.rb')
-rw-r--r--spec/mspec/lib/mspec/runner/actions/timeout.rb78
1 files changed, 65 insertions, 13 deletions
diff --git a/spec/mspec/lib/mspec/runner/actions/timeout.rb b/spec/mspec/lib/mspec/runner/actions/timeout.rb
index 543b7366d7..1200926872 100644
--- a/spec/mspec/lib/mspec/runner/actions/timeout.rb
+++ b/spec/mspec/lib/mspec/runner/actions/timeout.rb
@@ -3,6 +3,8 @@ class TimeoutAction
@timeout = timeout
@queue = Queue.new
@started = now
+ @fail = false
+ @error_message = "took longer than the configured timeout of #{@timeout}s"
end
def register
@@ -37,15 +39,26 @@ class TimeoutAction
elapsed = now - @started
if elapsed > @timeout
if @current_state
- STDERR.puts "\nExample took longer than the configured timeout of #{@timeout}s:"
+ STDERR.puts "\nExample #{@error_message}:"
STDERR.puts "#{@current_state.description}"
else
- STDERR.puts "\nSome code outside an example took longer than the configured timeout of #{@timeout}s"
+ STDERR.puts "\nSome code outside an example #{@error_message}"
end
STDERR.flush
show_backtraces
- exit 2
+ if MSpec.subprocesses.empty?
+ exit! 2
+ else
+ # Do not exit but signal the subprocess so we can get their output
+ MSpec.subprocesses.each do |pid|
+ kill_wait_one_second :SIGTERM, pid
+ hard_kill :SIGKILL, pid
+ end
+ @fail = true
+ @current_state = nil
+ break # stop this thread, will fail in #after
+ end
end
end
end
@@ -65,6 +78,11 @@ class TimeoutAction
@queue << -> do
@current_state = nil
end
+
+ if @fail
+ STDERR.puts "\n\nThe last example #{@error_message}. See above for the subprocess stacktrace."
+ exit! 2
+ end
end
def finish
@@ -72,20 +90,54 @@ class TimeoutAction
@thread.join
end
- private def show_backtraces
- if RUBY_ENGINE == 'truffleruby'
- STDERR.puts 'Java stacktraces:'
- Process.kill :SIGQUIT, Process.pid
+ private def hard_kill(signal, pid)
+ begin
+ Process.kill signal, pid
+ rescue Errno::ESRCH
+ # Process already terminated
+ end
+ end
+
+ private def kill_wait_one_second(signal, pid)
+ begin
+ Process.kill signal, pid
sleep 1
+ rescue Errno::ESRCH
+ # Process already terminated
end
+ end
- STDERR.puts "\nRuby backtraces:"
- if defined?(Truffle::Debug.show_backtraces)
- Truffle::Debug.show_backtraces
+ private def show_backtraces
+ java_stacktraces = -> pid {
+ if RUBY_ENGINE == 'truffleruby' || RUBY_ENGINE == 'jruby'
+ STDERR.puts 'Java stacktraces:'
+ kill_wait_one_second :SIGQUIT, pid
+ end
+ }
+
+ if MSpec.subprocesses.empty?
+ java_stacktraces.call Process.pid
+
+ STDERR.puts "\nRuby backtraces:"
+ if defined?(Truffle::Debug.show_backtraces)
+ Truffle::Debug.show_backtraces
+ else
+ Thread.list.each do |thread|
+ unless thread == Thread.current
+ STDERR.puts thread.inspect, thread.backtrace, ''
+ end
+ end
+ end
else
- Thread.list.each do |thread|
- unless thread == Thread.current
- STDERR.puts thread.inspect, thread.backtrace, ''
+ MSpec.subprocesses.each do |pid|
+ STDERR.puts "\nFor subprocess #{pid}"
+ java_stacktraces.call pid
+
+ if RUBY_ENGINE == 'truffleruby'
+ STDERR.puts "\nRuby backtraces:"
+ kill_wait_one_second :SIGALRM, pid
+ else
+ STDERR.puts "Don't know how to print backtraces of a subprocess on #{RUBY_ENGINE}"
end
end
end