class Coverband::Adapters::WebServiceStore

WebServiceStore: store a checkpoint of coverage to a remote service

Attributes

coverband_url[R]
hostname[R]
pid[R]
process_type[R]
runtime_env[R]

Public Class Methods

new(coverband_url, opts = {}) click to toggle source
Calls superclass method Coverband::Adapters::Base::new
# File lib/coverband/adapters/web_service_store.rb, line 11
def initialize(coverband_url, opts = {})
  super()
  require "socket"
  require "securerandom"
  @coverband_url = coverband_url
  @process_type = opts.fetch(:process_type) { $PROGRAM_NAME&.split("/")&.last || Coverband.configuration.process_type }
  @hostname = opts.fetch(:hostname) { ENV["DYNO"] || Socket.gethostname.force_encoding("utf-8").encode }
  @hostname = @hostname.delete("'", "").delete("’", "")
  @runtime_env = opts.fetch(:runtime_env) { Coverband.configuration.coverband_env }
  @failed_coverage_reports = []
end

Public Instance Methods

clear!() click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 27
def clear!
  # done via service UI
  raise "not supported via service"
end
clear_file!(filename) click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 32
def clear_file!(filename)
  # done via service UI
  raise "not supported via service"
end
coverage(local_type = nil, opts = {}) click to toggle source

Fetch coverband coverage via the API This would allow one to expore from the service and move back to the open source without having to reset coverage

# File lib/coverband/adapters/web_service_store.rb, line 48
def coverage(local_type = nil, opts = {})
  return if Coverband.configuration.service_disabled_dev_test_env?

  local_type ||= opts.key?(:override_type) ? opts[:override_type] : type
  env_filter = opts.key?(:env_filter) ? opts[:env_filter] : "production"
  uri = URI("#{coverband_url}/api/coverage?type=#{local_type}&env_filter=#{env_filter}")
  req = Net::HTTP::Get.new(uri, "Content-Type" => "application/json", "Coverband-Token" => Coverband.configuration.api_key)
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
    http.request(req)
  end
  JSON.parse(res.body)
rescue => e
  logger&.error "Coverband: Error while retrieving coverage #{e}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
end
logger() click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 23
def logger
  Coverband.configuration.logger
end
raw_store() click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 92
def raw_store
  raise "not supported via service"
end
save_report(report) click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 63
def save_report(report)
  return if report.empty?

  # We set here vs initialize to avoid setting on the primary process vs child processes
  @pid ||= ::Process.pid

  # TODO: do we need dup
  # TODO: we don't need upstream timestamps, server will track first_seen
  Thread.new do
    data = expand_report(report.dup)
    full_package = {
      collection_type: "coverage_delta",
      collection_data: {
        tags: {
          process_type: process_type,
          app_loading: type == Coverband::EAGER_TYPE,
          runtime_env: runtime_env,
          pid: pid,
          hostname: hostname
        },
        file_coverage: data
      }
    }

    save_coverage(full_package)
    retry_failed_reports
  end&.join
end
size() click to toggle source

NOTE: Should support nil to mean not supported the size feature doesn't really makde sense for the service

# File lib/coverband/adapters/web_service_store.rb, line 39
def size
  0
end

Private Instance Methods

add_retry_message(report_body) click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 113
def add_retry_message(report_body)
  if @failed_coverage_reports.length > 5
    logger&.info "Coverband: The errored reporting queue has reached 5. Subsequent reports will not be transmitted"
  else
    @failed_coverage_reports << report_body
  end
end
retry_failed_reports() click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 98
def retry_failed_reports
  retries = []
  @failed_coverage_reports.any? do
    begin
      report_body = @failed_coverage_reports.pop
      send_report_body(report_body)
    rescue
      retries << report_body
    end
  end
  retries.each do |report_body|
    add_retry_message(report_body)
  end
end
save_coverage(data) click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 121
def save_coverage(data)
  if Coverband.configuration.api_key.nil?
    puts "Coverband: Error: no Coverband API key was found!"
    return
  end

  coverage_body = {remote_uuid: SecureRandom.uuid, data: data}.to_json
  send_report_body(coverage_body)
rescue => e
  add_retry_message(coverage_body)
  logger&.info "Coverband: Error while saving coverage #{e}" if Coverband.configuration.verbose || Coverband.configuration.service_dev_mode
end
send_report_body(coverage_body) click to toggle source
# File lib/coverband/adapters/web_service_store.rb, line 134
def send_report_body(coverage_body)
  uri = URI("#{coverband_url}/api/collector")
  req = ::Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Coverband-Token" => Coverband.configuration.api_key)
  req.body = coverage_body
  logger&.info "Coverband: saving (#{uri}) #{req.body}" if Coverband.configuration.verbose
  res = ::Net::HTTP.start(
    uri.hostname,
    uri.port,
    open_timeout: Coverband.configuration.coverband_timeout,
    read_timeout: Coverband.configuration.coverband_timeout,
    ssl_timeout: Coverband.configuration.coverband_timeout,
    use_ssl: uri.scheme == "https"
  ) do |http|
    http.request(req)
  end
  if res.code.to_i >= 500
    add_retry_message(coverage_body)
  end
end