class Test::Unit::Runner
Public Class Methods
autorun()
click to toggle source
# File lib/test/unit.rb, line 363 def self.autorun at_exit { Test::Unit::RunCount.run_once { exit(Test::Unit::Runner.new.run(ARGV) || true) } unless @@stop_auto_run } unless @@installed_at_exit @@installed_at_exit = true end
Public Instance Methods
_prepare_run(suites, type)
click to toggle source
# File lib/test/unit.rb, line 676 def _prepare_run(suites, type) options[:job_status] ||= :replace if @tty && !@verbose case options[:color] when :always color = true when :auto, nil color = @options[:job_status] == :replace && /dumb/ !~ ENV["TERM"] else color = false end if color # dircolors-like style colors = (colors = ENV['TEST_COLORS']) ? Hash[colors.scan(/(\w+)=([^:]*)/)] : {} @passed_color = "\e[#{colors["pass"] || "32"}m" @failed_color = "\e[#{colors["fail"] || "31"}m" @skipped_color = "\e[#{colors["skip"] || "33"}m" @reset_color = "\e[m" else @passed_color = @failed_color = @skipped_color = @reset_color = "" end if color or @options[:job_status] == :replace @verbose = !options[:parallel] @output = StatusLineOutput.new(self) end if /\A\/(.*)\/\z/ =~ (filter = options[:filter]) filter = Regexp.new($1) end type = "#{type}_methods" total = if filter suites.inject(0) {|n, suite| n + suite.send(type).grep(filter).size} else suites.inject(0) {|n, suite| n + suite.send(type).size} end @test_count = 0 @total_tests = total.to_s(10) end
_print(s)
click to toggle source
# File lib/test/unit.rb, line 723 def _print(s); $stdout.print(s); end
_run_parallel(suites, type, result)
click to toggle source
# File lib/test/unit.rb, line 564 def _run_parallel suites, type, result if @options[:parallel] < 1 warn "Error: parameter of -j option should be greater than 0." return end # 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 = [] @total_tests = @tasks.size.to_s(10) rep = [] # FIXME: more good naming @workers = [] # Array of workers. @workers_hash = {} # out-IO => worker @ios = [] # Array of worker IOs begin # Thread: watchdog watchdog = start_watchdog @options[:parallel].times {launch_worker} while _io = IO.select(@ios)[0] break if _io.any? do |io| @need_quit or (deal(io, type, result, rep).nil? and !@workers.any? {|x| [:running, :prepare].include? x.status}) end end rescue Interrupt => ex @interrupt = ex return result ensure watchdog.kill if watchdog if @interrupt @ios.select!{|x| @workers_hash[x].status == :running } while !@ios.empty? && (__io = IO.select(@ios,[],[],10)) __io[0].reject! {|io| deal(io, type, result, rep, true)} end end quit_workers unless @interrupt || !@options[:retry] || @need_quit @options[:parallel] = false suites, rep = rep.partition {|r| r[:testcase] && r[:file] && r[:report].any? {|e| !e[2].is_a?(MiniTest::Skip)}} suites.map {|r| r[:file]}.uniq.each {|file| require file} suites.map! {|r| eval("::"+r[:testcase])} del_status_line or puts unless suites.empty? puts "Retrying..." _run_suites(suites, type) end end unless @options[:retry] del_status_line or puts end unless rep.empty? rep.each do |r| r[:report].each do |f| puke(*f) if f end end if @options[:retry] @errors += rep.map{|x| x[:result][0] }.inject(:+) @failures += rep.map{|x| x[:result][1] }.inject(:+) @skips += rep.map{|x| x[:result][2] }.inject(:+) end end unless @warnings.empty? warn "" @warnings.uniq! {|w| w[1].message} @warnings.each do |w| warn "#{w[0]}: #{w[1].message} (#{w[1].class})" end warn "" end end end
_run_suites(suites, type)
click to toggle source
# File lib/test/unit.rb, line 647 def _run_suites suites, type _prepare_run(suites, type) @interrupt = nil result = [] GC.start 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] report.sort_by!{|r| r.start_with?("Skipped:") ? 0 : (r.start_with?("Failure:") ? 1 : 2) } result end
add_status(line)
click to toggle source
# File lib/test/unit.rb, line 425 def add_status(line) unless @options[:job_status] == :replace print(line) return end @status_line_size ||= 0 line = line[0...(terminal_width-@status_line_size)] print line $stdout.flush @status_line_size += line.size end
after_worker_down(worker, e=nil, c=false)
click to toggle source
# File lib/test/unit.rb, line 372 def after_worker_down(worker, e=nil, c=false) return unless @options[:parallel] return if @interrupt warn e if e @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
after_worker_quit(worker)
click to toggle source
# File lib/test/unit.rb, line 449 def after_worker_quit(worker) return unless @options[:parallel] return if @interrupt @workers.delete(worker) @dead_workers << worker @ios = @workers.map(&:io) end
deal(io, type, result, rep, shutting_down = false)
click to toggle source
# File lib/test/unit.rb, line 521 def deal(io, type, result, rep, shutting_down = false) worker = @workers_hash[io] case worker.read when /^okay$/ worker.status = :running jobs_status when /^ready(!)?$/ bang = $1 worker.status = :ready return nil unless task = @tasks.shift if @options[:separate] and not bang worker.quit worker = add_worker end worker.run(task, type) @test_count += 1 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! return true 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$/, nil if shutting_down || worker.quit_called after_worker_quit worker else after_worker_down worker end end return false end
del_jobs_status()
click to toggle source
# File lib/test/unit.rb, line 444 def del_jobs_status return unless @options[:job_status] == :replace && @status_line_size.nonzero? del_status_line end
del_status_line()
click to toggle source
# File lib/test/unit.rb, line 400 def del_status_line @status_line_size ||= 0 unless @options[:job_status] == :replace $stdout.puts return end print "\r"+" "*@status_line_size+"\r" $stdout.flush @status_line_size = 0 end
delete_worker(worker)
click to toggle source
# File lib/test/unit.rb, line 473 def delete_worker(worker) @workers_hash.delete worker.io @workers.delete worker @ios.delete worker.io end
failed(s)
click to toggle source
# File lib/test/unit.rb, line 726 def failed(s) sep = "\n" @report_count ||= 0 report.each do |msg| if msg.start_with? "Skipped:" if @options[:hide_skip] del_status_line next end color = @skipped_color else color = @failed_color end msg = msg.split(/$/, 2) $stdout.printf("%s%s%3d) %s%s%s\n", sep, color, @report_count += 1, msg[0], @reset_color, msg[1]) sep = nil end report.clear end
jobs_status()
click to toggle source
# File lib/test/unit.rb, line 437 def jobs_status return unless @options[:job_status] puts "" unless @options[:verbose] or @options[:job_status] == :replace status_line = @workers.map(&:to_s).join(" ") update_status(status_line) or (puts; nil) end
launch_worker()
click to toggle source
# File lib/test/unit.rb, line 457 def launch_worker begin worker = Worker.launch(@options[:ruby],@args) rescue => e abort "ERROR: Failed to launch job process - #{e.class}: #{e.message}" end worker.hook(:dead) do |w,info| after_worker_quit w after_worker_down w, *info if !info.empty? && !worker.quit_called end @workers << worker @ios << worker.io @workers_hash[worker.io] = worker worker end
new_test(s)
click to toggle source
# File lib/test/unit.rb, line 713 def new_test(s) @test_count += 1 update_status(s) end
output()
click to toggle source
Calls superclass method
# File lib/test/unit.rb, line 672 def output (@output ||= nil) || super end
puke(klass, meth, e)
click to toggle source
Overriding of MiniTest::Unit#puke
Calls superclass method
# File lib/test/unit.rb, line 749 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. n = report.size rep = super if MiniTest::Skip === e and /no message given\z/ =~ e.message report.slice!(n..-1) rep = "." end rep end
put_status(line)
click to toggle source
# File lib/test/unit.rb, line 411 def put_status(line) unless @options[:job_status] == :replace print(line) return end @status_line_size ||= 0 del_status_line $stdout.flush line = line[0...terminal_width] print line $stdout.flush @status_line_size = line.size end
quit_workers()
click to toggle source
# File lib/test/unit.rb, line 479 def quit_workers return if @workers.empty? @workers.reject! do |worker| begin timeout(1) do worker.quit end rescue Errno::EPIPE rescue Timeout::Error end worker.close end return if @workers.empty? begin timeout(0.2 * @workers.size) do Process.waitall end rescue Timeout::Error @workers.each do |worker| worker.kill end @worker.clear end end
run(*args)
click to toggle source
Calls superclass method
Test::Unit::RunCount#run
# File lib/test/unit.rb, line 773 def run(*args) result = super puts "\nruby -v: #{RUBY_DESCRIPTION}" result end
start_watchdog()
click to toggle source
# File lib/test/unit.rb, line 505 def start_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 } next unless w w = w.dup if w.status != :quit && !w.quit_called? # Worker down w.died(nil, !stat.signaled? && stat.exitstatus) end end end end
status(*args)
click to toggle source
Calls superclass method
# File lib/test/unit.rb, line 767 def status(*args) result = super raise @interrupt if @interrupt result end
succeed()
click to toggle source
# File lib/test/unit.rb, line 724 def succeed; del_status_line; end
terminal_width()
click to toggle source
# File lib/test/unit.rb, line 386 def terminal_width unless @terminal_width ||= nil begin require 'io/console' width = $stdout.winsize[1] rescue LoadError, NoMethodError, Errno::ENOTTY, Errno::EBADF, Errno::EINVAL width = ENV["COLUMNS"].to_i.nonzero? || 80 end width -= 1 if /mswin|mingw/ =~ RUBY_PLATFORM @terminal_width = width end @terminal_width end
update_status(s)
click to toggle source
# File lib/test/unit.rb, line 718 def update_status(s) count = @test_count.to_s(10).rjust(@total_tests.size) put_status("#{@passed_color}[#{count}/#{@total_tests}]#{@reset_color} #{s}") end