parallel_tests 3.2.0 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/Readme.md +26 -8
 - data/bin/parallel_cucumber +2 -1
 - data/bin/parallel_rspec +2 -1
 - data/bin/parallel_spinach +2 -1
 - data/bin/parallel_test +2 -1
 - data/lib/parallel_tests.rb +4 -2
 - data/lib/parallel_tests/cli.rb +90 -47
 - data/lib/parallel_tests/cucumber/failures_logger.rb +1 -1
 - data/lib/parallel_tests/cucumber/features_with_steps.rb +4 -3
 - data/lib/parallel_tests/cucumber/runner.rb +4 -5
 - data/lib/parallel_tests/cucumber/scenario_line_logger.rb +3 -3
 - data/lib/parallel_tests/cucumber/scenarios.rb +5 -5
 - data/lib/parallel_tests/gherkin/io.rb +2 -3
 - data/lib/parallel_tests/gherkin/listener.rb +9 -10
 - data/lib/parallel_tests/gherkin/runner.rb +16 -21
 - data/lib/parallel_tests/gherkin/runtime_logger.rb +2 -1
 - data/lib/parallel_tests/grouper.rb +88 -10
 - data/lib/parallel_tests/pids.rb +3 -2
 - data/lib/parallel_tests/railtie.rb +1 -0
 - data/lib/parallel_tests/rspec/failures_logger.rb +2 -2
 - data/lib/parallel_tests/rspec/logger_base.rb +9 -7
 - data/lib/parallel_tests/rspec/runner.rb +21 -5
 - data/lib/parallel_tests/rspec/runtime_logger.rb +12 -10
 - data/lib/parallel_tests/rspec/summary_logger.rb +2 -3
 - data/lib/parallel_tests/spinach/runner.rb +2 -2
 - data/lib/parallel_tests/tasks.rb +44 -30
 - data/lib/parallel_tests/test/runner.rb +32 -27
 - data/lib/parallel_tests/test/runtime_logger.rb +19 -14
 - data/lib/parallel_tests/version.rb +2 -1
 - metadata +4 -4
 
| 
         @@ -1,10 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'parallel_tests/rspec/logger_base'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'parallel_tests/rspec/runner'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            class ParallelTests::RSpec::FailuresLogger < ParallelTests::RSpec::LoggerBase
         
     | 
| 
       5 
6 
     | 
    
         
             
              if RSPEC_2
         
     | 
| 
       6 
     | 
    
         
            -
                def dump_failures(*args)
         
     | 
| 
       7 
     | 
    
         
            -
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
                def dump_failures(*args); end
         
     | 
| 
       8 
8 
     | 
    
         
             
              else
         
     | 
| 
       9 
9 
     | 
    
         
             
                RSpec::Core::Formatters.register self, :dump_summary
         
     | 
| 
       10 
10 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
       2 
3 
     | 
    
         
             
              module RSpec
         
     | 
| 
       3 
4 
     | 
    
         
             
              end
         
     | 
| 
         @@ -13,26 +14,27 @@ class ParallelTests::RSpec::LoggerBase < RSpec::Core::Formatters::BaseTextFormat 
     | 
|
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
                @output ||= args[0]
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                 
     | 
| 
      
 17 
     | 
    
         
            +
                case @output
         
     | 
| 
      
 18 
     | 
    
         
            +
                when String # a path ?
         
     | 
| 
       17 
19 
     | 
    
         
             
                  FileUtils.mkdir_p(File.dirname(@output))
         
     | 
| 
       18 
     | 
    
         
            -
                  File.open(@output, 'w'){} # overwrite previous results
         
     | 
| 
      
 20 
     | 
    
         
            +
                  File.open(@output, 'w') {} # overwrite previous results
         
     | 
| 
       19 
21 
     | 
    
         
             
                  @output = File.open(@output, 'a')
         
     | 
| 
       20 
     | 
    
         
            -
                 
     | 
| 
      
 22 
     | 
    
         
            +
                when File # close and restart in append mode
         
     | 
| 
       21 
23 
     | 
    
         
             
                  @output.close
         
     | 
| 
       22 
24 
     | 
    
         
             
                  @output = File.open(@output.path, 'a')
         
     | 
| 
       23 
25 
     | 
    
         
             
                end
         
     | 
| 
       24 
26 
     | 
    
         
             
              end
         
     | 
| 
       25 
27 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
              #stolen from Rspec
         
     | 
