[ruby/irb] Extract integration testing helpers out of debug command
tests (https://github.com/ruby/irb/pull/660) The ability to run a test case in a subprocess is useful for testing many other features, like nested IRB sessions. So I think it's worth extracting them into a new test case class. https://github.com/ruby/irb/commit/73b7a895f8
This commit is contained in:
parent
dc54574ade
commit
8ecd300e1e
@ -7,6 +7,11 @@ begin
|
||||
rescue LoadError # ruby/ruby defines helpers differently
|
||||
end
|
||||
|
||||
begin
|
||||
require "pty"
|
||||
rescue LoadError # some platforms don't support PTY
|
||||
end
|
||||
|
||||
module IRB
|
||||
class InputMethod; end
|
||||
end
|
||||
@ -73,4 +78,109 @@ module TestIRB
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class IntegrationTestCase
|
||||
LIB = File.expand_path("../../lib", __dir__)
|
||||
TIMEOUT_SEC = 3
|
||||
|
||||
def setup
|
||||
unless defined?(PTY)
|
||||
omit "Integration tests require PTY."
|
||||
end
|
||||
end
|
||||
|
||||
def run_ruby_file(&block)
|
||||
cmd = [EnvUtil.rubybin, "-I", LIB, @ruby_file.to_path]
|
||||
tmp_dir = Dir.mktmpdir
|
||||
|
||||
@commands = []
|
||||
lines = []
|
||||
|
||||
yield
|
||||
|
||||
PTY.spawn(integration_envs.merge("TERM" => "dumb"), *cmd) do |read, write, pid|
|
||||
Timeout.timeout(TIMEOUT_SEC) do
|
||||
while line = safe_gets(read)
|
||||
lines << line
|
||||
|
||||
# means the breakpoint is triggered
|
||||
if line.match?(/binding\.irb/)
|
||||
while command = @commands.shift
|
||||
write.puts(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
read.close
|
||||
write.close
|
||||
kill_safely(pid)
|
||||
end
|
||||
|
||||
lines.join
|
||||
rescue Timeout::Error
|
||||
message = <<~MSG
|
||||
Test timedout.
|
||||
|
||||
#{'=' * 30} OUTPUT #{'=' * 30}
|
||||
#{lines.map { |l| " #{l}" }.join}
|
||||
#{'=' * 27} END OF OUTPUT #{'=' * 27}
|
||||
MSG
|
||||
assert_block(message) { false }
|
||||
ensure
|
||||
File.unlink(@ruby_file) if @ruby_file
|
||||
FileUtils.remove_entry tmp_dir
|
||||
end
|
||||
|
||||
# read.gets could raise exceptions on some platforms
|
||||
# https://github.com/ruby/ruby/blob/master/ext/pty/pty.c#L721-L728
|
||||
def safe_gets(read)
|
||||
read.gets
|
||||
rescue Errno::EIO
|
||||
nil
|
||||
end
|
||||
|
||||
def kill_safely pid
|
||||
return if wait_pid pid, TIMEOUT_SEC
|
||||
|
||||
Process.kill :TERM, pid
|
||||
return if wait_pid pid, 0.2
|
||||
|
||||
Process.kill :KILL, pid
|
||||
Process.waitpid(pid)
|
||||
rescue Errno::EPERM, Errno::ESRCH
|
||||
end
|
||||
|
||||
def wait_pid pid, sec
|
||||
total_sec = 0.0
|
||||
wait_sec = 0.001 # 1ms
|
||||
|
||||
while total_sec < sec
|
||||
if Process.waitpid(pid, Process::WNOHANG) == pid
|
||||
return true
|
||||
end
|
||||
sleep wait_sec
|
||||
total_sec += wait_sec
|
||||
wait_sec *= 2
|
||||
end
|
||||
|
||||
false
|
||||
rescue Errno::ECHILD
|
||||
true
|
||||
end
|
||||
|
||||
def type(command)
|
||||
@commands << command
|
||||
end
|
||||
|
||||
def write_ruby(program)
|
||||
@ruby_file = Tempfile.create(%w{irb- .rb})
|
||||
@ruby_file.write(program)
|
||||
@ruby_file.close
|
||||
end
|
||||
|
||||
def integration_envs
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,24 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
begin
|
||||
require "pty"
|
||||
rescue LoadError
|
||||
return
|
||||
end
|
||||
|
||||
require "tempfile"
|
||||
require "tmpdir"
|
||||
|
||||
require_relative "helper"
|
||||
|
||||
module TestIRB
|
||||
LIB = File.expand_path("../../lib", __dir__)
|
||||
|
||||
class DebugCommandTestCase < TestCase
|
||||
IRB_AND_DEBUGGER_OPTIONS = {
|
||||
"NO_COLOR" => "true", "RUBY_DEBUG_HISTORY_FILE" => ''
|
||||
}
|
||||
|
||||
class DebugCommandTest < IntegrationTestCase
|
||||
def setup
|
||||
if ruby_core?
|
||||
omit "This test works only under ruby/irb"
|
||||
@ -204,96 +192,8 @@ module TestIRB
|
||||
|
||||
private
|
||||
|
||||
TIMEOUT_SEC = 3
|
||||
|
||||
def run_ruby_file(&block)
|
||||
cmd = [EnvUtil.rubybin, "-I", LIB, @ruby_file.to_path]
|
||||
tmp_dir = Dir.mktmpdir
|
||||
|
||||
@commands = []
|
||||
lines = []
|
||||
|
||||
yield
|
||||
|
||||
PTY.spawn(IRB_AND_DEBUGGER_OPTIONS.merge("TERM" => "dumb"), *cmd) do |read, write, pid|
|
||||
Timeout.timeout(TIMEOUT_SEC) do
|
||||
while line = safe_gets(read)
|
||||
lines << line
|
||||
|
||||
# means the breakpoint is triggered
|
||||
if line.match?(/binding\.irb/)
|
||||
while command = @commands.shift
|
||||
write.puts(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
read.close
|
||||
write.close
|
||||
kill_safely(pid)
|
||||
end
|
||||
|
||||
lines.join
|
||||
rescue Timeout::Error
|
||||
message = <<~MSG
|
||||
Test timedout.
|
||||
|
||||
#{'=' * 30} OUTPUT #{'=' * 30}
|
||||
#{lines.map { |l| " #{l}" }.join}
|
||||
#{'=' * 27} END OF OUTPUT #{'=' * 27}
|
||||
MSG
|
||||
assert_block(message) { false }
|
||||
ensure
|
||||
File.unlink(@ruby_file) if @ruby_file
|
||||
FileUtils.remove_entry tmp_dir
|
||||
end
|
||||
|
||||
# read.gets could raise exceptions on some platforms
|
||||
# https://github.com/ruby/ruby/blob/master/ext/pty/pty.c#L729-L736
|
||||
def safe_gets(read)
|
||||
read.gets
|
||||
rescue Errno::EIO
|
||||
nil
|
||||
end
|
||||
|
||||
def kill_safely pid
|
||||
return if wait_pid pid, TIMEOUT_SEC
|
||||
|
||||
Process.kill :TERM, pid
|
||||
return if wait_pid pid, 0.2
|
||||
|
||||
Process.kill :KILL, pid
|
||||
Process.waitpid(pid)
|
||||
rescue Errno::EPERM, Errno::ESRCH
|
||||
end
|
||||
|
||||
def wait_pid pid, sec
|
||||
total_sec = 0.0
|
||||
wait_sec = 0.001 # 1ms
|
||||
|
||||
while total_sec < sec
|
||||
if Process.waitpid(pid, Process::WNOHANG) == pid
|
||||
return true
|
||||
end
|
||||
sleep wait_sec
|
||||
total_sec += wait_sec
|
||||
wait_sec *= 2
|
||||
end
|
||||
|
||||
false
|
||||
rescue Errno::ECHILD
|
||||
true
|
||||
end
|
||||
|
||||
def type(command)
|
||||
@commands << command
|
||||
end
|
||||
|
||||
def write_ruby(program)
|
||||
@ruby_file = Tempfile.create(%w{irb- .rb})
|
||||
@ruby_file.write(program)
|
||||
@ruby_file.close
|
||||
def integration_envs
|
||||
{ "NO_COLOR" => "true", "RUBY_DEBUG_HISTORY_FILE" => '' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user