In Files

  • test/unit.rb

Test::Unit::Runner

Public Class Methods

autorun() click to toggle source
 
               # File test/unit.rb, line 323
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

_run_parallel(suites, type, result) click to toggle source
 
               # 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
            
_run_suites(suites, type) click to toggle source
 
               # 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
            
after_worker_down(worker, e=nil, c=false) click to toggle source
 
               # 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
            
after_worker_quit(worker) click to toggle source
 
               # 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
            
del_jobs_status() click to toggle source
 
               # 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
            
jobs_status() click to toggle source
 
               # 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
            
puke(klass, meth, e) click to toggle source

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
            
status(*args) click to toggle source
 
               # File test/unit.rb, line 597
def status(*args)
  result = super
  raise @interrupt if @interrupt
  result
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.

blog comments powered by Disqus