| 
       27 
     | 
    
         
            -
              def close(* 
     | 
| 
       28 
     | 
    
         
            -
                @output.close 
     | 
| 
      
 28 
     | 
    
         
            +
              # stolen from Rspec
         
     | 
| 
      
 29 
     | 
    
         
            +
              def close(*)
         
     | 
| 
      
 30 
     | 
    
         
            +
                @output.close if (IO === @output) & (@output != $stdout)
         
     | 
| 
       29 
31 
     | 
    
         
             
              end
         
     | 
| 
       30 
32 
     | 
    
         | 
| 
       31 
33 
     | 
    
         
             
              protected
         
     | 
| 
       32 
34 
     | 
    
         | 
| 
       33 
35 
     | 
    
         
             
              # do not let multiple processes get in each others way
         
     | 
| 
       34 
36 
     | 
    
         
             
              def lock_output
         
     | 
| 
       35 
     | 
    
         
            -
                if  
     | 
| 
      
 37 
     | 
    
         
            +
                if @output.is_a?(File)
         
     | 
| 
       36 
38 
     | 
    
         
             
                  begin
         
     | 
| 
       37 
39 
     | 
    
         
             
                    @output.flock File::LOCK_EX
         
     | 
| 
       38 
40 
     | 
    
         
             
                    yield
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require "parallel_tests/test/runner"
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
         @@ -12,10 +13,9 @@ module ParallelTests 
     | 
|
| 
       12 
13 
     | 
    
         
             
                    end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
                    def determine_executable
         
     | 
| 
       15 
     | 
    
         
            -
                       
     | 
| 
       16 
     | 
    
         
            -
                      when File.exist?("bin/rspec")
         
     | 
| 
      
 16 
     | 
    
         
            +
                      if File.exist?("bin/rspec")
         
     | 
| 
       17 
17 
     | 
    
         
             
                        ParallelTests.with_ruby_binary("bin/rspec")
         
     | 
| 
       18 
     | 
    
         
            -
                       
     | 
| 
      
 18 
     | 
    
         
            +
                      elsif ParallelTests.bundler_enabled?
         
     | 
| 
       19 
19 
     | 
    
         
             
                        "bundle exec rspec"
         
     | 
| 
       20 
20 
     | 
    
         
             
                      else
         
     | 
| 
       21 
21 
     | 
    
         
             
                        "rspec"
         
     | 
| 
         @@ -23,7 +23,7 @@ module ParallelTests 
     | 
|
| 
       23 
23 
     | 
    
         
             
                    end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                    def runtime_log
         
     | 
| 
       26 
     | 
    
         
            -
                       
     | 
| 
      
 26 
     | 
    
         
            +
                      "tmp/parallel_runtime_rspec.log"
         
     | 
| 
       27 
27 
     | 
    
         
             
                    end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                    def test_file_name
         
     | 
| 
         @@ -48,6 +48,22 @@ module ParallelTests 
     | 
|
| 
       48 
48 
     | 
    
         
             
                      "#{clean} --seed #{seed}"
         
     | 
| 
       49 
49 
     | 
    
         
             
                    end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                    # Summarize results from threads and colorize results based on failure and pending counts.
         
     | 
| 
      
 52 
     | 
    
         
            +
                    #
         
     | 
| 
      
 53 
     | 
    
         
            +
                    def summarize_results(results)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      text = super
         
     | 
| 
      
 55 
     | 
    
         
            +
                      return text unless $stdout.tty?
         
     | 
| 
      
 56 
     | 
    
         
            +
                      sums = sum_up_results(results)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      color =
         
     | 
| 
      
 58 
     | 
    
         
            +
                        if sums['failure'] > 0
         
     | 
| 
      
 59 
     | 
    
         
            +
                          31 # red
         
     | 
| 
      
 60 
     | 
    
         
            +
                        elsif sums['pending'] > 0
         
     | 
| 
      
 61 
     | 
    
         
            +
                          33 # yellow
         
     | 
| 
      
 62 
     | 
    
         
            +
                        else
         
     | 
| 
      
 63 
     | 
    
         
            +
                          32 # green
         
     | 
| 
      
 64 
     | 
    
         
            +
                        end
         
     | 
| 
      
 65 
     | 
    
         
            +
                      "\e[#{color}m#{text}\e[0m"
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
       51 
67 
     | 
    
         | 
| 
       52 
68 
     | 
    
         
             
                    private
         
     | 
| 
       53 
69 
     | 
    
         | 
| 
         @@ -61,7 +77,7 @@ module ParallelTests 
     | 
|
| 
       61 
77 
     | 
    
         
             
                    end
         
     | 
| 
       62 
78 
     | 
    
         | 
| 
       63 
79 
     | 
    
         
             
                    def spec_opts
         
     | 
| 
       64 
     | 
    
         
            -
                      options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect{|f| File.file?(f) }
         
     | 
| 
      
 80 
     | 
    
         
            +
                      options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
         
     | 
| 
       65 
81 
     | 
    
         
             
                      return unless options_file
         
     | 
| 
       66 
82 
     | 
    
         
             
                      "-O #{options_file}"
         
     | 
| 
       67 
83 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'parallel_tests'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'parallel_tests/rspec/logger_base'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
         @@ -8,9 +9,7 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase 
     | 
|
| 
       8 
9 
     | 
    
         
             
                @group_nesting = 0
         
     | 
| 
       9 
10 
     | 
    
         
             
              end
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
              unless RSPEC_2
         
     | 
| 
       12 
     | 
    
         
            -
                RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished, :start_dump
         
     | 
| 
       13 
     | 
    
         
            -
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
              RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished, :start_dump unless RSPEC_2
         
     | 
| 
       14 
13 
     | 
    
         | 
| 
       15 
14 
     | 
    
         
             
              def example_group_started(example_group)
         
     | 
| 
       16 
15 
     | 
    
         
             
                @time = ParallelTests.now if @group_nesting == 0
         
     | 
| 
         @@ -27,16 +26,19 @@ class ParallelTests::RSpec::RuntimeLogger < ParallelTests::RSpec::LoggerBase 
     | 
|
| 
       27 
26 
     | 
    
         
             
                super if defined?(super)
         
     | 
| 
       28 
27 
     | 
    
         
             
              end
         
     | 
| 
       29 
28 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
              def dump_summary(* 
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
              def  
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
      
 29 
     | 
    
         
            +
              def dump_summary(*); end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def dump_failures(*); end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def dump_failure(*); end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              def dump_pending(*); end
         
     | 
| 
       34 
36 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
              def start_dump(* 
     | 
| 
       36 
     | 
    
         
            -
                return unless ENV['TEST_ENV_NUMBER'] #only record when running in parallel
         
     | 
| 
      
 37 
     | 
    
         
            +
              def start_dump(*)
         
     | 
| 
      
 38 
     | 
    
         
            +
                return unless ENV['TEST_ENV_NUMBER'] # only record when running in parallel
         
     | 
| 
       37 
39 
     | 
    
         
             
                lock_output do
         
     | 
| 
       38 
40 
     | 
    
         
             
                  @example_times.each do |file, time|
         
     | 
| 
       39 
     | 
    
         
            -
                    relative_path = file.sub( 
     | 
| 
      
 41 
     | 
    
         
            +
                    relative_path = file.sub(%r{^#{Regexp.escape Dir.pwd}/}, '').sub(%r{^\./}, "")
         
     | 
| 
       40 
42 
     | 
    
         
             
                    @output.puts "#{relative_path}:#{time > 0 ? time : 0}"
         
     | 
| 
       41 
43 
     | 
    
         
             
                  end
         
     | 
| 
       42 
44 
     | 
    
         
             
                end
         
     | 
| 
         @@ -1,9 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'parallel_tests/rspec/failures_logger'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            class ParallelTests::RSpec::SummaryLogger < ParallelTests::RSpec::LoggerBase
         
     | 
| 
       4 
     | 
    
         
            -
              unless RSPEC_2
         
     | 
| 
       5 
     | 
    
         
            -
                RSpec::Core::Formatters.register self, :dump_failures
         
     | 
| 
       6 
     | 
    
         
            -
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
              RSpec::Core::Formatters.register self, :dump_failures unless RSPEC_2
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
              def dump_failures(*args)
         
     | 
| 
       9 
8 
     | 
    
         
             
                lock_output { super }
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require "parallel_tests/gherkin/runner"
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
         @@ -9,10 +10,9 @@ module ParallelTests 
     | 
|
| 
       9 
10 
     | 
    
         
             
                    end
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
12 
     | 
    
         
             
                    def runtime_logging
         
     | 
| 
       12 
     | 
    
         
            -
                      #Not Yet Supported
         
     | 
| 
      
 13 
     | 
    
         
            +
                      # Not Yet Supported
         
     | 
| 
       13 
14 
     | 
    
         
             
                      ""
         
     | 
| 
       14 
15 
     | 
    
         
             
                    end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
16 
     | 
    
         
             
                  end
         
     | 
| 
       17 
17 
     | 
    
         
             
                end
         
     | 
| 
       18 
18 
     | 
    
         
             
              end
         
     | 
    
        data/lib/parallel_tests/tasks.rb
    CHANGED
    
    | 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'rake'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'shellwords'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
         @@ -27,12 +28,13 @@ module ParallelTests 
     | 
|
| 
       27 
28 
     | 
    
         
             
                    end
         
     | 
| 
       28 
29 
     | 
    
         
             
                  end
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
                  def run_in_parallel(cmd, options={})
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def run_in_parallel(cmd, options = {})
         
     | 
| 
       31 
32 
     | 
    
         
             
                    load_lib
         
     | 
| 
       32 
33 
     | 
    
         
             
                    count = " -n #{options[:count]}" unless options[:count].to_s.empty?
         
     | 
| 
       33 
34 
     | 
    
         
             
                    # Using the relative path to find the binary allow to run a specific version of it
         
     | 
| 
       34 
     | 
    
         
            -
                    executable = File.expand_path( 
     | 
| 
       35 
     | 
    
         
            -
                     
     | 
| 
      
 35 
     | 
    
         
            +
                    executable = File.expand_path('../../bin/parallel_test', __dir__)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    non_parallel = (options[:non_parallel] ? ' --non-parallel' : '')
         
     | 
| 
      
 37 
     | 
    
         
            +
                    command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} --exec '#{cmd}'#{count}#{non_parallel}"
         
     | 
| 
       36 
38 
     | 
    
         
             
                    abort unless system(command)
         
     | 
| 
       37 
39 
     | 
    
         
             
                  end
         
     | 
| 
       38 
40 
     | 
    
         | 
| 
         @@ -50,12 +52,12 @@ module ParallelTests 
     | 
|
| 
       50 
52 
     | 
    
         
             
                  # - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
         
     | 
| 
       51 
53 
     | 
    
         
             
                  def suppress_output(command, ignore_regex)
         
     | 
| 
       52 
54 
     | 
    
         
             
                    activate_pipefail = "set -o pipefail"
         
     | 
| 
       53 
     | 
    
         
            -
                    remove_ignored_lines = % 
     | 
| 
      
 55 
     | 
    
         
            +
                    remove_ignored_lines = %{(grep -v "#{ignore_regex}" || test 1)}
         
     | 
| 
       54 
56 
     | 
    
         | 
| 
       55 
57 
     | 
    
         
             
                    if File.executable?('/bin/bash') && system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null && test 1")
         
     | 
| 
       56 
58 
     | 
    
         
             
                      # We need to shell escape single quotes (' becomes '"'"') because
         
     | 
| 
       57 
59 
     | 
    
         
             
                      # run_in_parallel wraps command in single quotes
         
     | 
| 
       58 
     | 
    
         
            -
                      % 
     | 
| 
      
 60 
     | 
    
         
            +
                      %{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
         
     | 
| 
       59 
61 
     | 
    
         
             
                    else
         
     | 
| 
       60 
62 
     | 
    
         
             
                      command
         
     | 
| 
       61 
63 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -83,7 +85,7 @@ module ParallelTests 
     | 
|
| 
       83 
85 
     | 
    
         
             
                    # parallel:spec[2,models,options]
         
     | 
| 
       84 
86 
     | 
    
         
             
                    # parallel:spec[,models,options]
         
     | 
| 
       85 
87 
     | 
    
         
             
                    count = args.shift if args.first.to_s =~ /^\d*$/
         
     | 
| 
       86 
     | 
    
         
            -
                    num_processes = count. 
     | 
| 
      
 88 
     | 
    
         
            +
                    num_processes = (count.to_s.empty? ? nil : Integer(count))
         
     | 
| 
       87 
89 
     | 
    
         
             
                    pattern = args.shift
         
     | 
| 
       88 
90 
     | 
    
         
             
                    options = args.shift
         
     | 
| 
       89 
91 
     | 
    
         
             
                    pass_through = args.shift
         
     | 
| 
         @@ -96,30 +98,38 @@ end 
     | 
|
| 
       96 
98 
     | 
    
         | 
| 
       97 
99 
     | 
    
         
             
            namespace :parallel do
         
     | 
| 
       98 
100 
     | 
    
         
             
              desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
         
     | 
| 
       99 
     | 
    
         
            -
              task :setup, :count do |_,args|
         
     | 
| 
      
 101 
     | 
    
         
            +
              task :setup, :count do |_, args|
         
     | 
| 
       100 
102 
     | 
    
         
             
                command = "#{ParallelTests::Tasks.rake_bin} db:setup RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
         
     | 
| 
       101 
103 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
         
     | 
| 
       102 
104 
     | 
    
         
             
              end
         
     | 
| 
       103 
105 
     | 
    
         | 
| 
       104 
106 
     | 
    
         
             
              desc "Create test databases via db:create --> parallel:create[num_cpus]"
         
     | 
| 
       105 
     | 
    
         
            -
              task :create, :count do |_,args|
         
     | 
| 
      
 107 
     | 
    
         
            +
              task :create, :count do |_, args|
         
     | 
| 
       106 
108 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       107 
     | 
    
         
            -
                  "#{ParallelTests::Tasks.rake_bin} db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args 
     | 
| 
      
 109 
     | 
    
         
            +
                  "#{ParallelTests::Tasks.rake_bin} db:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
         
     | 
| 
      
 110 
     | 
    
         
            +
                )
         
     | 
| 
       108 
111 
     | 
    
         
             
              end
         
     | 
| 
       109 
112 
     | 
    
         | 
| 
       110 
113 
     | 
    
         
             
              desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
         
     | 
| 
       111 
     | 
    
         
            -
              task :drop, :count do |_,args|
         
     | 
| 
      
 114 
     | 
    
         
            +
              task :drop, :count do |_, args|
         
     | 
| 
       112 
115 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       113 
116 
     | 
    
         
             
                  "#{ParallelTests::Tasks.rake_bin} db:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env} " \
         
     | 
| 
       114 
     | 
    
         
            -
                  "DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args 
     | 
| 
      
 117 
     | 
    
         
            +
                  "DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args
         
     | 
| 
      
 118 
     | 
    
         
            +
                )
         
     | 
| 
       115 
119 
     | 
    
         
             
              end
         
     | 
| 
       116 
120 
     | 
    
         | 
| 
       117 
121 
     | 
    
         
             
              desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
         
     | 
| 
       118 
     | 
    
         
            -
              task(:prepare, [:count]) do |_,args|
         
     | 
| 
      
 122 
     | 
    
         
            +
              task(:prepare, [:count]) do |_, args|
         
     | 
| 
       119 
123 
     | 
    
         
             
                ParallelTests::Tasks.check_for_pending_migrations
         
     | 
| 
       120 
124 
     | 
    
         
             
                if defined?(ActiveRecord::Base) && [:ruby, :sql].include?(ActiveRecord::Base.schema_format)
         
     | 
| 
       121 
125 
     | 
    
         
             
                  # fast: dump once, load in parallel
         
     | 
| 
       122 
     | 
    
         
            -
                  type = 
     | 
| 
      
 126 
     | 
    
         
            +
                  type =
         
     | 
| 
      
 127 
     | 
    
         
            +
                    if Gem::Version.new(Rails.version) >= Gem::Version.new('6.1.0')
         
     | 
| 
      
 128 
     | 
    
         
            +
                      "schema"
         
     | 
| 
      
 129 
     | 
    
         
            +
                    else
         
     | 
| 
      
 130 
     | 
    
         
            +
                      ActiveRecord::Base.schema_format == :ruby ? "schema" : "structure"
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
       123 
133 
     | 
    
         
             
                  Rake::Task["db:#{type}:dump"].invoke
         
     | 
| 
       124 
134 
     | 
    
         | 
| 
       125 
135 
     | 
    
         
             
                  # remove database connection to prevent "database is being accessed by other users"
         
     | 
| 
         @@ -128,7 +138,7 @@ namespace :parallel do 
     | 
|
| 
       128 
138 
     | 
    
         
             
                  Rake::Task["parallel:load_#{type}"].invoke(args[:count])
         
     | 
| 
       129 
139 
     | 
    
         
             
                else
         
     | 
| 
       130 
140 
     | 
    
         
             
                  # slow: dump and load in in serial
         
     | 
| 
       131 
     | 
    
         
            -
                  args = args.to_hash.merge(: 
     | 
| 
      
 141 
     | 
    
         
            +
                  args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
         
     | 
| 
       132 
142 
     | 
    
         
             
                  task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
         
     | 
| 
       133 
143 
     | 
    
         
             
                  ParallelTests::Tasks.run_in_parallel("#{ParallelTests::Tasks.rake_bin} #{task_name}", args)
         
     | 
| 
       134 
144 
     | 
    
         
             
                  next
         
     | 
| 
         @@ -137,49 +147,55 @@ namespace :parallel do 
     | 
|
| 
       137 
147 
     | 
    
         | 
| 
       138 
148 
     | 
    
         
             
              # when dumping/resetting takes too long
         
     | 
| 
       139 
149 
     | 
    
         
             
              desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
         
     | 
| 
       140 
     | 
    
         
            -
              task :migrate, :count do |_,args|
         
     | 
| 
      
 150 
     | 
    
         
            +
              task :migrate, :count do |_, args|
         
     | 
| 
       141 
151 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       142 
     | 
    
         
            -
                  "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args 
     | 
| 
      
 152 
     | 
    
         
            +
                  "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
         
     | 
| 
      
 153 
     | 
    
         
            +
                )
         
     | 
| 
       143 
154 
     | 
    
         
             
              end
         
     | 
| 
       144 
155 
     | 
    
         | 
| 
       145 
156 
     | 
    
         
             
              desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
         
     | 
| 
       146 
     | 
    
         
            -
              task :rollback, :count do |_,args|
         
     | 
| 
      
 157 
     | 
    
         
            +
              task :rollback, :count do |_, args|
         
     | 
| 
       147 
158 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       148 
     | 
    
         
            -
                  "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args 
     | 
| 
      
 159 
     | 
    
         
            +
                  "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
         
     | 
| 
      
 160 
     | 
    
         
            +
                )
         
     | 
| 
       149 
161 
     | 
    
         
             
              end
         
     | 
| 
       150 
162 
     | 
    
         | 
| 
       151 
163 
     | 
    
         
             
              # just load the schema (good for integration server <-> no development db)
         
     | 
| 
       152 
164 
     | 
    
         
             
              desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
         
     | 
| 
       153 
     | 
    
         
            -
              task :load_schema, :count do |_,args|
         
     | 
| 
      
 165 
     | 
    
         
            +
              task :load_schema, :count do |_, args|
         
     | 
| 
       154 
166 
     | 
    
         
             
                command = "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
         
     | 
| 
       155 
167 
     | 
    
         
             
                  "db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
         
     | 
| 
       156 
168 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
         
     | 
| 
       157 
169 
     | 
    
         
             
              end
         
     | 
| 
       158 
170 
     | 
    
         | 
| 
       159 
171 
     | 
    
         
             
              # load the structure from the structure.sql file
         
     | 
| 
       160 
     | 
    
         
            -
               
     | 
| 
       161 
     | 
    
         
            -
               
     | 
| 
      
 172 
     | 
    
         
            +
              # (faster for rails < 6.1, deprecated after and only configured by `ActiveRecord::Base.schema_format`)
         
     | 
| 
      
 173 
     | 
    
         
            +
              desc "Load structure for test databases via db:schema:load --> parallel:load_structure[num_cpus]"
         
     | 
| 
      
 174 
     | 
    
         
            +
              task :load_structure, :count do |_, args|
         
     | 
| 
       162 
175 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       163 
176 
     | 
    
         
             
                  "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
         
     | 
| 
       164 
     | 
    
         
            -
                  "db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args 
     | 
| 
      
 177 
     | 
    
         
            +
                  "db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args
         
     | 
| 
      
 178 
     | 
    
         
            +
                )
         
     | 
| 
       165 
179 
     | 
    
         
             
              end
         
     | 
| 
       166 
180 
     | 
    
         | 
| 
       167 
181 
     | 
    
         
             
              desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
         
     | 
| 
       168 
     | 
    
         
            -
              task :seed, :count do |_,args|
         
     | 
| 
      
 182 
     | 
    
         
            +
              task :seed, :count do |_, args|
         
     | 
| 
       169 
183 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       170 
     | 
    
         
            -
                  "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args 
     | 
| 
      
 184 
     | 
    
         
            +
                  "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
         
     | 
| 
      
 185 
     | 
    
         
            +
                )
         
     | 
| 
       171 
186 
     | 
    
         
             
              end
         
     | 
| 
       172 
187 
     | 
    
         | 
| 
       173 
188 
     | 
    
         
             
              desc "Launch given rake command in parallel"
         
     | 
| 
       174 
189 
     | 
    
         
             
              task :rake, :command, :count do |_, args|
         
     | 
| 
       175 
190 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       176 
191 
     | 
    
         
             
                  "RAILS_ENV=#{ParallelTests::Tasks.rails_env} #{ParallelTests::Tasks.rake_bin} " \
         
     | 
| 
       177 
     | 
    
         
            -
                  "#{args.command}", args 
     | 
| 
      
 192 
     | 
    
         
            +
                  "#{args.command}", args
         
     | 
| 
      
 193 
     | 
    
         
            +
                )
         
     | 
| 
       178 
194 
     | 
    
         
             
              end
         
     | 
| 
       179 
195 
     | 
    
         | 
| 
       180 
196 
     | 
    
         
             
              ['test', 'spec', 'features', 'features-spinach'].each do |type|
         
     | 
| 
       181 
197 
     | 
    
         
             
                desc "Run #{type} in parallel with parallel:#{type}[num_cpus]"
         
     | 
| 
       182 
     | 
    
         
            -
                task type, [:count, :pattern, :options, :pass_through] do | 
     | 
| 
      
 198 
     | 
    
         
            +
                task type, [:count, :pattern, :options, :pass_through] do |_t, args|
         
     | 
| 
       183 
199 
     | 
    
         
             
                  ParallelTests::Tasks.check_for_pending_migrations
         
     | 
| 
       184 
200 
     | 
    
         
             
                  ParallelTests::Tasks.load_lib
         
     | 
| 
       185 
201 
     | 
    
         | 
| 
         @@ -188,12 +204,10 @@ namespace :parallel do 
     | 
|
| 
       188 
204 
     | 
    
         
             
                    'spec' => 'rspec',
         
     | 
| 
       189 
205 
     | 
    
         
             
                    'test' => 'test',
         
     | 
| 
       190 
206 
     | 
    
         
             
                    'features' => 'cucumber',
         
     | 
| 
       191 
     | 
    
         
            -
                    'features-spinach' => 'spinach' 
     | 
| 
      
 207 
     | 
    
         
            +
                    'features-spinach' => 'spinach'
         
     | 
| 
       192 
208 
     | 
    
         
             
                  }[type]
         
     | 
