class ParallelCucumber::Main
Public Class Methods
new(options)
click to toggle source
# File lib/parallel_cucumber/main.rb, line 7 def initialize(options) @options = options @logger = ParallelCucumber::CustomLogger.new(STDOUT) load_external_files @logger.progname = 'Primary' # Longer than 'Main', to make the log file pretty. @logger.level = options[:debug] ? ParallelCucumber::CustomLogger::DEBUG : ParallelCucumber::CustomLogger::INFO end
Public Instance Methods
determine_work_and_batch_size(count)
click to toggle source
# File lib/parallel_cucumber/main.rb, line 164 def determine_work_and_batch_size(count) if @options[:n] == 0 @options[:n] = [1, @options[:env_variables].map { |_k, v| v.is_a?(Array) ? v.count : 0 }].flatten.max @logger.info("Inferred worker count #{@options[:n]} from env_variables option") end number_of_workers = [@options[:n], [@options[:backup_worker_count], count].max].min unless number_of_workers == @options[:n] @logger.info(<<-LOG) Number of workers was overridden to #{number_of_workers}. More workers (#{@options[:n]}) requested than tests (#{count}). BackupWorkerCount: #{@options[:backup_worker_count]}". LOG end @logger.info(<<-LOG) Number of workers is #{number_of_workers}. LOG if (@options[:batch_size] - 1) * number_of_workers >= count original_batch_size = @options[:batch_size] @options[:batch_size] = [(count.to_f / number_of_workers).floor, 1].max @logger.info(<<-LOG) Batch size was overridden to #{@options[:batch_size]}. Presumably it will be more optimal for #{count} tests and #{number_of_workers} workers than #{original_batch_size} LOG end number_of_workers end
load_external_files()
click to toggle source
# File lib/parallel_cucumber/main.rb, line 16 def load_external_files return if @options[:load_files].nil? @options[:load_files].each do |file| @logger.debug("Loading File: #{file}") load file end end
report_by_group(results)
click to toggle source
# File lib/parallel_cucumber/main.rb, line 129 def report_by_group(results) group = Hash.new { |h, k| h[k] = Hash.new(0) } # Default new keys to 0 Helper::Command.wrap_block(@options[:log_decoration], 'Worker summary', @logger) do results.find_all { |w| w.first =~ /^:worker-/ }.each do |w| # w = [:worker-0, [[:batches, 7], [:group, "localhost2"], [:skipped, 7]]] gp = w.last[:group] next unless gp w.last.each { |(k, v)| group[gp][k] += w.last[k] if v && k != :group } group[gp][:group] = {} unless group[gp].key?(:group) group[gp][:group][w.first] = 1 end end @logger.info "== Groups key count #{group.keys.count}" return unless group.keys.count > 1 Helper::Command.wrap_block(@options[:log_decoration], 'Group summary', @logger) do group.each { |(k, v)| @logger.info("#{k} #{v.sort}") } end end
run()
click to toggle source
# File lib/parallel_cucumber/main.rb, line 24 def run @logger.debug("Connecting to Queue: #{@options[:queue_connection_params]}") queue = Helper::Queue.new(@options[:queue_connection_params]) unless queue.empty? @logger.error("Queue '#{queue.name}' is not empty") exit(1) end begin all_tests = Helper::Cucumber.selected_tests(@options[:cucumber_options], @options[:cucumber_args]) rescue StandardError => error Hooks.fire_on_dry_run_error(error) raise error end if all_tests.empty? @logger.info('There is no tests to run, exiting...') exit(0) end long_running_tests = if @options[:long_running_tests] narrowed_long_running_tests = [ @options[:cucumber_args], @options[:long_running_tests] ].join(' ') Helper::Cucumber.selected_tests(@options[:cucumber_options], narrowed_long_running_tests) else [] end first_tests = long_running_tests & all_tests if !long_running_tests.empty? && first_tests.empty? @logger.info("No long running tests found in common with main options: #{long_running_tests}") end tests = first_tests + (all_tests - first_tests).shuffle collective_queue_size = 0 @options[:directed_tests].each do |k, v| directed_tests = Helper::Cucumber.selected_tests(@options[:cucumber_options], v) if directed_tests.empty? @logger.warn("Queue for #{k} is empty - nothing selected by #{v}") else directed_tests = (directed_tests & long_running_tests) + (directed_tests - long_running_tests).shuffle @logger.debug("Connecting to Queue: _#{k}") directed_queue = Helper::Queue.new(@options[:queue_connection_params], "_#{k}") @logger.info("Adding #{directed_tests.count} tests to queue _#{k}") directed_queue.enqueue(directed_tests) tests -= directed_tests collective_queue_size += directed_queue.length end end @logger.info("Adding #{tests.count} tests to Queue") queue.enqueue(tests) unless tests.empty? begin Hooks.fire_before_workers(queue: queue) rescue StandardError => e trace = e.backtrace.join("\n\t") @logger.warn("There was exception in before_workers hook #{e.message} \n #{trace}") end collective_queue_size += queue.length number_of_workers = determine_work_and_batch_size(collective_queue_size) status_totals = {} total_mm, total_ss = time_it do results = run_parallel_workers(number_of_workers) || {} begin Hooks.fire_after_workers(results: results, queue: queue) rescue StandardError => e trace = e.backtrace.join("\n\t") @logger.warn("There was exception in after_workers hook #{e.message} \n #{trace}") end unrun = tests - results.keys @logger.error("Tests #{unrun.join(' ')} were not run") unless unrun.empty? @logger.error("Queue #{queue.name} is not empty") unless queue.empty? status_totals = Status.constants.map do |status| status = Status.const_get(status) tests_with_status = results.select { |_t, s| s[:status] == status }.keys [status, tests_with_status] end.to_h Helper::Command.wrap_block(@options[:log_decoration], 'Worker summary', @logger) do results.find_all { |w| w.first =~ /^:worker-/ }.each { |w| @logger.info("#{w.first} #{w.last.sort}") } end report_by_group(results) end @logger.debug("SUMMARY=#{@options[:summary]}") if @options[:summary] status_totals.each do |s, tt| next if tt.empty? @logger.info("Total: #{s.to_s.upcase} tests (#{tt.count}): #{tt.join(' ')}") filename = @options[:summary] && @options[:summary][s.to_s.downcase] open(filename, 'w') { |f| f << tt.join("\n") } if filename end @logger.info("\nTook #{total_mm} minutes #{total_ss} seconds") exit((tests - status_totals[Status::PASSED] - status_totals[Status::SKIPPED]).empty? ? 0 : 1) end
run_parallel_workers(number_of_workers)
click to toggle source
# File lib/parallel_cucumber/main.rb, line 152 def run_parallel_workers(number_of_workers) Helper::Command.wrap_block(@options[:log_decoration], @options[:log_decoration]['worker_block'] || 'workers', @logger) do worker_manager = ParallelCucumber::WorkerManager.new(@options, @logger) worker_manager.start(number_of_workers) ensure worker_manager.kill end end