class Hydra::Master

Attributes

failed_files[R]
report_text[R]

A text report of the time it took to run each file

Public Class Methods

new(opts = { }) click to toggle source

Create a new Master

Options:

  • :files

    • An array of test files to be run. These should be relative paths from the root of the project, since they may be run on different machines which may have different paths.

  • :workers

    • An array of hashes. Each hash should be the configuration options for a worker.

  • :listeners

  • :verbose

    • Set to true to see lots of Hydra output (for debugging)

  • :autosort

    • Set to false to disable automatic sorting by historical run-time per file

# File lib/hydra/master.rb, line 36
def initialize(opts = { })
  opts.stringify_keys!
  config_file = opts.delete('config') { nil }
  if config_file

    begin
      config_erb = ERB.new(IO.read(config_file)).result(binding)
    rescue Exception => e
      raise(YmlLoadError,"config file was found, but could not be parsed with ERB.\n#{$!.inspect}")
    end

    begin
      config_yml = YAML::load(config_erb)
    rescue StandardError => e
      raise(YmlLoadError,"config file was found, but could not be parsed.\n#{$!.inspect}")
    end

    opts.merge!(config_yml.stringify_keys!)
  end
  @files = Array(opts.fetch('files') { nil })
  raise "No files, nothing to do" if @files.empty?
  @incomplete_files = @files.dup
  @failed_files = []
  @workers = []
  @listeners = []
  @event_listeners = Array(opts.fetch('listeners') { nil } )
  @event_listeners.select{|l| l.is_a? String}.each do |l|
    @event_listeners.delete_at(@event_listeners.index(l))
    listener = eval(l)
    @event_listeners << listener if listener.is_a?(Hydra::Listener::Abstract)
  end

  @string_runner_event_listeners = Array( opts.fetch( 'runner_listeners' ) { nil } )

  @runner_log_file = opts.fetch('runner_log_file') { nil }
  @verbose = opts.fetch('verbose') { false }
  @autosort = opts.fetch('autosort') { true }
  @sync = opts.fetch('sync') { nil }
  @environment = opts.fetch('environment') { 'test' }
  @options = opts.fetch('options') { '' }

  if @autosort
    sort_files_from_report
    @event_listeners << Hydra::Listener::ReportGenerator.new(File.new(heuristic_file, 'w'))
  end

  # default is one worker that is configured to use a pipe with one runner
  worker_cfg = opts.fetch('workers') { [ { 'type' => 'local', 'runners' => 1} ] }

  trace "Initialized"
  trace "  Files:   (#{@files.inspect})"
  trace "  Workers: (#{worker_cfg.inspect})"
  trace "  Verbose: (#{@verbose.inspect})"

  @event_listeners.each{|l| l.testing_begin(@files) }

  boot_workers worker_cfg
  process_messages
end

Public Instance Methods

process_results(worker, message) click to toggle source

Process the results coming back from the worker.

# File lib/hydra/master.rb, line 114
def process_results(worker, message)
  if message.output =~ %rActiveRecord::StatementInvalid(.*)[Dd]eadlock/ or
     message.output =~ %rPGError: ERROR(.*)[Dd]eadlock/ or
     message.output =~ %rMysql::Error: SAVEPOINT(.*)does not exist: ROLLBACK/ or
     message.output =~ %rMysql::Error: Deadlock found/
    trace "Deadlock detected running [#{message.file}]. Will retry at the end"
    @files.push(message.file)
    send_file(worker)
  else
    @incomplete_files.delete_at(@incomplete_files.index(message.file))
    trace "#{@incomplete_files.size} Files Remaining"
    @event_listeners.each{|l| l.file_end(message.file, message.output) }
    unless message.output == '.'
      @failed_files << message.file
    end
    if @incomplete_files.empty?
      @workers.each do |worker|
        @event_listeners.each{|l| l.worker_end(worker) }
      end

      shutdown_all_workers
    else
      send_file(worker)
    end
  end
end
send_file(worker) click to toggle source

Send a file down to a worker.

# File lib/hydra/master.rb, line 102
def send_file(worker)
  f = @files.shift
  if f
    trace "Sending #{f.inspect}"
    @event_listeners.each{|l| l.file_begin(f) }
    worker[:io].write(RunFile.new(:file => f))
  else
    trace "No more files to send"
  end
end
worker_begin(worker) click to toggle source

Message handling

# File lib/hydra/master.rb, line 97
def worker_begin(worker)
  @event_listeners.each {|l| l.worker_begin(worker) }
end