class FuzzBert::Executor

Constants

DEFAULT_ARGS
DEFAULT_HANDLER
DEFAULT_LIMIT
DEFAULT_POOL_SIZE
DEFAULT_SLEEP_DELAY

Attributes

handler[R]
limit[R]
pool_size[R]
sleep_delay[R]

Public Class Methods

new(suites, args = DEFAULT_ARGS) click to toggle source
# File lib/fuzzbert/executor.rb, line 17
def initialize(suites, args = DEFAULT_ARGS)
  raise ArgumentError.new("No test cases were passed") unless suites

  args ||= DEFAULT_ARGS
  @pool_size = args[:pool_size] || DEFAULT_POOL_SIZE
  @limit = args[:limit] || DEFAULT_LIMIT
  @handler = args[:handler] || DEFAULT_HANDLER.new
  @sleep_delay = args[:sleep_delay] || DEFAULT_SLEEP_DELAY
  @data_cache = {}
  @n = 0
  @exiting = false
  @producer = DataProducer.new(suites)
end

Public Instance Methods

run() click to toggle source
# File lib/fuzzbert/executor.rb, line 31
def run
  trap_child_exit
  trap_interrupt

  @pool_size.times { run_instance(*@producer.next) }
  @running = true
  @limit == -1 ? sleep : conditional_sleep
end

Private Instance Methods

conditional_sleep() click to toggle source
# File lib/fuzzbert/executor.rb, line 125
def conditional_sleep
  sleep @sleep_delay until !@running
end
graceful_exit() click to toggle source
# File lib/fuzzbert/executor.rb, line 107
def graceful_exit
  puts "\nExiting...Interrupt again to exit immediately"
  begin
    while Process.wait; end
  rescue Errno::ECHILD
  end
  exit 0
end
handle(error_data) click to toggle source
# File lib/fuzzbert/executor.rb, line 116
def handle(error_data)
  @handler.handle(error_data)
end
interrupted(status) click to toggle source
# File lib/fuzzbert/executor.rb, line 120
def interrupted(status)
  return false if status.exited?
  status.termsig == nil || status.termsig == 2
end
limit_reached?() click to toggle source
# File lib/fuzzbert/executor.rb, line 95
def limit_reached?
  @limit == -1 || @n < @limit
end
run_instance(description, test, generator) click to toggle source
# File lib/fuzzbert/executor.rb, line 42
def run_instance(description, test, generator)
  data = generator.to_data
  pid = fork do
    begin
      test.run(data)
    rescue StandardError
      abort
    end
  end
  id = "#{description}/#{generator.description}"
  @data_cache[pid] = [id, data]
end
start_new_child() click to toggle source
# File lib/fuzzbert/executor.rb, line 86
def start_new_child
  @n += 1
  if limit_reached?
    run_instance(*@producer.next) 
  else
    @running = false
  end
end
status_failed?(status) click to toggle source
# File lib/fuzzbert/executor.rb, line 82
def status_failed?(status)
  !status.success? && !interrupted(status)
end
trap_child_exit() click to toggle source
# File lib/fuzzbert/executor.rb, line 55
def trap_child_exit
  trap(:CHLD) do 
    while_child_exits do |exitval|
      pid = exitval[0]
      status = exitval[1]
      data_ary = @data_cache.delete(pid)

      handle({ 
        id: data_ary[0], 
        data: data_ary[1], 
        pid: pid, 
        status: status
      }) if status_failed?(status)

      start_new_child
    end
  end
end
trap_interrupt() click to toggle source
# File lib/fuzzbert/executor.rb, line 99
def trap_interrupt
  trap(:INT) do
    exit! (1) if @exiting
    @exiting = true
    graceful_exit
  end
end
while_child_exits() { |exitval| ... } click to toggle source
# File lib/fuzzbert/executor.rb, line 74
def while_child_exits
  while exitval = Process.wait2(-1, Process::WNOHANG)
    yield exitval
  end
rescue Errno::ECHILD
  # fine
end