Skip to content

Commit

Permalink
Update test/lib
Browse files Browse the repository at this point in the history
  • Loading branch information
nobu committed Oct 2, 2019
1 parent ba3bd6f commit 84e39f3
Show file tree
Hide file tree
Showing 11 changed files with 847 additions and 540 deletions.
51 changes: 51 additions & 0 deletions test/lib/colorize.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen-string-literal: true

class Colorize
def initialize(color = nil, opts = ((_, color = color, nil)[0] if Hash === color))
@colors = @reset = nil
if color or (color == nil && STDOUT.tty?)
if (/\A\e\[.*m\z/ =~ IO.popen("tput smso", "r", :err => IO::NULL, &:read) rescue nil)
@beg = "\e["
colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:\n]*)/)] : {}
if opts and colors_file = opts[:colors_file]
begin
File.read(colors_file).scan(/(\w+)=([^:\n]*)/) do |n, c|
colors[n] ||= c
end
rescue Errno::ENOENT
end
end
@colors = colors
@reset = "#{@beg}m"
end
end
self
end

DEFAULTS = {
"pass"=>"32", "fail"=>"31;1", "skip"=>"33;1",
"black"=>"30", "red"=>"31", "green"=>"32", "yellow"=>"33",
"blue"=>"34", "magenta"=>"35", "cyan"=>"36", "white"=>"37",
"bold"=>"1", "underline"=>"4", "reverse"=>"7",
}

def decorate(str, name)
if @colors and color = (@colors[name] || DEFAULTS[name])
"#{@beg}#{color}m#{str}#{@reset}"
else
str
end
end

DEFAULTS.each_key do |name|
define_method(name) {|str|
decorate(str, name)
}
end
end

if $0 == __FILE__
colorize = Colorize.new
col = ARGV.shift
ARGV.each {|str| puts colorize.decorate(str, col)}
end
185 changes: 122 additions & 63 deletions test/lib/envutil.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: us-ascii -*-
# frozen_string_literal: false
# frozen_string_literal: true
require "open3"
require "timeout"
require_relative "find_executable"
Expand Down Expand Up @@ -42,20 +42,79 @@ def rubybin
DEFAULT_SIGNALS = Signal.list
DEFAULT_SIGNALS.delete("TERM") if /mswin|mingw/ =~ RUBY_PLATFORM

RUBYLIB = ENV["RUBYLIB"]

class << self
attr_accessor :subprocess_timeout_scale
attr_accessor :timeout_scale
attr_reader :original_internal_encoding, :original_external_encoding,
:original_verbose

def capture_global_values
@original_internal_encoding = Encoding.default_internal
@original_external_encoding = Encoding.default_external
@original_verbose = $VERBOSE
end
end

def apply_timeout_scale(t)
if scale = EnvUtil.timeout_scale
t * scale
else
t
end
end
module_function :apply_timeout_scale

def timeout(sec, klass = nil, message = nil, &blk)
return yield(sec) if sec == nil or sec.zero?
sec = apply_timeout_scale(sec)
Timeout.timeout(sec, klass, message, &blk)
end
module_function :timeout

def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1)
reprieve = apply_timeout_scale(reprieve) if reprieve

signals = Array(signal).select do |sig|
DEFAULT_SIGNALS[sig.to_s] or
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
end
signals |= [:ABRT, :KILL]
case pgroup
when 0, true
pgroup = -pid
when nil, false
pgroup = pid
end
while signal = signals.shift
begin
Process.kill signal, pgroup
rescue Errno::EINVAL
next
rescue Errno::ESRCH
break
end
if signals.empty? or !reprieve
Process.wait(pid)
else
begin
Timeout.timeout(reprieve) {Process.wait(pid)}
rescue Timeout::Error
end
end
end
$?
end
module_function :terminate

def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
encoding: nil, timeout: 10, reprieve: 1, timeout_error: Timeout::Error,
stdout_filter: nil, stderr_filter: nil,
signal: :TERM,
rubybin: EnvUtil.rubybin,
rubybin: EnvUtil.rubybin, precommand: nil,
**opt)
if scale = EnvUtil.subprocess_timeout_scale
timeout *= scale if timeout
reprieve *= scale if reprieve
end
timeout = apply_timeout_scale(timeout)

