1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
require 'rbconfig'
require 'timeout'
require 'fileutils'
require_relative 'lib/colorize'
require_relative 'lib/gem_env'
ENV.delete("GNUMAKEFLAGS")
github_actions = ENV["GITHUB_ACTIONS"] == "true"
DEFAULT_ALLOWED_FAILURES = RUBY_PLATFORM =~ /mswin|mingw/ ? [
'rbs',
'debug',
'irb',
'power_assert',
'net-imap',
] : []
allowed_failures = ENV['TEST_BUNDLED_GEMS_ALLOW_FAILURES'] || ''
allowed_failures = allowed_failures.split(',').concat(DEFAULT_ALLOWED_FAILURES).uniq.reject(&:empty?)
# make test-bundled-gems BUNDLED_GEMS=gem1,gem2,gem3
bundled_gems = ARGV.first || ''
colorize = Colorize.new
rake = File.realpath("../../.bundle/bin/rake", __FILE__)
gem_dir = File.realpath('../../gems', __FILE__)
rubylib = [gem_dir+'/lib', ENV["RUBYLIB"]].compact.join(File::PATH_SEPARATOR)
exit_code = 0
ruby = ENV['RUBY'] || RbConfig.ruby
failed = []
File.foreach("#{gem_dir}/bundled_gems") do |line|
next unless gem = line[/^[^\s\#]+/]
next unless bundled_gems.empty? || bundled_gems.split(",").include?(gem)
next unless File.directory?("#{gem_dir}/src/#{gem}/test")
test_command = "#{ruby} -C #{gem_dir}/src/#{gem} #{rake} test"
first_timeout = 600 # 10min
toplib = gem
unless File.exist?("#{gem_dir}/src/#{gem}/lib/#{toplib}.rb")
toplib = gem.tr("-", "/")
next unless File.exist?("#{gem_dir}/src/#{gem}/lib/#{toplib}.rb")
end
case gem
when "rbs"
# TODO: We should skip test file instead of test class/methods
skip_test_files = %w[
]
skip_test_files.each do |file|
path = "#{gem_dir}/src/#{gem}/#{file}"
File.unlink(path) if File.exist?(path)
end
rbs_skip_tests = [
File.join(__dir__, "/rbs_skip_tests")
]
if /mswin|mingw/ =~ RUBY_PLATFORM
rbs_skip_tests << File.join(__dir__, "/rbs_skip_tests_windows")
end
test_command << " stdlib_test validate RBS_SKIP_TESTS=#{rbs_skip_tests.join(File::PATH_SEPARATOR)} SKIP_RBS_VALIDATION=true"
first_timeout *= 3
when "debug"
# Since debug gem requires debug.so in child processes without
# activating the gem, we preset necessary paths in RUBYLIB
# environment variable.
load_path = true
when "test-unit"
test_command = "#{ruby} -C #{gem_dir}/src/#{gem} test/run.rb"
when "win32ole"
next unless /mswin|mingw/ =~ RUBY_PLATFORM
end
if load_path
libs = IO.popen([ruby, "-e", "old = $:.dup; require '#{toplib}'; puts $:-old"], &:read)
next unless $?.success?
ENV["RUBYLIB"] = [libs.split("\n"), rubylib].join(File::PATH_SEPARATOR)
else
ENV["RUBYLIB"] = rubylib
end
# 93(bright yellow) is copied from .github/workflows/mingw.yml
puts "#{github_actions ? "::group::\e\[93m" : "\n"}Testing the #{gem} gem#{github_actions ? "\e\[m" : ""}"
print "[command]" if github_actions
puts test_command
timeouts = {nil => first_timeout, INT: 30, TERM: 10, KILL: nil}
if /mingw|mswin/ =~ RUBY_PLATFORM
timeouts.delete(:TERM) # Inner process signal on Windows
timeouts.delete(:INT) # root process will be terminated too
group = :new_pgroup
pg = ""
else
group = :pgroup
pg = "-"
end
pid = Process.spawn(test_command, group => true)
timeouts.each do |sig, sec|
if sig
puts "Sending #{sig} signal"
Process.kill("#{pg}#{sig}", pid)
end
begin
break Timeout.timeout(sec) {Process.wait(pid)}
rescue Timeout::Error
end
rescue Interrupt
exit_code = Signal.list["INT"]
Process.kill("#{pg}KILL", pid)
Process.wait(pid)
break
end
print "::endgroup::\n" if github_actions
unless $?.success?
mesg = "Tests failed " +
($?.signaled? ? "by SIG#{Signal.signame($?.termsig)}" :
"with exit code #{$?.exitstatus}")
puts colorize.decorate(mesg, "fail")
if allowed_failures.include?(gem)
mesg = "Ignoring test failures for #{gem} due to \$TEST_BUNDLED_GEMS_ALLOW_FAILURES or DEFAULT_ALLOWED_FAILURES"
puts colorize.decorate(mesg, "skip")
else
failed << gem
exit_code = $?.exitstatus if $?.exitstatus
end
end
end
puts "Failed gems: #{failed.join(', ')}" unless failed.empty?
exit exit_code
|