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
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1d0652212f051b70b99ae872c05fb5ab37fbd5a13270d2158820555cd472a689
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 29c4e9cfbc3268880ce9ead6033e853588806503b0cc1bdfaf427ba6cd31b237
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: b8cbab7441e101617611cb37908656c416d9901b4ca02cf85920de646b1c0e750e6c37ae4690be7ae8d4c79640db2e7505bcbd331d0c3072a1e60e1f0ff5b462
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 635508aa6168d0b7e58e8e932d61b079bc25135339c1adf4121707d4849cc9cedfc1acc134dce586112eac23f5e04f6083aeb133ccfb7505a42ea754ecc5f5ae
         
     | 
    
        data/Readme.md
    CHANGED
    
    | 
         @@ -37,6 +37,9 @@ test: 
     | 
|
| 
       37 
37 
     | 
    
         
             
            ### Copy development schema (repeat after migrations)
         
     | 
| 
       38 
38 
     | 
    
         
             
                rake parallel:prepare
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
            ### Run migrations in additional database(s) (repeat after migrations)
         
     | 
| 
      
 41 
     | 
    
         
            +
                rake parallel:migrate
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
       40 
43 
     | 
    
         
             
            ### Setup environment from scratch (create db and loads schema, useful for CI)
         
     | 
| 
       41 
44 
     | 
    
         
             
                rake parallel:setup
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
         @@ -142,17 +145,19 @@ Add the following to your `.rspec_parallel` (or `.rspec`) : 
     | 
|
| 
       142 
145 
     | 
    
         
             
            RSpec: FailuresLogger
         
     | 
| 
       143 
146 
     | 
    
         
             
            -----------------------
         
     | 
| 
       144 
147 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
            Produce  
     | 
| 
      
 148 
     | 
    
         
            +
            Produce pastable command-line snippets for each failed example. For example:
         
     | 
| 
       146 
149 
     | 
    
         | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
      
 150 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 151 
     | 
    
         
            +
            rspec /path/to/my_spec.rb:123 # should do something
         
     | 