| 
       193 
209 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
                  if test_framework == 'spinach'
         
     | 
| 
       195 
     | 
    
         
            -
                    type = 'features'
         
     | 
| 
       196 
     | 
    
         
            -
                  end
         
     | 
| 
      
 210 
     | 
    
         
            +
                  type = 'features' if test_framework == 'spinach'
         
     | 
| 
       197 
211 
     | 
    
         
             
                  # Using the relative path to find the binary allow to run a specific version of it
         
     | 
| 
       198 
212 
     | 
    
         
             
                  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
         
     | 
| 
       199 
213 
     | 
    
         | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'parallel_tests'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
         @@ -32,7 +33,7 @@ module ParallelTests 
     | 
|
| 
       32 
33 
     | 
    
         
             
                    # --- usually used by other runners
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         
             
                    # finds all tests and partitions them into groups
         
     | 
| 
       35 
     | 
    
         
            -
                    def tests_in_groups(tests, num_groups, options={})
         
     | 
| 
      
 36 
     | 
    
         
            +
                    def tests_in_groups(tests, num_groups, options = {})
         
     | 
| 
       36 
37 
     | 
    
         
             
                      tests = tests_with_size(tests, options)
         
     | 
| 
       37 
38 
     | 
    
         
             
                      Grouper.in_even_groups_by_size(tests, num_groups, options)
         
     | 
