class Actir::ParallelTests::Test::Runner

Constants

NAME

Public Class Methods

execute_command(cmd, process_number, num_processes, options) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 83
def execute_command(cmd, process_number, num_processes, options)
  env = (options[:env] || {}).merge(
    #"TEST_ENV_NUMBER" => test_env_number(process_number),
    "env" => $env,
    "TEST_ENV_NUMBER" => process_number,
    "PARALLEL_TEST_GROUPS" => num_processes
  )
  cmd = "nice #{cmd}" if options[:nice]
  cmd = "#{cmd} 2>&1" if options[:combine_stderr]
  puts cmd if options[:verbose]

  execute_command_and_capture_output(env, cmd, options[:serialize_stdout])
end
execute_command_and_capture_output(env, cmd, silence) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 97
def execute_command_and_capture_output(env, cmd, silence)
  # make processes descriptive / visible in ps -ef
  separator = ';'
  exports = env.map do |k,v|
    "export #{k}=#{v}"
  end.join(separator)
  cmd = "#{exports}#{separator}#{cmd}"
  output = open("|#{cmd}", "r") { |output| capture_output(output, silence) }
  #modify by Hub
  #exitstatus = $?.exitstatus
  #"$?.exitstatus" 返回的值有时有问题,不能明确标示用例执行结果是否成功
  #改成判断结果数据中是否有failure和error
  exitstatus = get_test_failed_num(find_results(output).join)
  {:stdout => output, :exit_status => exitstatus}
