module KnapsackPro module Runners module Queue class RSpecRunner < BaseRunner def self.run(args) require 'rspec/core' require_relative '../../formatters/rspec_queue_summary_formatter' require_relative '../../formatters/rspec_queue_profile_formatter_extension' ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true' ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id runner = new(KnapsackPro::Adapters::RSpecAdapter) cli_args = (args || '').split # if user didn't provide the format then use explicitly default progress formatter # in order to avoid KnapsackPro::Formatters::RSpecQueueSummaryFormatter being the only default formatter cli_args += ['--format', 'progress'] unless cli_args.include?('--format') cli_args += [ '--format', KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s, '--default-path', runner.test_dir, ] run_tests(runner, true, cli_args, 0, []) end def self.run_tests(runner, can_initialize_queue, args, exitstatus, all_test_file_paths) test_file_paths = runner.test_file_paths( can_initialize_queue: can_initialize_queue, executed_test_files: all_test_file_paths ) if test_file_paths.empty? unless all_test_file_paths.empty? KnapsackPro::Formatters::RSpecQueueSummaryFormatter.print_summary KnapsackPro::Formatters::RSpecQueueProfileFormatterExtension.print_summary log_rspec_command(args, all_test_file_paths, :end_of_queue) end KnapsackPro::Hooks::Queue.call_after_queue KnapsackPro::Report.save_node_queue_to_api exit(exitstatus) else subset_queue_id = KnapsackPro::Config::EnvGenerator.set_subset_queue_id ENV['KNAPSACK_PRO_SUBSET_QUEUE_ID'] = subset_queue_id all_test_file_paths += test_file_paths cli_args = args + test_file_paths log_rspec_command(args, test_file_paths, :subset_queue) options = RSpec::Core::ConfigurationOptions.new(cli_args) exit_code = RSpec::Core::Runner.new(options).run($stderr, $stdout) exitstatus = exit_code if exit_code != 0 rspec_clear_examples KnapsackPro::Hooks::Queue.call_after_subset_queue run_tests(runner, false, args, exitstatus, all_test_file_paths) end end private def self.log_rspec_command(cli_args, test_file_paths, type) case type when :subset_queue KnapsackPro.logger.info("To retry in development the subset of tests fetched from API queue please run below command on your machine. If you use --order random then remember to add proper --seed 123 that you will find at the end of rspec command.") when :end_of_queue KnapsackPro.logger.info("To retry in development the tests for this CI node please run below command on your machine. It will run all tests in a single run. If you need to reproduce a particular subset of tests fetched from API queue then above after each request to Knapsack Pro API you will find example rspec command.") end stringify_cli_args = cli_args.join(' ') stringify_cli_args.slice!("--format #{KnapsackPro::Formatters::RSpecQueueSummaryFormatter}") KnapsackPro.logger.info( "bundle exec rspec #{stringify_cli_args} " + KnapsackPro::TestFilePresenter.stringify_paths(test_file_paths) ) end # Clear rspec examples without the shared examples: # https://github.com/rspec/rspec-core/pull/2379 # # Keep formatters and report to accumulate info about failed/pending tests def self.rspec_clear_examples if RSpec::ExampleGroups.respond_to?(:remove_all_constants) RSpec::ExampleGroups.remove_all_constants else RSpec::ExampleGroups.constants.each do |constant| RSpec::ExampleGroups.__send__(:remove_const, constant) end end RSpec.world.example_groups.clear RSpec.configuration.start_time = ::RSpec::Core::Time.now RSpec.configuration.reset_filters end end end end end