| 
       38 
39 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -46,10 +47,17 @@ module ParallelTests 
     | 
|
| 
       46 
47 
     | 
    
         
             
                      when :filesize
         
     | 
| 
       47 
48 
     | 
    
         
             
                        sort_by_filesize(tests)
         
     | 
| 
       48 
49 
     | 
    
         
             
                      when :runtime
         
     | 
| 
       49 
     | 
    
         
            -
                        sort_by_runtime( 
     | 
| 
      
 50 
     | 
    
         
            +
                        sort_by_runtime(
         
     | 
| 
      
 51 
     | 
    
         
            +
                          tests, runtimes(tests, options),
         
     | 
| 
      
 52 
     | 
    
         
            +
                          options.merge(allowed_missing: (options[:allowed_missing_percent] || 50) / 100.0)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        )
         
     | 
| 
       50 
54 
     | 
    
         
             
                      when nil
         
     | 
| 
       51 
55 
     | 
    
         
             
                        # use recorded test runtime if we got enough data
         
     | 
| 
       52 
     | 
    
         
            -
                        runtimes =  
     | 
| 
      
 56 
     | 
    
         
            +
                        runtimes = begin
         
     | 
| 
      
 57 
     | 
    
         
            +
                          runtimes(tests, options)
         
     | 
| 
      
 58 
     | 
    
         
            +
                        rescue StandardError
         
     | 
| 
      
 59 
     | 
    
         
            +
                          []
         
     | 
| 
      
 60 
     | 
    
         
            +
                        end
         
     | 
| 
       53 
61 
     | 
    
         
             
                        if runtimes.size * 1.5 > tests.size
         
     | 
| 
       54 
62 
     | 
    
         
             
                          puts "Using recorded test runtime"
         
     | 
| 
       55 
63 
     | 
    
         
             
                          sort_by_runtime(tests, runtimes)
         
     | 
| 
         @@ -67,7 +75,7 @@ module ParallelTests 
     | 
|
| 
       67 
75 
     | 
    
         
             
                      env = (options[:env] || {}).merge(
         
     | 
| 
       68 
76 
     | 
    
         
             
                        "TEST_ENV_NUMBER" => test_env_number(process_number, options).to_s,
         
     | 
| 
       69 
77 
     | 
    
         
             
                        "PARALLEL_TEST_GROUPS" => num_processes.to_s,
         
     | 
| 
       70 
     | 
    
         
            -
                        "PARALLEL_PID_FILE" => ParallelTests.pid_file_path 
     | 
| 
      
 78 
     | 
    
         
            +
                        "PARALLEL_PID_FILE" => ParallelTests.pid_file_path
         
     | 
| 
       71 
79 
     | 
    
         
             
                      )
         
     | 
| 
       72 
80 
     | 
    
         
             
                      cmd = "nice #{cmd}" if options[:nice]
         
     | 
| 
       73 
81 
     | 
    
         
             
                      cmd = "#{cmd} 2>&1" if options[:combine_stderr]
         
     | 
| 
         @@ -86,13 +94,11 @@ module ParallelTests 
     | 
|
| 
       86 
94 
     | 
    
         
             
                      end
         
     | 
| 
       87 
95 
     | 
    
         
             
                      ParallelTests.pids.delete(pid) if pid
         
     | 
| 
       88 
96 
     | 
    
         
             
                      exitstatus = $?.exitstatus
         
     | 
| 
       89 
     | 
    
         
            -
                      seed = output[/seed (\d+)/,1]
         
     | 
| 
      
 97 
     | 
    
         
            +
                      seed = output[/seed (\d+)/, 1]
         
     | 
| 
       90 
98 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
                      if report_process_command?(options) && options[:serialize_stdout]
         
     | 
| 
       92 
     | 
    
         
            -
                        output = [cmd, output].join("\n")
         
     | 
| 
       93 
     | 
    
         
            -
                      end
         
     | 
| 
      
 99 
     | 
    
         
            +
                      output = [cmd, output].join("\n") if report_process_command?(options) && options[:serialize_stdout]
         
     | 
| 
       94 
100 
     | 
    
         | 
| 
       95 
     | 
    
         
            -
                      {: 
     | 
| 
      
 101 
     | 
    
         
            +
                      { stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
         
     | 
| 
       96 
102 
     | 
    
         
             
                    end
         
     | 
| 
       97 
103 
     | 
    
         | 
| 
       98 
104 
     | 
    
         
             
                    def find_results(test_output)
         
     | 
| 
         @@ -104,7 +110,7 @@ module ParallelTests 
     | 
|
| 
       104 
110 
     | 
    
         
             
                      end.compact
         
     | 
| 
       105 
111 
     | 
    
         
             
                    end
         
     | 
| 
       106 
112 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                    def test_env_number(process_number, options={})
         
     | 
| 
      
 113 
     | 
    
         
            +
                    def test_env_number(process_number, options = {})
         
     | 
| 
       108 
114 
     | 
    
         
             
                      if process_number == 0 && !options[:first_is_1]
         
     | 
| 
       109 
115 
     | 
    
         
             
                        ''
         
     | 
| 
       110 
116 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -114,7 +120,7 @@ module ParallelTests 
     | 
|
| 
       114 
120 
     | 
    
         | 
| 
       115 
121 
     | 
    
         
             
                    def summarize_results(results)
         
     | 
| 
       116 
122 
     | 
    
         
             
                      sums = sum_up_results(results)
         
     | 
| 
       117 
     | 
    
         
            -
                      sums.sort.map{|word, number| 
     | 
| 
      
 123 
     | 
    
         
            +
                      sums.sort.map { |word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ')
         
     | 
| 
       118 
124 
     | 
    
         
             
                    end
         
     | 
| 
       119 
125 
     | 
    
         | 
| 
       120 
126 
     | 
    
         
             
                    # remove old seed and add new seed
         
     | 
| 
         @@ -134,19 +140,18 @@ module ParallelTests 
     | 
|
| 
       134 
140 
     | 
    
         
             
                    end
         
     | 
| 
       135 
141 
     | 
    
         | 
| 
       136 
142 
     | 
    
         
             
                    def sum_up_results(results)
         
     | 
| 
       137 
     | 
    
         
            -
                      results = results.join(' ').gsub(/s\b/,'') # combine and singularize results
         
     | 
| 
      
 143 
     | 
    
         
            +
                      results = results.join(' ').gsub(/s\b/, '') # combine and singularize results
         
     | 
| 
       138 
144 
     | 
    
         
             
                      counts = results.scan(/(\d+) (\w+)/)
         
     | 
| 
       139 
     | 
    
         
            -
                      counts. 
     | 
| 
      
 145 
     | 
    
         
            +
                      counts.each_with_object(Hash.new(0)) do |(number, word), sum|
         
     | 
| 
       140 
146 
     | 
    
         
             
                        sum[word] += number.to_i
         
     | 
| 
       141 
     | 
    
         
            -
                        sum
         
     | 
| 
       142 
147 
     | 
    
         
             
                      end
         
     | 
| 
       143 
148 
     | 
    
         
             
                    end
         
     | 
| 
       144 
149 
     | 
    
         | 
| 
       145 
150 
     | 
    
         
             
                    # read output of the process and print it in chunks
         
     | 
| 
       146 
     | 
    
         
            -
                    def capture_output(out, env, options={})
         
     | 
| 
       147 
     | 
    
         
            -
                      result = ""
         
     | 
| 
       148 
     | 
    
         
            -
                       
     | 
| 
       149 
     | 
    
         
            -
                         
     | 
| 
      
 151 
     | 
    
         
            +
                    def capture_output(out, env, options = {})
         
     | 
| 
      
 152 
     | 
    
         
            +
                      result = +""
         
     | 
| 
      
 153 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 154 
     | 
    
         
            +
                        loop do
         
     | 
| 
       150 
155 
     | 
    
         
             
                          read = out.readpartial(1000000) # read whatever chunk we can get
         
     | 
| 
       151 
156 
     | 
    
         
             
                          if Encoding.default_internal
         
     | 
| 
       152 
157 
     | 
    
         
             
                            read = read.force_encoding(Encoding.default_internal)
         
     | 
| 
         @@ -159,11 +164,13 @@ module ParallelTests 
     | 
|
| 
       159 
164 
     | 
    
         
             
                            $stdout.flush
         
     | 
| 
       160 
165 
     | 
    
         
             
                          end
         
     | 
| 
       161 
166 
     | 
    
         
             
                        end
         
     | 
| 
       162 
     | 
    
         
            -
                       
     | 
| 
      
 167 
     | 
    
         
            +
                      rescue EOFError
         
     | 
| 
      
 168 
     | 
    
         
            +
                        nil
         
     | 
| 
      
 169 
     | 
    
         
            +
                      end
         
     | 
| 
       163 
170 
     | 
    
         
             
                      result
         
     | 
| 
       164 
171 
     | 
    
         
             
                    end
         
     | 
| 
       165 
172 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
                    def sort_by_runtime(tests, runtimes, options={})
         
     | 
| 
      
 173 
     | 
    
         
            +
                    def sort_by_runtime(tests, runtimes, options = {})
         
     | 
| 
       167 
174 
     | 
    
         
             
                      allowed_missing = options[:allowed_missing] || 1.0
         
     | 
| 
       168 
175 
     | 
    
         
             
                      allowed_missing = tests.size * allowed_missing
         
     | 
| 
       169 
176 
     | 
    
         | 
| 
         @@ -178,9 +185,7 @@ module ParallelTests 
     | 
|
| 
       178 
185 
     | 
    
         
             
                        [test, time]
         
     | 
| 
       179 
186 
     | 
    
         
             
                      end
         
     | 
| 
       180 
187 
     | 
    
         | 
| 
       181 
     | 
    
         
            -
                      if options[:verbose]
         
     | 
| 
       182 
     | 
    
         
            -
                        puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests"
         
     | 
| 
       183 
     | 
    
         
            -
                      end
         
     | 
| 
      
 188 
     | 
    
         
            +
                      puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests" if options[:verbose]
         
     | 
| 
       184 
189 
     | 
    
         | 
| 
       185 
190 
     | 
    
         
             
                      set_unknown_runtime tests, options
         
     | 
| 
       186 
191 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -190,7 +195,7 @@ module ParallelTests 
     | 
|
| 
       190 
195 
     | 
    
         
             
                      lines = File.read(log).split("\n")
         
     | 
| 
       191 
196 
     | 
    
         
             
                      lines.each_with_object({}) do |line, times|
         
     | 
| 
       192 
197 
     | 
    
         
             
                        test, _, time = line.rpartition(':')
         
     | 
| 
       193 
     | 
    
         
            -
                        next unless test  
     | 
| 
      
 198 
     | 
    
         
            +
                        next unless test && time
         
     | 
| 
       194 
199 
     | 
    
         
             
                        times[test] = time.to_f if tests.include?(test)
         
     | 
| 
       195 
200 
     | 
    
         
             
                      end
         
     | 
| 
       196 
201 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -217,7 +222,7 @@ module ParallelTests 
     | 
|
| 
       217 
222 
     | 
    
         
             
                      end.uniq
         
     | 
| 
       218 
223 
     | 
    
         
             
                    end
         
     | 
| 
       219 
224 
     | 
    
         | 
| 
       220 
     | 
    
         
            -
                    def files_in_folder(folder, options={})
         
     | 
| 
      
 225 
     | 
    
         
            +
                    def files_in_folder(folder, options = {})
         
     | 
| 
       221 
226 
     | 
    
         
             
                      pattern = if options[:symlinks] == false # not nil or true
         
     | 
| 
       222 
227 
     | 
    
         
             
                        "**/*"
         
     | 
| 
       223 
228 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -225,7 +230,7 @@ module ParallelTests 
     | 
|
| 
       225 
230 
     | 
    
         
             
                        # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
         
     | 
| 
       226 
231 
     | 
    
         
             
                        "**{,/*/**}/*"
         
     | 
| 
       227 
232 
     | 
    
         
             
                      end
         
     | 
| 
       228 
     | 
    
         
            -
                      Dir[File.join(folder, pattern)].uniq
         
     | 
| 
      
 233 
     | 
    
         
            +
                      Dir[File.join(folder, pattern)].uniq.sort
         
     | 
| 
       229 
234 
     | 
    
         
             
                    end
         
     | 
| 
       230 
235 
     | 
    
         | 
| 
       231 
236 
     | 
    
         
             
                    private
         
     | 
| 
         @@ -236,7 +241,7 @@ module ParallelTests 
     | 
|
| 
       236 
241 
     | 
    
         
             
                      known, unknown = tests.partition(&:last)
         
     | 
| 
       237 
242 
     | 
    
         
             
                      return if unknown.empty?
         
     | 
| 
       238 
243 
     | 
    
         
             
                      unknown_runtime = options[:unknown_runtime] ||
         
     | 
| 
       239 
     | 
    
         
            -
                        (known.empty? ? 1 : known.map!(&:last). 
     | 
| 
      
 244 
     | 
    
         
            +
                        (known.empty? ? 1 : known.map!(&:last).sum / known.size) # average
         
     | 
| 
       240 
245 
     | 
    
         
             
                      unknown.each { |set| set[1] = unknown_runtime }
         
     | 
| 
       241 
246 
     | 
    
         
             
                    end
         
     | 
| 
       242 
247 
     | 
    
         |