in_c, in_p = IO.pipe
out_p, out_c = IO.pipe if capture_stdout
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
Expand All @@ -72,8 +131,11 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
if Array === args and Hash === args.first
child_env.update(args.shift)
end
if RUBYLIB and lib = child_env["RUBYLIB"]
child_env["RUBYLIB"] = [lib, RUBYLIB].join(File::PATH_SEPARATOR)
end
args = [args] if args.kind_of?(String)
pid = spawn(child_env, rubybin, *args, **opt)
pid = spawn(child_env, *precommand, rubybin, *args, **opt)
in_c.close
out_c.close if capture_stdout
err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
Expand All @@ -87,35 +149,8 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
timeout_error = nil
else
signals = Array(signal).select do |sig|
DEFAULT_SIGNALS[sig.to_s] or
DEFAULT_SIGNALS[Signal.signame(sig)] rescue false
end
signals |= [:ABRT, :KILL]
case pgroup = opt[:pgroup]
when 0, true
pgroup = -pid
when nil, false
pgroup = pid
end
while signal = signals.shift
begin
Process.kill signal, pgroup
rescue Errno::EINVAL
next
rescue Errno::ESRCH
break
end
if signals.empty? or !reprieve
Process.wait(pid)
else
begin
Timeout.timeout(reprieve) {Process.wait(pid)}
rescue Timeout::Error
end
end
end
status = $?
status = terminate(pid, signal, opt[:pgroup], reprieve)
terminated = Time.now
end
stdout = th_stdout.value if capture_stdout
stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
Expand All @@ -126,8 +161,8 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr =
stderr = stderr_filter.call(stderr) if stderr_filter
if timeout_error
bt = caller_locations
msg = "execution of #{bt.shift.label} expired"
msg = Test::Unit::Assertions::FailDesc[status, msg, [stdout, stderr].join("\n")].()
msg = "execution of #{bt.shift.label} expired timeout (#{timeout} sec)"
msg = failure_description(status, terminated, msg, [stdout, stderr].join("\n"))
raise timeout_error, msg, bt.map(&:to_s)
end
return stdout, stderr, status
Expand All @@ -151,30 +186,33 @@ class << self
end

def verbose_warning
class << (stderr = "")
alias write <<
class << (stderr = "".dup)
alias write concat
def flush; end
end
stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
stderr, $stderr = $stderr, stderr
$VERBOSE = true
yield stderr
return $stderr
ensure
stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
stderr, $stderr = $stderr, stderr
$VERBOSE = EnvUtil.original_verbose
end
module_function :verbose_warning

def default_warning
verbose, $VERBOSE = $VERBOSE, false
$VERBOSE = false
yield
ensure
$VERBOSE = verbose
$VERBOSE = EnvUtil.original_verbose
end
module_function :default_warning

def suppress_warning
verbose, $VERBOSE = $VERBOSE, nil
$VERBOSE = nil
yield
ensure
$VERBOSE = verbose
$VERBOSE = EnvUtil.original_verbose
end
module_function :suppress_warning

Expand All @@ -187,26 +225,18 @@ def under_gc_stress(stress = true)
module_function :under_gc_stress

def with_default_external(enc)
verbose, $VERBOSE = $VERBOSE, nil
origenc, Encoding.default_external = Encoding.default_external, enc
$VERBOSE = verbose
suppress_warning { Encoding.default_external = enc }
yield
ensure
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = origenc
$VERBOSE = verbose
suppress_warning { Encoding.default_external = EnvUtil.original_external_encoding }
end
module_function :with_default_external

def with_default_internal(enc)
verbose, $VERBOSE = $VERBOSE, nil
origenc, Encoding.default_internal = Encoding.default_internal, enc
$VERBOSE = verbose
suppress_warning { Encoding.default_internal = enc }
yield
ensure
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_internal = origenc
$VERBOSE = verbose
suppress_warning { Encoding.default_internal = EnvUtil.original_internal_encoding }
end
module_function :with_default_internal

Expand Down Expand Up @@ -257,6 +287,37 @@ def self.diagnostic_reports(signame, pid, now)
end
end

def self.failure_description(status, now, message = "", out = "")
pid = status.pid
if signo = status.termsig
signame = Signal.signame(signo)
sigdesc = "signal #{signo}"
end
log = diagnostic_reports(signame, pid, now)
if signame
sigdesc = "SIG#{signame} (#{sigdesc})"
end
if status.coredump?
sigdesc = "#{sigdesc} (core dumped)"
end
full_message = ''.dup
message = message.call if Proc === message
if message and !message.empty?
full_message << message << "\n"
end
full_message << "pid #{pid}"
full_message << " exit #{status.exitstatus}" if status.exited?
full_message << " killed by #{sigdesc}" if sigdesc
if out and !out.empty?
full_message << "\n" << out.b.gsub(/^/, '| ')
full_message.sub!(/(?<!\n)\z/, "\n")
end
if log
full_message << "Diagnostic reports:\n" << log.b.gsub(/^/, '| ')
end
full_message
end

def self.gc_stress_to_class?
unless defined?(@gc_stress_to_class)
_, _, status = invoke_ruby(["-e""exit GC.respond_to?(:add_stress_to_class)"])
Expand All @@ -274,10 +335,8 @@ class << self
attr_reader :ruby
end
dir = File.dirname(ruby)
name = File.basename(ruby, CONFIG['EXEEXT'])
CONFIG['bindir'] = dir
CONFIG['ruby_install_name'] = name
CONFIG['RUBY_INSTALL_NAME'] = name
Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
end
end

EnvUtil.capture_global_values
2 changes: 1 addition & 1 deletion test/lib/find_executable.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# frozen_string_literal: false
# frozen_string_literal: true
require "rbconfig"

module EnvUtil
Expand Down
Loading

0 comments on commit 84e39f3

Please sign in to comment.