class KnapsackPro::Runners::Queue::RSpecRunner

Public Class Methods

new(adapter_class, rspec_pure, args, stream_error, stream_out) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 23
def initialize(adapter_class, rspec_pure, args, stream_error, stream_out)
  super(adapter_class)
  @adapter_class = adapter_class
  @rspec_pure = rspec_pure
  args_array = (args || '').split
  has_format_option = @adapter_class.has_format_option?(args_array)
  has_require_rails_helper_option = @adapter_class.has_require_rails_helper_option?(args_array)
  rails_helper_exists = @adapter_class.rails_helper_exists?(test_dir)
  @cli_args = rspec_pure.prepare_cli_args(args, has_format_option, has_require_rails_helper_option, rails_helper_exists, test_dir)
  @stream_error = stream_error
  @stream_out = stream_out
  @node_test_file_paths = []
  @rspec_runner = nil # RSpec::Core::Runner is lazy initialized
  @queue = KnapsackPro::Queue.new
end
run(args, stream_error = $stderr, stream_out = $stdout) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 7
def self.run(args, stream_error = $stderr, stream_out = $stdout)
  require 'rspec/core'
  require_relative '../../extensions/rspec_extension'
  require_relative '../../formatters/time_tracker'
  require_relative '../../formatters/time_tracker_fetcher'

  KnapsackPro::Extensions::RSpecExtension.setup!

  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec

  rspec_pure = KnapsackPro::Pure::Queue::RSpecPure.new

  queue_runner = new(KnapsackPro::Adapters::RSpecAdapter, rspec_pure, args, stream_error, stream_out)
  queue_runner.run
end

Public Instance Methods

handle_signal!() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 110
def handle_signal!
  self.class.handle_signal!
end
log_fail_fast_limit_met() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 114
def log_fail_fast_limit_met
  KnapsackPro.logger.warn('Test execution has been canceled because the RSpec --fail-fast option is enabled. It will cause other CI nodes to run tests longer because they need to consume more tests from the Knapsack Pro Queue API.')
end
run() click to toggle source

Based on: github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L85

@return [Fixnum] exit status code.

0 if all specs passed,
or the configured failure exit code (1 by default) if specs failed.
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 45
def run
  pre_run_setup

  if @rspec_runner.knapsack__wants_to_quit?
    exit_code = @rspec_runner.knapsack__exit_early
    Kernel.exit(exit_code)
  end

  begin
    exit_code = @rspec_runner.knapsack__run_specs(self)
  rescue KnapsackPro::Runners::Queue::BaseRunner::TerminationError
    exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
    Kernel.exit(exit_code)
  rescue KnapsackPro::QueueAllocator::FallbackModeError
    exit_code = KnapsackPro::Config::Env.fallback_mode_error_exit_code
    Kernel.exit(exit_code)
  rescue Exception => exception
    KnapsackPro.logger.error("An unexpected exception happened. RSpec cannot handle it. The exception: #{exception.inspect}")
    KnapsackPro.logger.error("Exception message: #{exception.message}")
    KnapsackPro.logger.error("Exception backtrace: #{exception.backtrace&.join("\n")}")

    message = @rspec_pure.exit_summary(unexecuted_test_files)
    KnapsackPro.logger.warn(message) if message

    exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
    Kernel.exit(exit_code)
  end

  post_run_tasks(exit_code)
end
with_batch() { |test_file_paths, queue| ... } click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 76
def with_batch
  can_initialize_queue = true

  loop do
    handle_signal!
    test_file_paths = pull_tests_from_queue(can_initialize_queue: can_initialize_queue)
    can_initialize_queue = false

    break if test_file_paths.empty?

    subset_queue_id = KnapsackPro::Config::EnvGenerator.set_subset_queue_id
    ENV['KNAPSACK_PRO_SUBSET_QUEUE_ID'] = subset_queue_id

    @queue.add_batch_for(test_file_paths)

    KnapsackPro::Hooks::Queue.call_before_subset_queue(@queue)

    yield test_file_paths, @queue

    KnapsackPro::Hooks::Queue.call_after_subset_queue(@queue)

    if @rspec_runner.knapsack__wants_to_quit?
      KnapsackPro.logger.warn('RSpec wants to quit.')
      set_terminate_process
    end
    if @rspec_runner.knapsack__rspec_is_quitting?
      KnapsackPro.logger.warn('RSpec is quitting.')
      set_terminate_process
    end

    log_rspec_batch_command(test_file_paths)
  end
end

Private Instance Methods

ensure_no_deprecated_run_all_when_everything_filtered_option!() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 147
def ensure_no_deprecated_run_all_when_everything_filtered_option!
  return unless @rspec_runner.knapsack__deprecated_run_all_when_everything_filtered_enabled?

  error_message = "The run_all_when_everything_filtered option is deprecated. See: #{KnapsackPro::Urls::RSPEC__DEPRECATED_RUN_ALL_WHEN_EVERYTHING_FILTERED}"
  KnapsackPro.logger.error(error_message)
  raise error_message
end
log_info_messages(messages) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 178
def log_info_messages(messages)
  messages.each do |message|
    KnapsackPro.logger.info(message)
  end
end
log_rspec_batch_command(test_file_paths) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 164
def log_rspec_batch_command(test_file_paths)
  order_option = @adapter_class.order_option(@cli_args)
  printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
  messages = @rspec_pure.rspec_command(printable_args, test_file_paths, :batch_finished)
  log_info_messages(messages)
end
log_rspec_queue_command() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 171
def log_rspec_queue_command
  order_option = @adapter_class.order_option(@cli_args)
  printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
  messages = @rspec_pure.rspec_command(printable_args, @node_test_file_paths, :queue_finished)
  log_info_messages(messages)
end
post_run_tasks(exit_code) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 136
def post_run_tasks(exit_code)
  @adapter_class.verify_bind_method_called

  log_rspec_queue_command

  time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
  KnapsackPro::Report.save_node_queue_to_api(time_tracker&.queue(@node_test_file_paths))

  Kernel.exit(exit_code)
end
pre_run_setup() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 120
def pre_run_setup
  ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true'
  ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id

  KnapsackPro::Config::Env.set_test_runner_adapter(@adapter_class)

  ENV['SPEC_OPTS'] = @rspec_pure.add_knapsack_pro_formatters_to(ENV['SPEC_OPTS'])
  @adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(@cli_args)

  rspec_configuration_options = ::RSpec::Core::ConfigurationOptions.new(@cli_args)
  @rspec_runner = ::RSpec::Core::Runner.new(rspec_configuration_options)
  @rspec_runner.knapsack__setup(@stream_error, @stream_out)

  ensure_no_deprecated_run_all_when_everything_filtered_option!
end
pull_tests_from_queue(can_initialize_queue: false) click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 155
def pull_tests_from_queue(can_initialize_queue: false)
  test_file_paths = test_file_paths(
    can_initialize_queue: can_initialize_queue,
    executed_test_files: @node_test_file_paths
  )
  @node_test_file_paths += test_file_paths
  test_file_paths
end
unexecuted_test_files() click to toggle source
# File lib/knapsack_pro/runners/queue/rspec_runner.rb, line 184
def unexecuted_test_files
  KnapsackPro::Formatters::TimeTrackerFetcher.unexecuted_test_files(@node_test_file_paths)
end