| 
      
 152 
     | 
    
         
            +
            ```
         
     | 
| 
       148 
153 
     | 
    
         | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
            Add the following to your `.rspec_parallel` (or `.rspec`) :
         
     | 
| 
      
 154 
     | 
    
         
            +
            Add to `.rspec_parallel` or use as CLI flag:
         
     | 
| 
       152 
155 
     | 
    
         | 
| 
       153 
156 
     | 
    
         
             
                --format progress
         
     | 
| 
       154 
157 
     | 
    
         
             
                --format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
         
     | 
| 
       155 
158 
     | 
    
         | 
| 
      
 159 
     | 
    
         
            +
            (Not needed to retry failures, for that pass [--only-failures](https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures) to rspec)
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
       156 
161 
     | 
    
         
             
            Cucumber: FailuresLogger
         
     | 
| 
       157 
162 
     | 
    
         
             
            -----------------------
         
     | 
| 
       158 
163 
     | 
    
         | 
| 
         @@ -205,8 +210,19 @@ Options are: 
     | 
|
| 
       205 
210 
     | 
    
         
             
                      default - runtime when runtime log is filled otherwise filesize
         
     | 
| 
       206 
211 
     | 
    
         
             
                -m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
         
     | 
| 
       207 
212 
     | 
    
         
             
                -s, --single [PATTERN]           Run all matching files in the same process
         
     | 
| 
       208 
     | 
    
         
            -
                -i, --isolate                    Do not run any other tests in the group used by --single(-s)
         
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
      
 213 
     | 
    
         
            +
                -i, --isolate                    Do not run any other tests in the group used by --single(-s).
         
     | 
| 
      
 214 
     | 
    
         
            +
                                                 Automatically turned on if --isolate-n is set above 0.
         
     | 
| 
      
 215 
     | 
    
         
            +
                    --isolate-n                  Number of processes for isolated groups. Default to 1 when --isolate is on.
         
     | 
| 
      
 216 
     | 
    
         
            +
                    --specify-groups [SPECS]     Use 'specify-groups' if you want to specify multiple specs running in multiple
         
     | 
| 
      
 217 
     | 
    
         
            +
                                                 processes in a specific formation. Commas indicate specs in the same process,
         
     | 
| 
      
 218 
     | 
    
         
            +
                                                 pipes indicate specs in a new process.  Cannot use with --single, --isolate, or
         
     | 
| 
      
 219 
     | 
    
         
            +
                                                 --isolate-n.  Ex.
         
     | 
| 
      
 220 
     | 
    
         
            +
                                                 Ex.
         
     | 
| 
      
 221 
     | 
    
         
            +
                                                 $ parallel_tests -n 3 . --specify-groups '1_spec.rb,2_spec.rb|3_spec.rb'
         
     | 
| 
      
 222 
     | 
    
         
            +
                                                   Process 1 will contain 1_spec.rb and 2_spec.rb
         
     | 
| 
      
 223 
     | 
    
         
            +
                                                   Process 2 will contain 3_spec.rb
         
     | 
| 
      
 224 
     | 
    
         
            +
                                                   Process 3 will contain all other specs
         
     | 
| 
      
 225 
     | 
    
         
            +
                    --only-group INT[,INT]
         
     | 
| 
       210 
226 
     | 
    
         
             
                -e, --exec [COMMAND]             execute this code parallel and with ENV['TEST_ENV_NUMBER']
         
     | 
| 
       211 
227 
     | 
    
         
             
                -o, --test-options '[OPTIONS]'   execute test commands with those options
         
     | 
| 
       212 
228 
     | 
    
         
             
                -t, --type [TYPE]                test(default) / rspec / cucumber / spinach
         
     | 
| 
         @@ -280,7 +296,7 @@ TIPS 
     | 
|
| 
       280 
296 
     | 
    
         
             
               `export PARALLEL_TEST_FIRST_IS_1=true` will provide the same result
         
     | 
| 
       281 
297 
     | 
    
         
             
             - [email_spec and/or action_mailer_cache_delivery](https://github.com/grosser/parallel_tests/wiki)
         
     | 
| 
       282 
298 
     | 
    
         
             
             - [zeus-parallel_tests](https://github.com/sevos/zeus-parallel_tests)
         
     | 
| 
       283 
     | 
    
         
            -
             - [Distributed  
     | 
| 
      
 299 
     | 
    
         
            +
             - [Distributed Parallel Tests on CI systems)](https://github.com/grosser/parallel_tests/wiki/Distributed-Parallel-Tests-on-CI-systems) learn how `parallel_tests` can run on distributed servers such as Travis and GitLab-CI. Also shows you how to use parallel_tests without adding `TEST_ENV_NUMBER`-backends
         
     | 
| 
       284 
300 
     | 
    
         
             
             - [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
         
     | 
| 
       285 
301 
     | 
    
         
             
             - [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
         
     | 
| 
       286 
302 
     | 
    
         
             
             - [Capistrano setup](https://github.com/grosser/parallel_tests/wiki/Remotely-with-capistrano) let your tests run on a big box instead of your laptop
         
     | 
| 
         @@ -376,6 +392,8 @@ inspired by [pivotal labs](https://blog.pivotal.io/labs/labs/parallelize-your-rs 
     | 
|
| 
       376 
392 
     | 
    
         
             
             - [Calaway](https://github.com/calaway)
         
     | 
| 
       377 
393 
     | 
    
         
             
             - [alboyadjian](https://github.com/alboyadjian)
         
     | 
| 
       378 
394 
     | 
    
         
             
             - [Nathan Broadbent](https://github.com/ndbroadbent)
         
     | 
| 
      
 395 
     | 
    
         
            +
             - [Vikram B Kumar](https://github.com/v-kumar)
         
     | 
| 
      
 396 
     | 
    
         
            +
             - [Joshua Pinter](https://github.com/joshuapinter)
         
     | 
| 
       379 
397 
     | 
    
         | 
| 
       380 
398 
     | 
    
         
             
            [Michael Grosser](http://grosser.it)<br/>
         
     | 
| 
       381 
399 
     | 
    
         
             
            michael@grosser.it<br/>
         
     | 
    
        data/bin/parallel_cucumber
    CHANGED
    
    | 
         @@ -1,7 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            # enable local usage from cloned repo
         
     | 
| 
       4 
     | 
    
         
            -
            root = File.expand_path( 
     | 
| 
      
 5 
     | 
    
         
            +
            root = File.expand_path('..', __dir__)
         
     | 
| 
       5 
6 
     | 
    
         
             
            $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            require "parallel_tests"
         
     | 
    
        data/bin/parallel_rspec
    CHANGED
    
    | 
         @@ -1,7 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            # enable local usage from cloned repo
         
     | 
| 
       4 
     | 
    
         
            -
            root = File.expand_path( 
     | 
| 
      
 5 
     | 
    
         
            +
            root = File.expand_path('..', __dir__)
         
     | 
| 
       5 
6 
     | 
    
         
             
            $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            require "parallel_tests"
         
     | 
    
        data/bin/parallel_spinach
    CHANGED
    
    | 
         @@ -1,7 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            # enable local usage from cloned repo
         
     | 
| 
       4 
     | 
    
         
            -
            root = File.expand_path( 
     | 
| 
      
 5 
     | 
    
         
            +
            root = File.expand_path('..', __dir__)
         
     | 
| 
       5 
6 
     | 
    
         
             
            $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            require "parallel_tests"
         
     | 
    
        data/bin/parallel_test
    CHANGED
    
    | 
         @@ -1,7 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            # enable local usage from cloned repo
         
     | 
| 
       4 
     | 
    
         
            -
            root = File.expand_path( 
     | 
| 
      
 5 
     | 
    
         
            +
            root = File.expand_path('..', __dir__)
         
     | 
| 
       5 
6 
     | 
    
         
             
            $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            require "parallel_tests"
         
     | 
    
        data/lib/parallel_tests.rb
    CHANGED
    
    | 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require "parallel"
         
     | 
| 
       2 
3 
     | 
    
         
             
            require "parallel_tests/railtie" if defined? Rails::Railtie
         
     | 
| 
       3 
4 
     | 
    
         
             
            require "rbconfig"
         
     | 
| 
         @@ -17,7 +18,7 @@ module ParallelTests 
     | 
|
| 
       17 
18 
     | 
    
         
             
                    count,
         
     | 
| 
       18 
19 
     | 
    
         
             
                    ENV["PARALLEL_TEST_PROCESSORS"],
         
     | 
| 
       19 
20 
     | 
    
         
             
                    Parallel.processor_count
         
     | 
| 
       20 
     | 
    
         
            -
                  ].detect{|c|  
     | 
| 
      
 21 
     | 
    
         
            +
                  ].detect { |c| !c.to_s.strip.empty? }.to_i
         
     | 
| 
       21 
22 
     | 
    
         
             
                end
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
                def with_pid_file
         
     | 
| 
         @@ -57,7 +58,8 @@ module ParallelTests 
     | 
|
| 
       57 
58 
     | 
    
         
             
                  until !File.directory?(current) || current == previous
         
     | 
| 
       58 
59 
     | 
    
         
             
                    filename = File.join(current, "Gemfile")
         
     | 
| 
       59 
60 
     | 
    
         
             
                    return true if File.exist?(filename)
         
     | 
| 
       60 
     | 
    
         
            -
                     
     | 
| 
      
 61 
     | 
    
         
            +
                    previous = current
         
     | 
| 
      
 62 
     | 
    
         
            +
                    current = File.expand_path("..", current)
         
     | 
| 
       61 
63 
     | 
    
         
             
                  end
         
     | 
| 
       62 
64 
     | 
    
         | 
| 
       63 
65 
     | 
    
         
             
                  false
         
     | 
    
        data/lib/parallel_tests/cli.rb
    CHANGED
    
    | 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'optparse'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'tempfile'
         
     | 
| 
       3 
4 
     | 
    
         
             
            require 'parallel_tests'
         
     | 
| 
         @@ -14,7 +15,7 @@ module ParallelTests 
     | 
|
| 
       14 
15 
     | 
    
         
             
                  ENV['DISABLE_SPRING'] ||= '1'
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
                  num_processes = ParallelTests.determine_number_of_processes(options[:count])
         
     | 
| 
       17 
     | 
    
         
            -
                  num_processes  
     | 
| 
      
 18 
     | 
    
         
            +
                  num_processes *= (options[:multiply] || 1)
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                  options[:first_is_1] ||= first_is_1?
         
     | 
| 
       20 
21 
     | 
    
         | 
| 
         @@ -56,12 +57,12 @@ module ParallelTests 
     | 
|
| 
       56 
57 
     | 
    
         
             
                def run_tests_in_parallel(num_processes, options)
         
     | 
| 
       57 
58 
     | 
    
         
             
                  test_results = nil
         
     | 
| 
       58 
59 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                  run_tests_proc = ->  
     | 
| 
      
 60 
     | 
    
         
            +
                  run_tests_proc = -> do
         
     | 
| 
       60 
61 
     | 
    
         
             
                    groups = @runner.tests_in_groups(options[:files], num_processes, options)
         
     | 
| 
       61 
     | 
    
         
            -
                    groups.reject! 
     | 
| 
      
 62 
     | 
    
         
            +
                    groups.reject!(&:empty?)
         
     | 
| 
       62 
63 
     | 
    
         | 
| 
       63 
64 
     | 
    
         
             
                    test_results = if options[:only_group]
         
     | 
| 
       64 
     | 
    
         
            -
                      groups_to_run = options[:only_group]. 
     | 
| 
      
 65 
     | 
    
         
            +
                      groups_to_run = options[:only_group].map { |i| groups[i - 1] }.compact
         
     | 
| 
       65 
66 
     | 
    
         
             
                      report_number_of_tests(groups_to_run) unless options[:quiet]
         
     | 
| 
       66 
67 
     | 
    
         
             
                      execute_in_parallel(groups_to_run, groups_to_run.size, options) do |group|
         
     | 
| 
       67 
68 
     | 
    
         
             
                        run_tests(group, groups_to_run.index(group), 1, options)
         
     | 
| 
         @@ -75,7 +76,7 @@ module ParallelTests 
     | 
|
| 
       75 
76 
     | 
    
         
             
                    end
         
     | 
| 
       76 
77 
     | 
    
         | 
| 
       77 
78 
     | 
    
         
             
                    report_results(test_results, options) unless options[:quiet]
         
     | 
| 
       78 
     | 
    
         
            -
                   
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
       79 
80 
     | 
    
         | 
| 
       80 
81 
     | 
    
         
             
                  if options[:quiet]
         
     | 
| 
       81 
82 
     | 
    
         
             
                    run_tests_proc.call
         
     | 
| 
         @@ -88,7 +89,7 @@ module ParallelTests 
     | 
|
| 
       88 
89 
     | 
    
         | 
| 
       89 
90 
     | 
    
         
             
                def run_tests(group, process_number, num_processes, options)
         
     | 
| 
       90 
91 
     | 
    
         
             
                  if group.empty?
         
     | 
| 
       91 
     | 
    
         
            -
                    {: 
     | 
| 
      
 92 
     | 
    
         
            +
                    { stdout: '', exit_status: 0, command: '', seed: nil }
         
     | 
| 
       92 
93 
     | 
    
         
             
                  else
         
     | 
| 
       93 
94 
     | 
    
         
             
                    @runner.run_tests(group, process_number, num_processes, options)
         
     | 
| 
       94 
95 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -115,7 +116,7 @@ module ParallelTests 
     | 
|
| 
       115 
116 
     | 
    
         
             
                end
         
     | 
| 
       116 
117 
     | 
    
         | 
| 
       117 
118 
     | 
    
         
             
                def report_results(test_results, options)
         
     | 
| 
       118 
     | 
    
         
            -
                  results = @runner.find_results(test_results.map { |result| result[:stdout] }*"")
         
     | 
| 
      
 119 
     | 
    
         
            +
                  results = @runner.find_results(test_results.map { |result| result[:stdout] } * "")
         
     | 
| 
       119 
120 
     | 
    
         
             
                  puts ""
         
     | 
| 
       120 
121 
     | 
    
         
             
                  puts @runner.summarize_results(results)
         
     | 
| 
       121 
122 
     | 
    
         | 
| 
         @@ -140,20 +141,31 @@ module ParallelTests 
     | 
|
| 
       140 
141 
     | 
    
         
             
                def report_number_of_tests(groups)
         
     | 
| 
       141 
142 
     | 
    
         
             
                  name = @runner.test_file_name
         
     | 
| 
       142 
143 
     | 
    
         
             
                  num_processes = groups.size
         
     | 
| 
       143 
     | 
    
         
            -
                  num_tests = groups.map(&:size). 
     | 
| 
      
 144 
     | 
    
         
            +
                  num_tests = groups.map(&:size).sum
         
     | 
| 
       144 
145 
     | 
    
         
             
                  tests_per_process = (num_processes == 0 ? 0 : num_tests / num_processes)
         
     | 
| 
       145 
     | 
    
         
            -
                  puts "#{num_processes}  
     | 
| 
      
 146 
     | 
    
         
            +
                  puts "#{pluralize(num_processes, 'process')} for #{pluralize(num_tests, name)}, ~ #{pluralize(tests_per_process, name)} per process"
         
     | 
| 
      
 147 
     | 
    
         
            +
                end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                def pluralize(n, singular)
         
     | 
| 
      
 150 
     | 
    
         
            +
                  if n == 1
         
     | 
| 
      
 151 
     | 
    
         
            +
                    "1 #{singular}"
         
     | 
| 
      
 152 
     | 
    
         
            +
                  elsif singular.end_with?('s', 'sh', 'ch', 'x', 'z')
         
     | 
| 
      
 153 
     | 
    
         
            +
                    "#{n} #{singular}es"
         
     | 
| 
      
 154 
     | 
    
         
            +
                  else
         
     | 
| 
      
 155 
     | 
    
         
            +
                    "#{n} #{singular}s"
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
       146 
157 
     | 
    
         
             
                end
         
     | 
| 
       147 
158 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
                #exit with correct status code so rake parallel:test && echo 123 works
         
     | 
| 
      
 159 
     | 
    
         
            +
                # exit with correct status code so rake parallel:test && echo 123 works
         
     | 
| 
       149 
160 
     | 
    
         
             
                def any_test_failed?(test_results)
         
     | 
| 
       150 
161 
     | 
    
         
             
                  test_results.any? { |result| result[:exit_status] != 0 }
         
     | 
| 
       151 
162 
     | 
    
         
             
                end
         
     | 
| 
       152 
163 
     | 
    
         | 
| 
       153 
164 
     | 
    
         
             
                def parse_options!(argv)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  newline_padding = " " * 37
         
     | 
| 
       154 
166 
     | 
    
         
             
                  options = {}
         
     | 
| 
       155 
167 
     | 
    
         
             
                  OptionParser.new do |opts|
         
     | 
| 
       156 
     | 
    
         
            -
                    opts.banner =  
     | 
| 
      
 168 
     | 
    
         
            +
                    opts.banner = <<~BANNER
         
     | 
| 
       157 
169 
     | 
    
         
             
                      Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
         
     | 
| 
       158 
170 
     | 
    
         | 
| 
       159 
171 
     | 
    
         
             
                      [optional] Only selected files & folders:
         
     | 
| 
         @@ -167,32 +179,51 @@ module ParallelTests 
     | 
|
| 
       167 
179 
     | 
    
         
             
                    opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
         
     | 
| 
       168 
180 
     | 
    
         
             
                    opts.on("-p", "--pattern [PATTERN]", "run tests matching this regex pattern") { |pattern| options[:pattern] = /#{pattern}/ }
         
     | 
| 
       169 
181 
     | 
    
         
             
                    opts.on("--exclude-pattern", "--exclude-pattern [PATTERN]", "exclude tests matching this regex pattern") { |pattern| options[:exclude_pattern] = /#{pattern}/ }
         
     | 
| 
       170 
     | 
    
         
            -
                    opts.on( 
     | 
| 
       171 
     | 
    
         
            -
                      group  
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
             
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
      
 182 
     | 
    
         
            +
                    opts.on(
         
     | 
| 
      
 183 
     | 
    
         
            +
                      "--group-by [TYPE]",
         
     | 
| 
      
 184 
     | 
    
         
            +
                      <<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
         
     | 
| 
      
 185 
     | 
    
         
            +
                        group tests by:
         
     | 
| 
      
 186 
     | 
    
         
            +
                        found - order of finding files
         
     | 
| 
      
 187 
     | 
    
         
            +
                        steps - number of cucumber/spinach steps
         
     | 
| 
      
 188 
     | 
    
         
            +
                        scenarios - individual cucumber scenarios
         
     | 
| 
      
 189 
     | 
    
         
            +
                        filesize - by size of the file
         
     | 
| 
      
 190 
     | 
    
         
            +
                        runtime - info from runtime log
         
     | 
| 
      
 191 
     | 
    
         
            +
                        default - runtime when runtime log is filled otherwise filesize
         
     | 
| 
       178 
192 
     | 
    
         
             
                      TEXT
         
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
                    opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run")  
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
                    opts.on("-s [PATTERN]", "--single [PATTERN]",
         
     | 
| 
       183 
     | 
    
         
            -
                      "Run all matching files in the same process") do |pattern|
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
                      options[:single_process] ||= []
         
     | 
| 
       186 
     | 
    
         
            -
                      options[:single_process] << /#{pattern}/
         
     | 
| 
      
 193 
     | 
    
         
            +
                    ) { |type| options[:group_by] = type.to_sym }
         
     | 
| 
      
 194 
     | 
    
         
            +
                    opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") do |multiply|
         
     | 
| 
      
 195 
     | 
    
         
            +
                      options[:multiply] = multiply
         
     | 
| 
       187 
196 
     | 
    
         
             
                    end
         
     | 
| 
       188 
197 
     | 
    
         | 
| 
       189 
     | 
    
         
            -
                    opts.on("- 
     | 
| 
       190 
     | 
    
         
            -
                       
     | 
| 
      
 198 
     | 
    
         
            +
                    opts.on("-s [PATTERN]", "--single [PATTERN]", "Run all matching files in the same process") do |pattern|
         
     | 
| 
      
 199 
     | 
    
         
            +
                      (options[:single_process] ||= []) << /#{pattern}/
         
     | 
| 
      
 200 
     | 
    
         
            +
                    end
         
     | 
| 
       191 
201 
     | 
    
         | 
| 
      
 202 
     | 
    
         
            +
                    opts.on("-i", "--isolate", "Do not run any other tests in the group used by --single(-s)") do
         
     | 
| 
       192 
203 
     | 
    
         
             
                      options[:isolate] = true
         
     | 
| 
       193 
204 
     | 
    
         
             
                    end
         
     | 
| 
       194 
205 
     | 
    
         | 
| 
       195 
     | 
    
         
            -
                    opts.on( 
     | 
| 
      
 206 
     | 
    
         
            +
                    opts.on(
         
     | 
| 
      
 207 
     | 
    
         
            +
                      "--isolate-n [PROCESSES]",
         
     | 
| 
      
 208 
     | 
    
         
            +
                      Integer,
         
     | 
| 
      
 209 
     | 
    
         
            +
                      "Use 'isolate'  singles with number of processes, default: 1."
         
     | 
| 
      
 210 
     | 
    
         
            +
                    ) { |n| options[:isolate_count] = n }
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                    opts.on(
         
     | 
| 
      
 213 
     | 
    
         
            +
                      "--specify-groups [SPECS]",
         
     | 
| 
      
 214 
     | 
    
         
            +
                      <<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
         
     | 
| 
      
 215 
     | 
    
         
            +
                        Use 'specify-groups' if you want to specify multiple specs running in multiple
         
     | 
| 
      
 216 
     | 
    
         
            +
                        processes in a specific formation. Commas indicate specs in the same process,
         
     | 
| 
      
 217 
     | 
    
         
            +
                        pipes indicate specs in a new process. Cannot use with --single, --isolate, or
         
     | 
| 
      
 218 
     | 
    
         
            +
                        --isolate-n.  Ex.
         
     | 
| 
      
 219 
     | 
    
         
            +
                        $ parallel_tests -n 3 . --specify-groups '1_spec.rb,2_spec.rb|3_spec.rb'
         
     | 
| 
      
 220 
     | 
    
         
            +
                          Process 1 will contain 1_spec.rb and 2_spec.rb
         
     | 
| 
      
 221 
     | 
    
         
            +
                          Process 2 will contain 3_spec.rb
         
     | 
| 
      
 222 
     | 
    
         
            +
                          Process 3 will contain all other specs
         
     | 
| 
      
 223 
     | 
    
         
            +
                      TEXT
         
     | 
| 
      
 224 
     | 
    
         
            +
                    ) { |groups| options[:specify_groups] = groups }
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                    opts.on("--only-group INT[,INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
         
     | 
| 
       196 
227 
     | 
    
         | 
| 
       197 
228 
     | 
    
         
             
                    opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |path| options[:execute] = path }
         
     | 
| 
       198 
229 
     | 
    
         
             
                    opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg.lstrip }
         
     | 
| 
         @@ -204,18 +235,20 @@ module ParallelTests 
     | 
|
| 
       204 
235 
     | 
    
         
             
                        abort
         
     | 
| 
       205 
236 
     | 
    
         
             
                      end
         
     | 
| 
       206 
237 
     | 
    
         
             
                    end
         
     | 
| 
       207 
     | 
    
         
            -
                    opts.on( 
     | 
| 
       208 
     | 
    
         
            -
                       
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
      
 238 
     | 
    
         
            +
                    opts.on(
         
     | 
| 
      
 239 
     | 
    
         
            +
                      "--suffix [PATTERN]",
         
     | 
| 
      
 240 
     | 
    
         
            +
                      <<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
         
     | 
| 
      
 241 
     | 
    
         
            +
                        override built in test file pattern (should match suffix):
         
     | 
| 
      
 242 
     | 
    
         
            +
                        '_spec\.rb$' - matches rspec files
         
     | 
| 
      
 243 
     | 
    
         
            +
                        '_(test|spec).rb$' - matches test or spec files
         
     | 
| 
       211 
244 
     | 
    
         
             
                      TEXT
         
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
      
 245 
     | 
    
         
            +
                    ) { |pattern| options[:suffix] = /#{pattern}/ }
         
     | 
| 
       213 
246 
     | 
    
         
             
                    opts.on("--serialize-stdout", "Serialize stdout output, nothing will be written until everything is done") { options[:serialize_stdout] = true }
         
     | 
| 
       214 
247 
     | 
    
         
             
                    opts.on("--prefix-output-with-test-env-number", "Prefixes test env number to the output when not using --serialize-stdout") { options[:prefix_output_with_test_env_number] = true }
         
     | 
| 
       215 
248 
     | 
    
         
             
                    opts.on("--combine-stderr", "Combine stderr into stdout, useful in conjunction with --serialize-stdout") { options[:combine_stderr] = true }
         
     | 
| 
       216 
249 
     | 
    
         
             
                    opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec") { options[:non_parallel] = true }
         
     | 
| 
       217 
250 
     | 
    
         
             
                    opts.on("--no-symlinks", "Do not traverse symbolic links to find test files") { options[:symlinks] = false }
         
     | 
| 
       218 
     | 
    
         
            -
                    opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern') 
     | 
| 
      
 251 
     | 
    
         
            +
                    opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern') { |arg| options[:ignore_tag_pattern] = arg }
         
     | 
| 
       219 
252 
     | 
    
         
             
                    opts.on("--nice", "execute test commands with low priority.") { options[:nice] = true }
         
     | 
| 
       220 
253 
     | 
    
         
             
                    opts.on("--runtime-log [PATH]", "Location of previously recorded test runtimes") { |path| options[:runtime_log] = path }
         
     | 
| 
       221 
254 
     | 
    
         
             
                    opts.on("--allowed-missing [INT]", Integer, "Allowed percentage of missing runtimes (default = 50)") { |percent| options[:allowed_missing_percent] = percent }
         
     | 
| 
         @@ -226,13 +259,17 @@ module ParallelTests 
     | 
|
| 
       226 
259 
     | 
    
         
             
                    opts.on("--verbose-process-command", "Displays only the command that will be executed by each process") { options[:verbose_process_command] = true }
         
     | 
| 
       227 
260 
     | 
    
         
             
                    opts.on("--verbose-rerun-command", "When there are failures, displays the command executed by each process that failed") { options[:verbose_rerun_command] = true }
         
     | 
| 
       228 
261 
     | 
    
         
             
                    opts.on("--quiet", "Print only tests output") { options[:quiet] = true }
         
     | 
| 
       229 
     | 
    
         
            -
                    opts.on("-v", "--version", "Show Version")  
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
      
 262 
     | 
    
         
            +
                    opts.on("-v", "--version", "Show Version") do
         
     | 
| 
      
 263 
     | 
    
         
            +
                      puts ParallelTests::VERSION
         
     | 
| 
      
 264 
     | 
    
         
            +
                      exit 0
         
     | 
| 
      
 265 
     | 
    
         
            +
                    end
         
     | 
| 
      
 266 
     | 
    
         
            +
                    opts.on("-h", "--help", "Show this.") do
         
     | 
| 
      
 267 
     | 
    
         
            +
                      puts opts
         
     | 
| 
      
 268 
     | 
    
         
            +
                      exit 0
         
     | 
| 
      
 269 
     | 
    
         
            +
                    end
         
     | 
| 
       231 
270 
     | 
    
         
             
                  end.parse!(argv)
         
     | 
| 
       232 
271 
     | 
    
         | 
| 
       233 
     | 
    
         
            -
                  if options[:verbose] && options[:quiet]
         
     | 
| 
       234 
     | 
    
         
            -
                    raise "Both options are mutually exclusive: verbose & quiet"
         
     | 
| 
       235 
     | 
    
         
            -
                  end
         
     | 
| 
      
 272 
     | 
    
         
            +
                  raise "Both options are mutually exclusive: verbose & quiet" if options[:verbose] && options[:quiet]
         
     | 
| 
       236 
273 
     | 
    
         | 
| 
       237 
274 
     | 
    
         
             
                  if options[:count] == 0
         
     | 
| 
       238 
275 
     | 
    
         
             
                    options.delete(:count)
         
     | 
| 
         @@ -249,12 +286,18 @@ module ParallelTests 
     | 
|
| 
       249 
286 
     | 
    
         | 
| 
       250 
287 
     | 
    
         
             
                  options[:group_by] ||= :filesize if options[:only_group]
         
     | 
| 
       251 
288 
     | 
    
         | 
| 
       252 
     | 
    
         
            -
                   
     | 
| 
      
 289 
     | 
    
         
            +
                  if options[:group_by] == :found && options[:single_process]
         
     | 
| 
      
 290 
     | 
    
         
            +
                    raise "--group-by found and --single-process are not supported"
         
     | 
| 
      
 291 
     | 
    
         
            +
                  end
         
     | 
| 
       253 
292 
     | 
    
         
             
                  allowed = [:filesize, :runtime, :found]
         
     | 
| 
       254 
293 
     | 
    
         
             
                  if !allowed.include?(options[:group_by]) && options[:only_group]
         
     | 
| 
       255 
294 
     | 
    
         
             
                    raise "--group-by #{allowed.join(" or ")} is required for --only-group"
         
     | 
| 
       256 
295 
     | 
    
         
             
                  end
         
     | 
| 
       257 
296 
     | 
    
         | 
| 
      
 297 
     | 
    
         
            +
                  if options[:specify_groups] && (options.keys & [:single_process, :isolate, :isolate_count]).any?
         
     | 
| 
      
 298 
     | 
    
         
            +
                    raise "Can't pass --specify-groups with any of these keys: --single, --isolate, or --isolate-n"
         
     | 
| 
      
 299 
     | 
    
         
            +
                  end
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
       258 
301 
     | 
    
         
             
                  options
         
     | 
| 
       259 
302 
     | 
    
         
             
                end
         
     | 
| 
       260 
303 
     | 
    
         | 
| 
         @@ -266,7 +309,7 @@ module ParallelTests 
     | 
|
| 
       266 
309 
     | 
    
         | 
| 
       267 
310 
     | 
    
         
             
                def extract_test_options(argv)
         
     | 
| 
       268 
311 
     | 
    
         
             
                  dash_index = argv.index("--") || -1
         
     | 
| 
       269 
     | 
    
         
            -
                  argv[dash_index+1..-1]
         
     | 
| 
      
 312 
     | 
    
         
            +
                  argv[dash_index + 1..-1]
         
     | 
| 
       270 
313 
     | 
    
         
             
                end
         
     | 
| 
       271 
314 
     | 
    
         | 
| 
       272 
315 
     | 
    
         
             
                def append_test_options(options, argv)
         
     | 
| 
         @@ -286,7 +329,7 @@ module ParallelTests 
     | 
|
| 
       286 
329 
     | 
    
         | 
| 
       287 
330 
     | 
    
         
             
                def execute_shell_command_in_parallel(command, num_processes, options)
         
     | 
| 
       288 
331 
     | 
    
         
             
                  runs = if options[:only_group]
         
     | 
| 
       289 
     | 
    
         
            -
                    options[:only_group].map{|g| g - 1}
         
     | 
| 
      
 332 
     | 
    
         
            +
                    options[:only_group].map { |g| g - 1 }
         
     | 
| 
       290 
333 
     | 
    
         
             
                  else
         
     | 
| 
       291 
334 
     | 
    
         
             
                    (0...num_processes).to_a
         
     | 
| 
       292 
335 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -305,13 +348,13 @@ module ParallelTests 
     | 
|
| 
       305 
348 
     | 
    
         
             
                  abort if results.any? { |r| r[:exit_status] != 0 }
         
     | 
| 
       306 
349 
     | 
    
         
             
                end
         
     | 
| 
       307 
350 
     | 
    
         | 
| 
       308 
     | 
    
         
            -
                def report_time_taken
         
     | 
| 
       309 
     | 
    
         
            -
                  seconds = ParallelTests.delta 
     | 
| 
      
 351 
     | 
    
         
            +
                def report_time_taken(&block)
         
     | 
| 
      
 352 
     | 
    
         
            +
                  seconds = ParallelTests.delta(&block).to_i
         
     | 
| 
       310 
353 
     | 
    
         
             
                  puts "\nTook #{seconds} seconds#{detailed_duration(seconds)}"
         
     | 
| 
       311 
354 
     | 
    
         
             
                end
         
     | 
| 
       312 
355 
     | 
    
         | 
| 
       313 
356 
     | 
    
         
             
                def detailed_duration(seconds)
         
     | 
| 
       314 
     | 
    
         
            -
                  parts = [ 
     | 
| 
      
 357 
     | 
    
         
            +
                  parts = [seconds / 3600, seconds % 3600 / 60, seconds % 60].drop_while(&:zero?)
         
     | 
| 
       315 
358 
     | 
    
         
             
                  return if parts.size < 2
         
     | 
| 
       316 
359 
     | 
    
         
             
                  parts = parts.map { |i| "%02d" % i }.join(':').sub(/^0/, '')
         
     | 
| 
       317 
360 
     | 
    
         
             
                  " (#{parts})"
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       1 
2 
     | 
    
         
             
            begin
         
     | 
| 
       2 
3 
     | 
    
         
             
              gem "cuke_modeler", "~> 3.0"
         
     | 
| 
       3 
4 
     | 
    
         
             
              require 'cuke_modeler'
         
     | 
| 
         @@ -12,7 +13,7 @@ module ParallelTests 
     | 
|
| 
       12 
13 
     | 
    
         
             
                    def all(tests, options)
         
     | 
| 
       13 
14 
     | 
    
         
             
                      ignore_tag_pattern = options[:ignore_tag_pattern].nil? ? nil : Regexp.compile(options[:ignore_tag_pattern])
         
     | 
| 
       14 
15 
     | 
    
         
             
                      # format of hash will be FILENAME => NUM_STEPS
         
     | 
| 
       15 
     | 
    
         
            -
                      steps_per_file = tests.each_with_object({}) do |file,steps|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      steps_per_file = tests.each_with_object({}) do |file, steps|
         
     | 
| 
       16 
17 
     | 
    
         
             
                        feature = ::CukeModeler::FeatureFile.new(file).feature
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
                        # skip feature if it matches tag regex
         
     | 
| 
         @@ -20,8 +21,8 @@ module ParallelTests 
     | 
|
| 
       20 
21 
     | 
    
         | 
| 
       21 
22 
     | 
    
         
             
                        # count the number of steps in the file
         
     | 
| 
       22 
23 
     | 
    
         
             
                        # will only include a feature if the regex does not match
         
     | 
| 
       23 
     | 
    
         
            -
                        all_steps = feature.scenarios.map{|a| a.steps.count if a.tags.grep(ignore_tag_pattern).empty? }.compact
         
     | 
| 
       24 
     | 
    
         
            -
                        steps[file] = all_steps. 
     | 
| 
      
 24 
     | 
    
         
            +
                        all_steps = feature.scenarios.map { |a| a.steps.count if a.tags.grep(ignore_tag_pattern).empty? }.compact
         
     | 
| 
      
 25 
     | 
    
         
            +
                        steps[file] = all_steps.sum
         
     | 
| 
       25 
26 
     | 
    
         
             
                      end
         
     | 
| 
       26 
27 
     | 
    
         
             
                      steps_per_file.sort_by { |_, value| -value }
         
     | 
| 
       27 
28 
     | 
    
         
             
                    end
         
     |