nulogy/Gorgon

View on GitHub
lib/gorgon/job_state.rb

Summary

Maintainability
A
0 mins
Test Coverage
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