end
find_results(test_output) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 113
def find_results(test_output)
  test_output.split("\n").map {|line|
    line.gsub!(/\e\[\d+m/,'')
    next unless line_is_result?(line)
    line
  }.compact
end
line_is_result?(line) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 58
def line_is_result?(line)
  line.gsub!(/[.F*]/,'')
  line =~ /\d+ failure/
end
name() click to toggle source

— usually overwritten by other runners

# File lib/actir/parallel_tests/test/runner.rb, line 10
def name
  NAME
end
run_tests(test_files, process_number, num_processes, options, address) click to toggle source

modify by Hub add param address to ruby script as ARGV modify cmd to exec ruby test script

# File lib/actir/parallel_tests/test/runner.rb, line 28
def run_tests(test_files, process_number, num_processes, options, address)
  #require_list = test_files.map { |file| file.sub(" ", "\\ ") }.join(" ")
  #cmd = "#{executable} -Itest -e '%w[#{require_list}].each { |f| require %{./\#{f}}}' #{address}"
  #execute_command(cmd, process_number, num_processes, options)

  cmd = ""
  #如果有-n选项,则只运行指定的测试用例
  if options[:testcase]
    raise "more than one file was choosen" if test_files.size != 1 
    cmd = "#{executable} #{test_files[0]} -n #{options[:testcase]} #{address}"
  else
    test_files.each do |file|
      cmd += "#{executable} #{file} #{address};"
    end 
    cmd += "\n"
  end

  result = execute_command(cmd, process_number, num_processes, options)
  #记录log
  if options[:log]
    log_str = "[run_tests]: \n" + result[:stdout]
    Actir::ParallelTests::Test::Logger.log(log_str, process_number)
  end

  #从result中获取执行结果用于生成测试报告
  Actir::ParallelTests::Test::Result.get_testsuite_detail(result)

  result
end
summarize_results(results) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 125
def summarize_results(results)
  sums = sum_up_results(results)
  sums.to_a.map{|word, number|  "#{number} #{word}#{'s' if number != 1}" }.join(', ')
  #sums.sort.map{|word, number|  "#{number} #{word}#{'s' if number != 1}" }.join(', ')
end
test_env_number(process_number) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 121
def test_env_number(process_number)
  process_number == 0 ? '' : process_number + 1
end
test_file_name() click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 21
def test_file_name
  "test"
end
test_suffix() click to toggle source

modify by Hub 修改正则表达式使得使用我们目前的测试脚本文件命名 : test_xxx.rb

# File lib/actir/parallel_tests/test/runner.rb, line 16
def test_suffix
 # /_(test|spec).rb$/
 /test.*\.rb$/
end
tests_in_groups(tests, num_groups, options={}) click to toggle source

finds all tests and partitions them into groups

# File lib/actir/parallel_tests/test/runner.rb, line 66
def tests_in_groups(tests, num_groups, options={})
  tests = find_tests(tests, options)

  case options[:group_by]
  when :found
    tests.map! { |t| [t, 1] }
  when :filesize
    sort_by_filesize(tests)
  when nil
    sort_by_filesize(tests)
  else
    raise ArgumentError, "Unsupported option #{options[:group_by]}"
  end

  Grouper.in_even_groups_by_size(tests, num_groups, options)
end

Protected Class Methods

capture_output(out, silence) click to toggle source

read output of the process and print it in chunks

# File lib/actir/parallel_tests/test/runner.rb, line 172
def capture_output(out, silence)
  result = ""
  loop do
    begin
      read = out.readpartial(1000000) # read whatever chunk we can get
      if Encoding.default_internal
        read = read.force_encoding(Encoding.default_internal)
      end
      result << read
      unless silence
        $stdout.print read
        $stdout.flush
      end
    end
  end rescue EOFError
  result
end
determine_executable() click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 137
def determine_executable
  if Actir::Remote.is_local?
    "ruby"
  else
    #TO-DO jenkins服务器上的ruby是用rvm管理的,这里有个坑,在jenkins中调用ruby命令会报找不到
    #后续考虑更换rvm至rbenv
    #jenkins服务器上的ruby所在地址
    "/usr/local/rvm/rubies/ruby-2.0.0-p598/bin/ruby"
  end
end
executable() click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 133
def executable
  ENV['PARALLEL_TESTS_EXECUTABLE'] || determine_executable
end
files_in_folder(folder, options={}) click to toggle source

modify by Hub Bug Fix lack of method 'glob'

# File lib/actir/parallel_tests/test/runner.rb, line 224
def files_in_folder(folder, options={})
  pattern = "**{,/*/**}/*"
  # modify by Hub
  # add method glod : Dir.glob
  #Dir[File.join(folder, pattern)].uniq
  Dir.glob(File.join(folder, pattern)).uniq
end
find_tests(tests, options = {}) click to toggle source

modify by Hub 由原来的包含路径的文件名直接进行正则匹配改为取出文件的文件名进行匹配,更准确,不受文件夹命名的影响

# File lib/actir/parallel_tests/test/runner.rb, line 197
def find_tests(tests, options = {})
  (tests || []).map do |file_or_folder|
    if File.directory?(file_or_folder)
      #取出文件和文件夹名字
      files_and_folder = files_in_folder(file_or_folder, options)
      #去掉文件夹名字
      files = files_and_folder.grep(test_suffix)
      #去掉不以test开头的测试脚本
      files_2_delete = Array.new
      files.each do |file|
        file_name = File.basename(file)
        #不能在遍历数组时进行delete操作
        #记录要删除的元素名称
        files_2_delete << file unless file_name =~ /^test.*\.rb$/
        #files.delete(file) unless file_name =~ /^test.*\.rb$/
      end
      files_2_delete.each { |file_2_delete| files.delete(file_2_delete) }
      files
    else
      file_or_folder
    end
  end.flatten.uniq
end
get_test_failed_num(result) click to toggle source

通过结果判断是否有用例失败 返回失败用例的数目

# File lib/actir/parallel_tests/test/runner.rb, line 152
def get_test_failed_num(result)
  #获取结果字符串中的failure和error用例数
  failed_num = 0
  result.scan(/(\d+)\s(failure|error)/).each do |failed|
    failed_num += failed[0].to_i
  end
  failed_num
end
sort_by_filesize(tests) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 190
def sort_by_filesize(tests)
  tests.sort!
  tests.map! { |test| [test, File.stat(test).size] }
end
sum_up_results(results) click to toggle source
# File lib/actir/parallel_tests/test/runner.rb, line 161
def sum_up_results(results)
  results = results.join(' ').gsub(/s\b/,'') # combine and singularize results
  #results = results.join(' ')
  counts = results.scan(/(\d+) (\w+)/)
  counts.inject(Hash.new(0)) do |sum, (number, word)|
    sum[word] += number.to_i
    sum
  end
end