Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
MiniTest::Unit
# File test/unit.rb, line 386 def _run_parallel suites, type, result if @options[:parallel] < 1 warn "Error: parameter of -j option should be greater than 0." return end begin # Require needed things for parallel running require 'thread' require 'timeout' @tasks = @files.dup # Array of filenames. @need_quit = false @dead_workers = [] # Array of dead workers. @warnings = [] shutting_down = false rep = [] # FIXME: more good naming # Array of workers. @workers = @options[:parallel].times.map { worker = Worker.launch(@options[:ruby],@args) worker.hook(:dead) do |w,info| after_worker_quit w after_worker_down w, *info unless info.empty? end worker } # Thread: watchdog watchdog = Thread.new do while stat = Process.wait2 break if @interrupt # Break when interrupt pid, stat = stat w = (@workers + @dead_workers).find{|x| pid == x.pid }.dup next unless w unless w.status == :quit # Worker down w.died(nil, !stat.signaled? && stat.exitstatus) end end end @workers_hash = Hash[@workers.map {|w| [w.io,w] }] # out-IO => worker @ios = @workers.map{|w| w.io } # Array of worker IOs while _io = IO.select(@ios)[0] break unless _io.each do |io| break if @need_quit worker = @workers_hash[io] case worker.read when /^okay$/ worker.status = :running jobs_status when /^ready$/ worker.status = :ready if @tasks.empty? break unless @workers.find{|x| x.status == :running } else worker.run(@tasks.shift, type) end jobs_status when /^done (.+?)$/ r = Marshal.load($1.unpack("m")[0]) result << r[0..1] unless r[0..1] == [nil,nil] rep << {file: worker.real_file, report: r[2], result: r[3], testcase: r[5]} $:.push(*r[4]).uniq! when /^p (.+?)$/ del_jobs_status print $1.unpack("m")[0] jobs_status if @options[:job_status] == :replace when /^after (.+?)$/ @warnings << Marshal.load($1.unpack("m")[0]) when /^bye (.+?)$/ after_worker_down worker, Marshal.load($1.unpack("m")[0]) when /^bye$/ if shutting_down after_worker_quit worker else after_worker_down worker end end break if @need_quit end end rescue Interrupt => e @interrupt = e return result ensure shutting_down = true watchdog.kill if watchdog if @interrupt @ios.select!{|x| @workers_hash[x].status == :running } while !@ios.empty? && (__io = IO.select(@ios,[],[],10)) _io = __io[0] _io.each do |io| worker = @workers_hash[io] case worker.read when /^done (.+?)$/ r = Marshal.load($1.unpack("m")[0]) result << r[0..1] unless r[0..1] == [nil,nil] rep << {file: worker.real_file, report: r[2], result: r[3], testcase: r[5]} $:.push(*r[4]).uniq! @ios.delete(io) end end end end @workers.each do |worker| begin timeout(1) do worker.puts "quit" end rescue Errno::EPIPE rescue Timeout::Error end worker.close end begin timeout(0.2*@workers.size) do Process.waitall end rescue Timeout::Error @workers.each do |worker| begin Process.kill(:KILL,worker.pid) rescue Errno::ESRCH; end end end if @interrupt || @options[:no_retry] || @need_quit rep.each do |r| report.push(*r[:report]) end @errors += rep.map{|x| x[:result][0] }.inject(:+) @failures += rep.map{|x| x[:result][1] }.inject(:+) @skips += rep.map{|x| x[:result][2] }.inject(:+) else puts "" puts "Retrying..." puts "" rep.each do |r| if r[:testcase] && r[:file] && !r[:report].empty? require r[:file] _run_suite(eval(r[:testcase]),type) else report.push(*r[:report]) @errors += r[:result][0] @failures += r[:result][1] @skips += r[:result][2] end end end if @warnings warn "" ary = [] @warnings.reject! do |w| r = ary.include?(w[1].message) ary << w[1].message r end @warnings.each do |w| warn "#{w[0]}: #{w[1].message} (#{w[1].class})" end warn "" end end end
# File test/unit.rb, line 557 def _run_suites suites, type @interrupt = nil result = [] if @options[:parallel] _run_parallel suites, type, result else suites.each {|suite| begin result << _run_suite(suite, type) rescue Interrupt => e @interrupt = e break end } end report.reject!{|r| r.start_with? "Skipped:" } if @options[:hide_skip] result end
# File test/unit.rb, line 332 def after_worker_down(worker, e=nil, c=false) return unless @options[:parallel] return if @interrupt if e b = e.backtrace warn "#{b.shift}: #{e.message} (#{e.class})" STDERR.print b.map{|s| "\tfrom #{s}"}.join("\n") end @need_quit = true warn "" warn "Some worker was crashed. It seems ruby interpreter's bug" warn "or, a bug of test/unit/parallel.rb. try again without -j" warn "option." warn "" STDERR.flush exit c end
# File test/unit.rb, line 378 def after_worker_quit(worker) return unless @options[:parallel] return if @interrupt @workers.delete(worker) @dead_workers << worker @ios = @workers.map(&:io) end
# File test/unit.rb, line 373 def del_jobs_status return unless @options[:job_status] == :replace && @jstr_size.nonzero? print "\r"+" "*@jstr_size+"\r" end
# File test/unit.rb, line 350 def jobs_status return unless @options[:job_status] puts "" unless @options[:verbose] status_line = @workers.map(&:to_s).join(" ") if @options[:job_status] == :replace and $stdout.tty? @terminal_width ||= begin require 'io/console' $stdout.winsize[1] rescue LoadError, NoMethodError ENV["COLUMNS"].to_i.nonzero? || 80 end @jstr_size ||= 0 del_jobs_status $stdout.flush print status_line[0...@terminal_width] $stdout.flush @jstr_size = [status_line.size, @terminal_width].min else puts status_line end end
Overriding of MiniTest::Unit#puke
# File test/unit.rb, line 577 def puke klass, meth, e # TODO: # this overriding is for minitest feature that skip messages are # hidden when not verbose (-v), note this is temporally. e = case e when MiniTest::Skip then @skips += 1 "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n" when MiniTest::Assertion then @failures += 1 "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n" else @errors += 1 bt = MiniTest::filter_backtrace(e.backtrace).join "\n " "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n" end @report << e e[0, 1] end
Commenting is here to help enhance the documentation. For example, code samples, or clarification of the documentation.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file bug report so that it can be corrected for the next release. Thank you.
If you want to help improve the Ruby documentation, please visit Documenting-ruby.org.