lib/gorgon/job_state.rb
require 'gorgon/host_state'
require 'observer'
module Gorgon
class JobState
include Observable
attr_reader :total_files, :remaining_files_count, :state, :crashed_hosts
def initialize total_files
@total_files = total_files
@remaining_files_count = total_files
@failed_tests = []
@crashed_hosts = []
@hosts = {}
if @remaining_files_count > 0
@state = :starting
else
@state = :complete
end
end
def failed_files_count
@failed_tests.count
end
def finished_files_count
total_files - remaining_files_count
end
def file_started payload
raise_if_completed
if @state == :starting
@state = :running
end
file_started_update_host_state payload
changed
notify_observers payload
end
def file_finished payload
raise_if_completed
@remaining_files_count -= 1
@state = :complete if @remaining_files_count == 0
handle_failed_test payload if failed_test?(payload)
@hosts[payload[:hostname]].file_finished payload[:worker_id], payload[:filename]
changed
notify_observers payload
end
def gorgon_crash_message payload
@crashed_hosts << payload[:hostname]
changed
notify_observers payload
end
def cancel
@remaining_files_count = 0
@state = :cancelled
changed
notify_observers({})
end
def each_failed_test
@failed_tests.each do |test|
yield test
end
end
def each_running_file
@hosts.each do |hostname, host|
host.each_running_file do |filename|
yield hostname, filename
end
end
end
def total_running_hosts
@hosts.size
end
def total_running_workers
result = 0
@hosts.each do |hostname, host|
result += host.total_running_workers
end
result
end
def is_job_complete?
@state == :complete
end
def is_job_cancelled?
@state == :cancelled
end
private
def file_started_update_host_state payload
hostname = payload[:hostname]
@hosts[hostname] = HostState.new if @hosts[hostname].nil?
@hosts[hostname].file_started payload[:worker_id], payload[:filename]
end
def handle_failed_test payload
@failed_tests << payload
end
def raise_if_completed
# TODO: Following should raise a specific error instead of a generic RuntimeError
raise "JobState#file_finished called when job was already complete" if is_job_complete?
puts "NOTICE: JobState#file_finished called after job was cancelled" if is_job_cancelled?
end
def failed_test? payload
payload[:type] == "fail" || payload[:type] == "crash"
end
end
end