diff options
Diffstat (limited to 'tooling/lib/tooling/parallel_rspec_runner.rb')
-rw-r--r-- | tooling/lib/tooling/parallel_rspec_runner.rb | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/tooling/lib/tooling/parallel_rspec_runner.rb b/tooling/lib/tooling/parallel_rspec_runner.rb new file mode 100644 index 00000000000..b482160d3c0 --- /dev/null +++ b/tooling/lib/tooling/parallel_rspec_runner.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'knapsack' + +# A custom parallel rspec runner based on Knapsack runner +# which takes in additional option for a file containing +# list of test files. +# +# When executing RSpec in CI, the list of tests allocated by Knapsack +# will be compared with the test files listed in the file. +# +# Only the test files allocated by Knapsack and listed in the file +# would be executed in the CI node. +# +# Reference: +# https://github.com/ArturT/knapsack/blob/v1.20.0/lib/knapsack/runners/rspec_runner.rb +module Tooling + class ParallelRSpecRunner + def self.run(rspec_args: nil, filter_tests_file: nil) + new(rspec_args: rspec_args, filter_tests_file: filter_tests_file).run + end + + def initialize(allocator: knapsack_allocator, filter_tests_file: nil, rspec_args: nil) + @allocator = allocator + @filter_tests_file = filter_tests_file + @rspec_args = rspec_args&.split(' ') || [] + end + + def run + Knapsack.logger.info + Knapsack.logger.info 'Knapsack node specs:' + Knapsack.logger.info node_tests + Knapsack.logger.info + Knapsack.logger.info 'Filter specs:' + Knapsack.logger.info filter_tests + Knapsack.logger.info + Knapsack.logger.info 'Running specs:' + Knapsack.logger.info tests_to_run + Knapsack.logger.info + + if tests_to_run.empty? + Knapsack.logger.info 'No tests to run on this node, exiting.' + return + end + + exec(*rspec_command) + end + + private + + attr_reader :allocator, :filter_tests_file, :rspec_args + + def rspec_command + %w[bundle exec rspec].tap do |cmd| + cmd.push(*rspec_args) + cmd.push('--default-path', allocator.test_dir) + cmd.push('--') + cmd.push(*tests_to_run) + end + end + + def tests_to_run + if filter_tests.empty? + Knapsack.logger.info 'Running all node tests without filter' + return node_tests + end + + @tests_to_run ||= node_tests & filter_tests + end + + def node_tests + allocator.node_tests + end + + def filter_tests + @filter_tests ||= + filter_tests_file ? tests_from_file(filter_tests_file) : [] + end + + def tests_from_file(filter_tests_file) + return [] unless File.exist?(filter_tests_file) + + File.read(filter_tests_file).split(' ') + end + + def knapsack_allocator + Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator + end + end +end |