parallel_tests 3.7.3 → 4.2.1
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 +10 -9
 - data/lib/parallel_tests/cli.rb +38 -31
 - data/lib/parallel_tests/cucumber/runner.rb +2 -2
 - data/lib/parallel_tests/cucumber/scenario_line_logger.rb +1 -1
 - data/lib/parallel_tests/cucumber/scenarios.rb +4 -3
 - data/lib/parallel_tests/gherkin/runner.rb +11 -16
 - data/lib/parallel_tests/grouper.rb +1 -5
 - data/lib/parallel_tests/pids.rb +2 -2
 - data/lib/parallel_tests/rspec/runner.rb +7 -14
 - data/lib/parallel_tests/tasks.rb +105 -60
 - data/lib/parallel_tests/test/runner.rb +55 -15
 - data/lib/parallel_tests/version.rb +1 -1
 - data/lib/parallel_tests.rb +1 -1
 - metadata +10 -10
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: a9044c95c595a48f89a621563c609a4c9fa89d851792ca694a30fcaf947a2119
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 248e38e467b9070c1666819e2c1dc9149b791644b42e8a90cd53df82ebb80eed
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 363e8d317a43d03043a270c19d05f60071bd05a9b435a0545454e81b96d875b694dd4fadc74669ba136990d57d863883132a19ff7fd1c9c4169e2c16a8e2db38
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: ef251fa00adf1310c5281ee4985119ce6b4810d121d87a3a4a7f6b6a03aa968ed9be7847eec127e74a118983e4454b181635d1538b1a17b5f242fbb11839caa9
         
     | 
    
        data/Readme.md
    CHANGED
    
    | 
         @@ -1,8 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # parallel_tests
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            [](https://rubygems.org/gems/parallel_tests)
         
     | 
| 
       4 
     | 
    
         
            -
            [](https://github.com/grosser/parallel_tests/actions?query=workflow%3Awindows)
         
     | 
| 
      
 4 
     | 
    
         
            +
            [](https://github.com/grosser/parallel_tests/actions?query=workflow%3Atest)
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
6 
     | 
    
         
             
            Speedup Test::Unit + RSpec + Cucumber + Spinach by running parallel on multiple CPU cores.<br/>
         
     | 
| 
       8 
7 
     | 
    
         
             
            ParallelTests splits tests into even groups (by number of lines or runtime) and runs each group in a single process with its own database.
         
     | 
| 
         @@ -42,7 +41,7 @@ test: 
     | 
|
| 
       42 
41 
     | 
    
         | 
| 
       43 
42 
     | 
    
         
             
            ### Setup environment from scratch (create db and loads schema, useful for CI)
         
     | 
| 
       44 
43 
     | 
    
         
             
                rake parallel:setup
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
       46 
45 
     | 
    
         
             
            ### Drop all test databases
         
     | 
| 
       47 
46 
     | 
    
         
             
                rake parallel:drop
         
     | 
| 
       48 
47 
     | 
    
         | 
| 
         @@ -193,15 +192,15 @@ Setup for non-rails 
     | 
|
| 
       193 
192 
     | 
    
         
             
             - use `ENV['TEST_ENV_NUMBER']` inside your tests to select separate db/memcache/etc. (docker compose: expose it)
         
     | 
| 
       194 
193 
     | 
    
         | 
| 
       195 
194 
     | 
    
         
             
             - Only run a subset of files / folders:
         
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
       197 
196 
     | 
    
         
             
                `parallel_test test/bar test/baz/foo_text.rb`
         
     | 
| 
       198 
197 
     | 
    
         | 
| 
       199 
198 
     | 
    
         
             
             - Pass test-options and files via `--`:
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
       201 
200 
     | 
    
         
             
                `parallel_rspec -- -t acceptance -f progress -- spec/foo_spec.rb spec/acceptance`
         
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
       203 
202 
     | 
    
         
             
             - Pass in test options, by using the -o flag (wrap everything in quotes):
         
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
       205 
204 
     | 
    
         
             
                `parallel_cucumber -n 2 -o '-p foo_profile --tags @only_this_tag or @only_that_tag --format summary'`
         
     | 
| 
       206 
205 
     | 
    
         | 
| 
       207 
206 
     | 
    
         
             
            Options are:
         
     | 
| 
         @@ -250,8 +249,7 @@ Options are: 
     | 
|
| 
       250 
249 
     | 
    
         
             
                    --first-is-1                 Use "1" as TEST_ENV_NUMBER to not reuse the default test environment
         
     | 
| 
       251 
250 
     | 
    
         
             
                    --fail-fast                  Stop all groups when one group fails (best used with --test-options '--fail-fast' if supported
         
     | 
| 
       252 
251 
     | 
    
         
             
                    --verbose                    Print debug output
         
     | 
| 
       253 
     | 
    
         
            -
                    --verbose- 
     | 
| 
       254 
     | 
    
         
            -
                    --verbose-rerun-command      When there are failures, displays the command executed by each process that failed
         
     | 
| 
      
 252 
     | 
    
         
            +
                    --verbose-command            Displays the command that will be executed by each process and when there are failures displays the command executed by each process that failed
         
     | 
| 
       255 
253 
     | 
    
         
             
                    --quiet                      Print only tests output
         
     | 
| 
       256 
254 
     | 
    
         
             
                -v, --version                    Show Version
         
     | 
| 
       257 
255 
     | 
    
         
             
                -h, --help                       Show this.
         
     | 
| 
         @@ -402,6 +400,9 @@ inspired by [pivotal labs](https://blog.pivotal.io/labs/labs/parallelize-your-rs 
     | 
|
| 
       402 
400 
     | 
    
         
             
             - [Vikram B Kumar](https://github.com/v-kumar)
         
     | 
| 
       403 
401 
     | 
    
         
             
             - [Joshua Pinter](https://github.com/joshuapinter)
         
     | 
| 
       404 
402 
     | 
    
         
             
             - [Zach Dennis](https://github.com/zdennis)
         
     | 
| 
      
 403 
     | 
    
         
            +
             - [Jon Dufresne](https://github.com/jdufresne)
         
     | 
| 
      
 404 
     | 
    
         
            +
             - [Eric Kessler](https://github.com/enkessler)
         
     | 
| 
      
 405 
     | 
    
         
            +
             - [Adis Osmonov](https://github.com/adis-io)
         
     | 
| 
       405 
406 
     | 
    
         | 
| 
       406 
407 
     | 
    
         
             
            [Michael Grosser](http://grosser.it)<br/>
         
     | 
| 
       407 
408 
     | 
    
         
             
            michael@grosser.it<br/>
         
     | 
    
        data/lib/parallel_tests/cli.rb
    CHANGED
    
    | 
         @@ -20,7 +20,7 @@ module ParallelTests 
     | 
|
| 
       20 
20 
     | 
    
         
             
                  options[:first_is_1] ||= first_is_1?
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                  if options[:execute]
         
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
      
 23 
     | 
    
         
            +
                    execute_command_in_parallel(options[:execute], num_processes, options)
         
     | 
| 
       24 
24 
     | 
    
         
             
                  else
         
     | 
| 
       25 
25 
     | 
    
         
             
                    run_tests_in_parallel(num_processes, options)
         
     | 
| 
       26 
26 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -32,9 +32,23 @@ module ParallelTests 
     | 
|
| 
       32 
32 
     | 
    
         
             
                  @graceful_shutdown_attempted ||= false
         
     | 
| 
       33 
33 
     | 
    
         
             
                  Kernel.exit if @graceful_shutdown_attempted
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                  #  
     | 
| 
       36 
     | 
    
         
            -
                  #  
     | 
| 
       37 
     | 
    
         
            -
                   
     | 
| 
      
 35 
     | 
    
         
            +
                  # In a shell, all sub-processes also get an interrupt, so they shut themselves down.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  # In a background process this does not happen and we need to do it ourselves.
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # We cannot always send the interrupt since then the sub-processes would get interrupted twice when in foreground
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # and that messes with interrupt handling.
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # (can simulate detached with `(bundle exec parallel_rspec test/a_spec.rb -n 2 &)`)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # also the integration test "passes on int signal to child processes" is detached.
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # On windows getpgid does not work so we resort to always killing which is the smaller bug.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # The ParallelTests::Pids `synchronize` method can't be called directly from a trap,
         
     | 
| 
      
 46 
     | 
    
         
            +
                  # using Thread workaround https://github.com/ddollar/foreman/issues/332
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Thread.new do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    if Gem.win_platform? || ((child_pid = ParallelTests.pids.all.first) && Process.getpgid(child_pid) != Process.pid)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      ParallelTests.stop_all_processes
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
       38 
52 
     | 
    
         | 
| 
       39 
53 
     | 
    
         
             
                  @graceful_shutdown_attempted = true
         
     | 
| 
       40 
54 
     | 
    
         
             
                end
         
     | 
| 
         @@ -61,20 +75,15 @@ module ParallelTests 
     | 
|
| 
       61 
75 
     | 
    
         
             
                    groups = @runner.tests_in_groups(options[:files], num_processes, options)
         
     | 
| 
       62 
76 
     | 
    
         
             
                    groups.reject!(&:empty?)
         
     | 
| 
       63 
77 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
                     
     | 
| 
       65 
     | 
    
         
            -
                       
     | 
| 
       66 
     | 
    
         
            -
                       
     | 
| 
       67 
     | 
    
         
            -
                      execute_in_parallel(groups_to_run, groups_to_run.size, options) do |group|
         
     | 
| 
       68 
     | 
    
         
            -
                        run_tests(group, groups_to_run.index(group), 1, options)
         
     | 
| 
       69 
     | 
    
         
            -
                      end
         
     | 
| 
       70 
     | 
    
         
            -
                    else
         
     | 
| 
       71 
     | 
    
         
            -
                      report_number_of_tests(groups) unless options[:quiet]
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                      execute_in_parallel(groups, groups.size, options) do |group|
         
     | 
| 
       74 
     | 
    
         
            -
                        run_tests(group, groups.index(group), num_processes, options)
         
     | 
| 
       75 
     | 
    
         
            -
                      end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    if options[:only_group]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      groups = options[:only_group].map { |i| groups[i - 1] }.compact
         
     | 
| 
      
 80 
     | 
    
         
            +
                      num_processes = 1
         
     | 
| 
       76 
81 
     | 
    
         
             
                    end
         
     | 
| 
       77 
82 
     | 
    
         | 
| 
      
 83 
     | 
    
         
            +
                    report_number_of_tests(groups) unless options[:quiet]
         
     | 
| 
      
 84 
     | 
    
         
            +
                    test_results = execute_in_parallel(groups, groups.size, options) do |group|
         
     | 
| 
      
 85 
     | 
    
         
            +
                      run_tests(group, groups.index(group), num_processes, options)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
       78 
87 
     | 
    
         
             
                    report_results(test_results, options) unless options[:quiet]
         
     | 
| 
       79 
88 
     | 
    
         
             
                  end
         
     | 
| 
       80 
89 
     | 
    
         | 
| 
         @@ -100,7 +109,7 @@ module ParallelTests 
     | 
|
| 
       100 
109 
     | 
    
         | 
| 
       101 
110 
     | 
    
         
             
                def run_tests(group, process_number, num_processes, options)
         
     | 
| 
       102 
111 
     | 
    
         
             
                  if group.empty?
         
     | 
| 
       103 
     | 
    
         
            -
                    { stdout: '', exit_status: 0, command:  
     | 
| 
      
 112 
     | 
    
         
            +
                    { stdout: '', exit_status: 0, command: nil, seed: nil }
         
     | 
| 
       104 
113 
     | 
    
         
             
                  else
         
     | 
| 
       105 
114 
     | 
    
         
             
                    @runner.run_tests(group, process_number, num_processes, options)
         
     | 
| 
       106 
115 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -136,13 +145,12 @@ module ParallelTests 
     | 
|
| 
       136 
145 
     | 
    
         
             
                  failing_sets = test_results.reject { |r| r[:exit_status] == 0 }
         
     | 
| 
       137 
146 
     | 
    
         
             
                  return if failing_sets.none?
         
     | 
| 
       138 
147 
     | 
    
         | 
| 
       139 
     | 
    
         
            -
                  if options[:verbose] || options[: 
     | 
| 
      
 148 
     | 
    
         
            +
                  if options[:verbose] || options[:verbose_command]
         
     | 
| 
       140 
149 
     | 
    
         
             
                    puts "\n\nTests have failed for a parallel_test group. Use the following command to run the group again:\n\n"
         
     | 
| 
       141 
150 
     | 
    
         
             
                    failing_sets.each do |failing_set|
         
     | 
| 
       142 
151 
     | 
    
         
             
                      command = failing_set[:command]
         
     | 
| 
       143 
     | 
    
         
            -
                      command = command.gsub(/;export [A-Z_]+;/, ' ') # remove ugly export statements
         
     | 
| 
       144 
152 
     | 
    
         
             
                      command = @runner.command_with_seed(command, failing_set[:seed]) if failing_set[:seed]
         
     | 
| 
       145 
     | 
    
         
            -
                       
     | 
| 
      
 153 
     | 
    
         
            +
                      @runner.print_command(command, failing_set[:env] || {})
         
     | 
| 
       146 
154 
     | 
    
         
             
                    end
         
     | 
| 
       147 
155 
     | 
    
         
             
                  end
         
     | 
| 
       148 
156 
     | 
    
         
             
                end
         
     | 
| 
         @@ -229,7 +237,7 @@ module ParallelTests 
     | 
|
| 
       229 
237 
     | 
    
         
             
                        processes in a specific formation. Commas indicate specs in the same process,
         
     | 
| 
       230 
238 
     | 
    
         
             
                        pipes indicate specs in a new process. Cannot use with --single, --isolate, or
         
     | 
| 
       231 
239 
     | 
    
         
             
                        --isolate-n.  Ex.
         
     | 
| 
       232 
     | 
    
         
            -
                        $  
     | 
| 
      
 240 
     | 
    
         
            +
                        $ parallel_test -n 3 . --specify-groups '1_spec.rb,2_spec.rb|3_spec.rb'
         
     | 
| 
       233 
241 
     | 
    
         
             
                          Process 1 will contain 1_spec.rb and 2_spec.rb
         
     | 
| 
       234 
242 
     | 
    
         
             
                          Process 2 will contain 3_spec.rb
         
     | 
| 
       235 
243 
     | 
    
         
             
                          Process 3 will contain all other specs
         
     | 
| 
         @@ -238,8 +246,8 @@ module ParallelTests 
     | 
|
| 
       238 
246 
     | 
    
         | 
| 
       239 
247 
     | 
    
         
             
                    opts.on("--only-group INT[,INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
         
     | 
| 
       240 
248 
     | 
    
         | 
| 
       241 
     | 
    
         
            -
                    opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { | 
     | 
| 
       242 
     | 
    
         
            -
                    opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg 
     | 
| 
      
 249 
     | 
    
         
            +
                    opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |arg| options[:execute] = Shellwords.shellsplit(arg) }
         
     | 
| 
      
 250 
     | 
    
         
            +
                    opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = Shellwords.shellsplit(arg) }
         
     | 
| 
       243 
251 
     | 
    
         
             
                    opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
         
     | 
| 
       244 
252 
     | 
    
         
             
                      @runner = load_runner(type)
         
     | 
| 
       245 
253 
     | 
    
         
             
                    rescue NameError, LoadError => e
         
     | 
| 
         @@ -267,8 +275,7 @@ module ParallelTests 
     | 
|
| 
       267 
275 
     | 
    
         
             
                    opts.on("--first-is-1", "Use \"1\" as TEST_ENV_NUMBER to not reuse the default test environment") { options[:first_is_1] = true }
         
     | 
| 
       268 
276 
     | 
    
         
             
                    opts.on("--fail-fast", "Stop all groups when one group fails (best used with --test-options '--fail-fast' if supported") { options[:fail_fast] = true }
         
     | 
| 
       269 
277 
     | 
    
         
             
                    opts.on("--verbose", "Print debug output") { options[:verbose] = true }
         
     | 
| 
       270 
     | 
    
         
            -
                    opts.on("--verbose- 
     | 
| 
       271 
     | 
    
         
            -
                    opts.on("--verbose-rerun-command", "When there are failures, displays the command executed by each process that failed") { options[:verbose_rerun_command] = true }
         
     | 
| 
      
 278 
     | 
    
         
            +
                    opts.on("--verbose-command", "Displays the command that will be executed by each process and when there are failures displays the command executed by each process that failed") { options[:verbose_command] = true }
         
     | 
| 
       272 
279 
     | 
    
         
             
                    opts.on("--quiet", "Print only tests output") { options[:quiet] = true }
         
     | 
| 
       273 
280 
     | 
    
         
             
                    opts.on("-v", "--version", "Show Version") do
         
     | 
| 
       274 
281 
     | 
    
         
             
                      puts ParallelTests::VERSION
         
     | 
| 
         @@ -322,20 +329,20 @@ module ParallelTests 
     | 
|
| 
       322 
329 
     | 
    
         
             
                def extract_file_paths(argv)
         
     | 
| 
       323 
330 
     | 
    
         
             
                  dash_index = argv.rindex("--")
         
     | 
| 
       324 
331 
     | 
    
         
             
                  file_args_at = (dash_index || -1) + 1
         
     | 
| 
       325 
     | 
    
         
            -
                  [argv[file_args_at 
     | 
| 
      
 332 
     | 
    
         
            +
                  [argv[file_args_at..], argv[0...(dash_index || 0)]]
         
     | 
| 
       326 
333 
     | 
    
         
             
                end
         
     | 
| 
       327 
334 
     | 
    
         | 
| 
       328 
335 
     | 
    
         
             
                def extract_test_options(argv)
         
     | 
| 
       329 
336 
     | 
    
         
             
                  dash_index = argv.index("--") || -1
         
     | 
| 
       330 
     | 
    
         
            -
                  argv[dash_index + 1 
     | 
| 
      
 337 
     | 
    
         
            +
                  argv[dash_index + 1..]
         
     | 
| 
       331 
338 
     | 
    
         
             
                end
         
     | 
| 
       332 
339 
     | 
    
         | 
| 
       333 
340 
     | 
    
         
             
                def append_test_options(options, argv)
         
     | 
| 
       334 
341 
     | 
    
         
             
                  new_opts = extract_test_options(argv)
         
     | 
| 
       335 
342 
     | 
    
         
             
                  return if new_opts.empty?
         
     | 
| 
       336 
343 
     | 
    
         | 
| 
       337 
     | 
    
         
            -
                   
     | 
| 
       338 
     | 
    
         
            -
                  options[:test_options]  
     | 
| 
      
 344 
     | 
    
         
            +
                  options[:test_options] ||= []
         
     | 
| 
      
 345 
     | 
    
         
            +
                  options[:test_options] += new_opts
         
     | 
| 
       339 
346 
     | 
    
         
             
                end
         
     | 
| 
       340 
347 
     | 
    
         | 
| 
       341 
348 
     | 
    
         
             
                def load_runner(type)
         
     | 
| 
         @@ -345,7 +352,7 @@ module ParallelTests 
     | 
|
| 
       345 
352 
     | 
    
         
             
                  klass_name.split('::').inject(Object) { |x, y| x.const_get(y) }
         
     | 
| 
       346 
353 
     | 
    
         
             
                end
         
     | 
| 
       347 
354 
     | 
    
         | 
| 
       348 
     | 
    
         
            -
                def  
     | 
| 
      
 355 
     | 
    
         
            +
                def execute_command_in_parallel(command, num_processes, options)
         
     | 
| 
       349 
356 
     | 
    
         
             
                  runs = if options[:only_group]
         
     | 
| 
       350 
357 
     | 
    
         
             
                    options[:only_group].map { |g| g - 1 }
         
     | 
| 
       351 
358 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -397,7 +404,7 @@ module ParallelTests 
     | 
|
| 
       397 
404 
     | 
    
         
             
                def simulate_output_for_ci(simulate)
         
     | 
| 
       398 
405 
     | 
    
         
             
                  if simulate
         
     | 
| 
       399 
406 
     | 
    
         
             
                    progress_indicator = Thread.new do
         
     | 
| 
       400 
     | 
    
         
            -
                      interval = Float(ENV 
     | 
| 
      
 407 
     | 
    
         
            +
                      interval = Float(ENV['PARALLEL_TEST_HEARTBEAT_INTERVAL'] || 60)
         
     | 
| 
       401 
408 
     | 
    
         
             
                      loop do
         
     | 
| 
       402 
409 
     | 
    
         
             
                        sleep interval
         
     | 
| 
       403 
410 
     | 
    
         
             
                        print '.'
         
     | 
| 
         @@ -35,8 +35,8 @@ module ParallelTests 
     | 
|
| 
       35 
35 
     | 
    
         
             
                    end
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                    def command_with_seed(cmd, seed)
         
     | 
| 
       38 
     | 
    
         
            -
                      clean = cmd 
     | 
| 
       39 
     | 
    
         
            -
                       
     | 
| 
      
 38 
     | 
    
         
            +
                      clean = remove_command_arguments(cmd, '--order')
         
     | 
| 
      
 39 
     | 
    
         
            +
                      [*clean, '--order', "random:#{seed}"]
         
     | 
| 
       40 
40 
     | 
    
         
             
                    end
         
     | 
| 
       41 
41 
     | 
    
         
             
                  end
         
     | 
| 
       42 
42 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,7 +27,7 @@ module ParallelTests 
     | 
|
| 
       27 
27 
     | 
    
         
             
                          example_tags = example.tags.map(&:name)
         
     | 
| 
       28 
28 
     | 
    
         
             
                          example_tags = scenario_tags + example_tags
         
     | 
| 
       29 
29 
     | 
    
         
             
                          next unless matches_tags?(example_tags)
         
     | 
| 
       30 
     | 
    
         
            -
                          example.rows[1 
     | 
| 
      
 30 
     | 
    
         
            +
                          example.rows[1..].each do |row|
         
     | 
| 
       31 
31 
     | 
    
         
             
                            test_line = row.source_line
         
     | 
| 
       32 
32 
     | 
    
         
             
                            next if line_numbers.any? && !line_numbers.include?(test_line)
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
         @@ -4,7 +4,6 @@ require 'cucumber/runtime' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'cucumber'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'parallel_tests/cucumber/scenario_line_logger'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'parallel_tests/gherkin/listener'
         
     | 
| 
       7 
     | 
    
         
            -
            require 'shellwords'
         
     | 
| 
       8 
7 
     | 
    
         | 
| 
       9 
8 
     | 
    
         
             
            begin
         
     | 
| 
       10 
9 
     | 
    
         
             
              gem "cuke_modeler", "~> 3.0"
         
     | 
| 
         @@ -20,7 +19,7 @@ module ParallelTests 
     | 
|
| 
       20 
19 
     | 
    
         
             
                    def all(files, options = {})
         
     | 
| 
       21 
20 
     | 
    
         
             
                      # Parse tag expression from given test options and ignore tag pattern. Refer here to understand how new tag expression syntax works - https://github.com/cucumber/cucumber/tree/master/tag-expressions
         
     | 
| 
       22 
21 
     | 
    
         
             
                      tags = []
         
     | 
| 
       23 
     | 
    
         
            -
                      words = options[:test_options] 
     | 
| 
      
 22 
     | 
    
         
            +
                      words = options[:test_options] || []
         
     | 
| 
       24 
23 
     | 
    
         
             
                      words.each_with_index { |w, i| tags << words[i + 1] if ["-t", "--tags"].include?(w) }
         
     | 
| 
       25 
24 
     | 
    
         
             
                      if ignore = options[:ignore_tag_pattern]
         
     | 
| 
       26 
25 
     | 
    
         
             
                        tags << "not (#{ignore})"
         
     | 
| 
         @@ -53,7 +52,9 @@ module ParallelTests 
     | 
|
| 
       53 
52 
     | 
    
         
             
                        feature_tags = feature.tags.map(&:name)
         
     | 
| 
       54 
53 
     | 
    
         | 
| 
       55 
54 
     | 
    
         
             
                        # We loop on each children of the feature
         
     | 
| 
       56 
     | 
    
         
            -
                        feature.tests 
     | 
| 
      
 55 
     | 
    
         
            +
                        test_models = feature.tests
         
     | 
| 
      
 56 
     | 
    
         
            +
                        test_models += feature.rules.flat_map(&:tests) if feature.respond_to?(:rules) # cuke_modeler >= 3.2 supports rules
         
     | 
| 
      
 57 
     | 
    
         
            +
                        test_models.each do |test|
         
     | 
| 
       57 
58 
     | 
    
         
             
                          # It's a scenario, we add it to the scenario_line_logger
         
     | 
| 
       58 
59 
     | 
    
         
             
                          scenario_line_logger.visit_feature_element(document.path, test, feature_tags, line_numbers: test_lines)
         
     | 
| 
       59 
60 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -1,6 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         
             
            require "parallel_tests/test/runner"
         
     | 
| 
       3 
     | 
    
         
            -
            require 'shellwords'
         
     | 
| 
       4 
3 
     | 
    
         | 
| 
       5 
4 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
       6 
5 
     | 
    
         
             
              module Gherkin
         
     | 
| 
         @@ -16,17 +15,13 @@ module ParallelTests 
     | 
|
| 
       16 
15 
     | 
    
         
             
                        end
         
     | 
| 
       17 
16 
     | 
    
         
             
                      end
         
     | 
| 
       18 
17 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
                      sanitized_test_files = combined_scenarios.map { |val| WINDOWS ? "\"#{val}\"" : Shellwords.escape(val) }
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
18 
     | 
    
         
             
                      options[:env] ||= {}
         
     | 
| 
       22 
19 
     | 
    
         
             
                      options[:env] = options[:env].merge({ 'AUTOTEST' => '1' }) if $stdout.tty?
         
     | 
| 
       23 
20 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
                      cmd =  
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                        cucumber_opts(options[:test_options])
         
     | 
| 
       29 
     | 
    
         
            -
                      ].compact.reject(&:empty?).join(' ')
         
     | 
| 
      
 21 
     | 
    
         
            +
                      cmd = executable
         
     | 
| 
      
 22 
     | 
    
         
            +
                      cmd += runtime_logging if File.directory?(File.dirname(runtime_log))
         
     | 
| 
      
 23 
     | 
    
         
            +
                      cmd += combined_scenarios
         
     | 
| 
      
 24 
     | 
    
         
            +
                      cmd += cucumber_opts(options[:test_options])
         
     | 
| 
       30 
25 
     | 
    
         
             
                      execute_command(cmd, process_number, num_processes, options)
         
     | 
| 
       31 
26 
     | 
    
         
             
                    end
         
     | 
| 
       32 
27 
     | 
    
         | 
| 
         @@ -62,22 +57,22 @@ module ParallelTests 
     | 
|
| 
       62 
57 
     | 
    
         
             
                          plural = "s" if (word == group) && (number != 1)
         
     | 
| 
       63 
58 
     | 
    
         
             
                          "#{number} #{word}#{plural}"
         
     | 
| 
       64 
59 
     | 
    
         
             
                        end
         
     | 
| 
       65 
     | 
    
         
            -
                        "#{sums[0]} (#{sums[1 
     | 
| 
      
 60 
     | 
    
         
            +
                        "#{sums[0]} (#{sums[1..].join(", ")})"
         
     | 
| 
       66 
61 
     | 
    
         
             
                      end.compact.join("\n")
         
     | 
| 
       67 
62 
     | 
    
         
             
                    end
         
     | 
| 
       68 
63 
     | 
    
         | 
| 
       69 
64 
     | 
    
         
             
                    def cucumber_opts(given)
         
     | 
| 
       70 
     | 
    
         
            -
                      if given 
     | 
| 
      
 65 
     | 
    
         
            +
                      if given&.include?('--profile') || given&.include?('-p')
         
     | 
| 
       71 
66 
     | 
    
         
             
                        given
         
     | 
| 
       72 
67 
     | 
    
         
             
                      else
         
     | 
| 
       73 
     | 
    
         
            -
                        [given, profile_from_config] 
     | 
| 
      
 68 
     | 
    
         
            +
                        [*given, *profile_from_config]
         
     | 
| 
       74 
69 
     | 
    
         
             
                      end
         
     | 
| 
       75 
70 
     | 
    
         
             
                    end
         
     | 
| 
       76 
71 
     | 
    
         | 
| 
       77 
72 
     | 
    
         
             
                    def profile_from_config
         
     | 
| 
       78 
73 
     | 
    
         
             
                      # copied from https://github.com/cucumber/cucumber/blob/master/lib/cucumber/cli/profile_loader.rb#L85
         
     | 
| 
       79 
74 
     | 
    
         
             
                      config = Dir.glob("{,.config/,config/}#{name}{.yml,.yaml}").first
         
     | 
| 
       80 
     | 
    
         
            -
                       
     | 
| 
      
 75 
     | 
    
         
            +
                      ['--profile', 'parallel'] if config && File.read(config) =~ /^parallel:/
         
     | 
| 
       81 
76 
     | 
    
         
             
                    end
         
     | 
| 
       82 
77 
     | 
    
         | 
| 
       83 
78 
     | 
    
         
             
                    def tests_in_groups(tests, num_groups, options = {})
         
     | 
| 
         @@ -91,7 +86,7 @@ module ParallelTests 
     | 
|
| 
       91 
86 
     | 
    
         
             
                    end
         
     | 
| 
       92 
87 
     | 
    
         | 
| 
       93 
88 
     | 
    
         
             
                    def runtime_logging
         
     | 
| 
       94 
     | 
    
         
            -
                       
     | 
| 
      
 89 
     | 
    
         
            +
                      ['--format', 'ParallelTests::Gherkin::RuntimeLogger', '--out', runtime_log]
         
     | 
| 
       95 
90 
     | 
    
         
             
                    end
         
     | 
| 
       96 
91 
     | 
    
         | 
| 
       97 
92 
     | 
    
         
             
                    def runtime_log
         
     | 
| 
         @@ -102,11 +97,11 @@ module ParallelTests 
     | 
|
| 
       102 
97 
     | 
    
         
             
                      if File.exist?("bin/#{name}")
         
     | 
| 
       103 
98 
     | 
    
         
             
                        ParallelTests.with_ruby_binary("bin/#{name}")
         
     | 
| 
       104 
99 
     | 
    
         
             
                      elsif ParallelTests.bundler_enabled?
         
     | 
| 
       105 
     | 
    
         
            -
                        "bundle exec  
     | 
| 
      
 100 
     | 
    
         
            +
                        ["bundle", "exec", name]
         
     | 
| 
       106 
101 
     | 
    
         
             
                      elsif File.file?("script/#{name}")
         
     | 
| 
       107 
102 
     | 
    
         
             
                        ParallelTests.with_ruby_binary("script/#{name}")
         
     | 
| 
       108 
103 
     | 
    
         
             
                      else
         
     | 
| 
       109 
     | 
    
         
            -
                        name.to_s
         
     | 
| 
      
 104 
     | 
    
         
            +
                        [name.to_s]
         
     | 
| 
       110 
105 
     | 
    
         
             
                      end
         
     | 
| 
       111 
106 
     | 
    
         
             
                    end
         
     | 
| 
       112 
107 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -26,10 +26,6 @@ module ParallelTests 
     | 
|
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
                    isolate_count = isolate_count(options)
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                    if isolate_count >= num_groups
         
     | 
| 
       30 
     | 
    
         
            -
                      raise 'Number of isolated processes must be less than total the number of processes'
         
     | 
| 
       31 
     | 
    
         
            -
                    end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
29 
     | 
    
         
             
                    if isolate_count >= num_groups
         
     | 
| 
       34 
30 
     | 
    
         
             
                      raise 'Number of isolated processes must be >= total number of processes'
         
     | 
| 
       35 
31 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -38,7 +34,7 @@ module ParallelTests 
     | 
|
| 
       38 
34 
     | 
    
         
             
                      # add all files that should run in a multiple isolated processes to their own groups
         
     | 
| 
       39 
35 
     | 
    
         
             
                      group_features_by_size(items_to_group(single_items), groups[0..(isolate_count - 1)])
         
     | 
| 
       40 
36 
     | 
    
         
             
                      # group the non-isolated by size
         
     | 
| 
       41 
     | 
    
         
            -
                      group_features_by_size(items_to_group(items), groups[isolate_count 
     | 
| 
      
 37 
     | 
    
         
            +
                      group_features_by_size(items_to_group(items), groups[isolate_count..])
         
     | 
| 
       42 
38 
     | 
    
         
             
                    else
         
     | 
| 
       43 
39 
     | 
    
         
             
                      # add all files that should run in a single non-isolated process to first group
         
     | 
| 
       44 
40 
     | 
    
         
             
                      single_items.each { |item, size| add_to_group(groups.first, item, size) }
         
     | 
    
        data/lib/parallel_tests/pids.rb
    CHANGED
    
    | 
         @@ -43,14 +43,14 @@ module ParallelTests 
     | 
|
| 
       43 
43 
     | 
    
         | 
| 
       44 
44 
     | 
    
         
             
                def read
         
     | 
| 
       45 
45 
     | 
    
         
             
                  sync do
         
     | 
| 
       46 
     | 
    
         
            -
                    contents =  
     | 
| 
      
 46 
     | 
    
         
            +
                    contents = File.read(file_path)
         
     | 
| 
       47 
47 
     | 
    
         
             
                    return if contents.empty?
         
     | 
| 
       48 
48 
     | 
    
         
             
                    @pids = JSON.parse(contents)
         
     | 
| 
       49 
49 
     | 
    
         
             
                  end
         
     | 
| 
       50 
50 
     | 
    
         
             
                end
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
52 
     | 
    
         
             
                def save
         
     | 
| 
       53 
     | 
    
         
            -
                  sync {  
     | 
| 
      
 53 
     | 
    
         
            +
                  sync { File.write(file_path, pids.to_json) }
         
     | 
| 
       54 
54 
     | 
    
         
             
                end
         
     | 
| 
       55 
55 
     | 
    
         | 
| 
       56 
56 
     | 
    
         
             
                def sync(&block)
         
     | 
| 
         @@ -7,8 +7,7 @@ module ParallelTests 
     | 
|
| 
       7 
7 
     | 
    
         
             
                  DEV_NULL = (WINDOWS ? "NUL" : "/dev/null")
         
     | 
| 
       8 
8 
     | 
    
         
             
                  class << self
         
     | 
| 
       9 
9 
     | 
    
         
             
                    def run_tests(test_files, process_number, num_processes, options)
         
     | 
| 
       10 
     | 
    
         
            -
                       
     | 
| 
       11 
     | 
    
         
            -
                      cmd = [exe, options[:test_options], color, spec_opts, *test_files].compact.join(" ")
         
     | 
| 
      
 10 
     | 
    
         
            +
                      cmd = [*executable, *options[:test_options], *color, *spec_opts, *test_files]
         
     | 
| 
       12 
11 
     | 
    
         
             
                      execute_command(cmd, process_number, num_processes, options)
         
     | 
| 
       13 
12 
     | 
    
         
             
                    end
         
     | 
| 
       14 
13 
     | 
    
         | 
| 
         @@ -16,9 +15,9 @@ module ParallelTests 
     | 
|
| 
       16 
15 
     | 
    
         
             
                      if File.exist?("bin/rspec")
         
     | 
| 
       17 
16 
     | 
    
         
             
                        ParallelTests.with_ruby_binary("bin/rspec")
         
     | 
| 
       18 
17 
     | 
    
         
             
                      elsif ParallelTests.bundler_enabled?
         
     | 
| 
       19 
     | 
    
         
            -
                        "bundle exec rspec"
         
     | 
| 
      
 18 
     | 
    
         
            +
                        ["bundle", "exec", "rspec"]
         
     | 
| 
       20 
19 
     | 
    
         
             
                      else
         
     | 
| 
       21 
     | 
    
         
            -
                        "rspec"
         
     | 
| 
      
 20 
     | 
    
         
            +
                        ["rspec"]
         
     | 
| 
       22 
21 
     | 
    
         
             
                      end
         
     | 
| 
       23 
22 
     | 
    
         
             
                    end
         
     | 
| 
       24 
23 
     | 
    
         | 
| 
         @@ -48,8 +47,8 @@ module ParallelTests 
     | 
|
| 
       48 
47 
     | 
    
         
             
                    # --order rand:1234
         
     | 
| 
       49 
48 
     | 
    
         
             
                    # --order random:1234
         
     | 
| 
       50 
49 
     | 
    
         
             
                    def command_with_seed(cmd, seed)
         
     | 
| 
       51 
     | 
    
         
            -
                      clean = cmd 
     | 
| 
       52 
     | 
    
         
            -
                       
     | 
| 
      
 50 
     | 
    
         
            +
                      clean = remove_command_arguments(cmd, '--seed', '--order')
         
     | 
| 
      
 51 
     | 
    
         
            +
                      [*clean, '--seed', seed]
         
     | 
| 
       53 
52 
     | 
    
         
             
                    end
         
     | 
| 
       54 
53 
     | 
    
         | 
| 
       55 
54 
     | 
    
         
             
                    # Summarize results from threads and colorize results based on failure and pending counts.
         
     | 
| 
         @@ -71,19 +70,13 @@ module ParallelTests 
     | 
|
| 
       71 
70 
     | 
    
         | 
| 
       72 
71 
     | 
    
         
             
                    private
         
     | 
| 
       73 
72 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                    # so it can be stubbed....
         
     | 
| 
       75 
     | 
    
         
            -
                    def run(cmd)
         
     | 
| 
       76 
     | 
    
         
            -
                      `#{cmd}`
         
     | 
| 
       77 
     | 
    
         
            -
                    end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
73 
     | 
    
         
             
                    def color
         
     | 
| 
       80 
     | 
    
         
            -
                      '--color --tty' if $stdout.tty?
         
     | 
| 
      
 74 
     | 
    
         
            +
                      ['--color', '--tty'] if $stdout.tty?
         
     | 
| 
       81 
75 
     | 
    
         
             
                    end
         
     | 
| 
       82 
76 
     | 
    
         | 
| 
       83 
77 
     | 
    
         
             
                    def spec_opts
         
     | 
| 
       84 
78 
     | 
    
         
             
                      options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
         
     | 
| 
       85 
     | 
    
         
            -
                       
     | 
| 
       86 
     | 
    
         
            -
                      "-O #{options_file}"
         
     | 
| 
      
 79 
     | 
    
         
            +
                      ["-O", options_file] if options_file
         
     | 
| 
       87 
80 
     | 
    
         
             
                    end
         
     | 
| 
       88 
81 
     | 
    
         
             
                  end
         
     | 
| 
       89 
82 
     | 
    
         
             
                end
         
     | 
    
        data/lib/parallel_tests/tasks.rb
    CHANGED
    
    | 
         @@ -9,16 +9,8 @@ module ParallelTests 
     | 
|
| 
       9 
9 
     | 
    
         
             
                    'test'
         
     | 
| 
       10 
10 
     | 
    
         
             
                  end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                  def rake_bin
         
     | 
| 
       13 
     | 
    
         
            -
                    # Prevent 'Exec format error' Errno::ENOEXEC on Windows
         
     | 
| 
       14 
     | 
    
         
            -
                    return "rake" if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
         
     | 
| 
       15 
     | 
    
         
            -
                    binstub_path = File.join('bin', 'rake')
         
     | 
| 
       16 
     | 
    
         
            -
                    return binstub_path if File.exist?(binstub_path)
         
     | 
| 
       17 
     | 
    
         
            -
                    "rake"
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
12 
     | 
    
         
             
                  def load_lib
         
     | 
| 
       21 
     | 
    
         
            -
                    $LOAD_PATH << File.expand_path( 
     | 
| 
      
 13 
     | 
    
         
            +
                    $LOAD_PATH << File.expand_path('..', __dir__)
         
     | 
| 
       22 
14 
     | 
    
         
             
                    require "parallel_tests"
         
     | 
| 
       23 
15 
     | 
    
         
             
                  end
         
     | 
| 
       24 
16 
     | 
    
         | 
| 
         @@ -30,12 +22,15 @@ module ParallelTests 
     | 
|
| 
       30 
22 
     | 
    
         | 
| 
       31 
23 
     | 
    
         
             
                  def run_in_parallel(cmd, options = {})
         
     | 
| 
       32 
24 
     | 
    
         
             
                    load_lib
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       34 
26 
     | 
    
         
             
                    # Using the relative path to find the binary allow to run a specific version of it
         
     | 
| 
       35 
27 
     | 
    
         
             
                    executable = File.expand_path('../../bin/parallel_test', __dir__)
         
     | 
| 
       36 
     | 
    
         
            -
                     
     | 
| 
       37 
     | 
    
         
            -
                    command  
     | 
| 
       38 
     | 
    
         
            -
                     
     | 
| 
      
 28 
     | 
    
         
            +
                    command = ParallelTests.with_ruby_binary(executable)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    command += ['--exec', Shellwords.join(cmd)]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    command += ['-n', options[:count]] unless options[:count].to_s.empty?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    command << '--non-parallel' if options[:non_parallel]
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    abort unless system(*command)
         
     | 
| 
       39 
34 
     | 
    
         
             
                  end
         
     | 
| 
       40 
35 
     | 
    
         | 
| 
       41 
36 
     | 
    
         
             
                  # this is a crazy-complex solution for a very simple problem:
         
     | 
| 
         @@ -48,16 +43,14 @@ module ParallelTests 
     | 
|
| 
       48 
43 
     | 
    
         
             
                  # - pipefail makes pipe fail with exitstatus of first failed command
         
     | 
| 
       49 
44 
     | 
    
         
             
                  # - pipefail is not supported in (zsh)
         
     | 
| 
       50 
45 
     | 
    
         
             
                  # - defining a new rake task like silence_schema would force users to load parallel_tests in test env
         
     | 
| 
       51 
     | 
    
         
            -
                  # - do not use ' since run_in_parallel uses them to quote stuff
         
     | 
| 
       52 
46 
     | 
    
         
             
                  # - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
         
     | 
| 
       53 
47 
     | 
    
         
             
                  def suppress_output(command, ignore_regex)
         
     | 
| 
       54 
48 
     | 
    
         
             
                    activate_pipefail = "set -o pipefail"
         
     | 
| 
       55 
     | 
    
         
            -
                    remove_ignored_lines = %{(grep -v  
     | 
| 
      
 49 
     | 
    
         
            +
                    remove_ignored_lines = %{(grep -v #{Shellwords.escape(ignore_regex)} || true)}
         
     | 
| 
       56 
50 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                    if  
     | 
| 
       58 
     | 
    
         
            -
                       
     | 
| 
       59 
     | 
    
         
            -
                       
     | 
| 
       60 
     | 
    
         
            -
                      %{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
         
     | 
| 
      
 51 
     | 
    
         
            +
                    if system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null")
         
     | 
| 
      
 52 
     | 
    
         
            +
                      shell_command = "#{activate_pipefail} && (#{Shellwords.shelljoin(command)}) | #{remove_ignored_lines}"
         
     | 
| 
      
 53 
     | 
    
         
            +
                      ['/bin/bash', '-c', shell_command]
         
     | 
| 
       61 
54 
     | 
    
         
             
                    else
         
     | 
| 
       62 
55 
     | 
    
         
             
                      command
         
     | 
| 
       63 
56 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -90,7 +83,56 @@ module ParallelTests 
     | 
|
| 
       90 
83 
     | 
    
         
             
                    options = args.shift
         
     | 
| 
       91 
84 
     | 
    
         
             
                    pass_through = args.shift
         
     | 
| 
       92 
85 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                    [num_processes, pattern 
     | 
| 
      
 86 
     | 
    
         
            +
                    [num_processes, pattern, options, pass_through]
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  def schema_format_based_on_rails_version
         
     | 
| 
      
 90 
     | 
    
         
            +
                    if rails_7_or_greater?
         
     | 
| 
      
 91 
     | 
    
         
            +
                      ActiveRecord.schema_format
         
     | 
| 
      
 92 
     | 
    
         
            +
                    else
         
     | 
| 
      
 93 
     | 
    
         
            +
                      ActiveRecord::Base.schema_format
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  def schema_type_based_on_rails_version
         
     | 
| 
      
 98 
     | 
    
         
            +
                    if rails_61_or_greater? || schema_format_based_on_rails_version == :ruby
         
     | 
| 
      
 99 
     | 
    
         
            +
                      "schema"
         
     | 
| 
      
 100 
     | 
    
         
            +
                    else
         
     | 
| 
      
 101 
     | 
    
         
            +
                      "structure"
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  def build_run_command(type, args)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    count, pattern, options, pass_through = ParallelTests::Tasks.parse_args(args)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    test_framework = {
         
     | 
| 
      
 108 
     | 
    
         
            +
                      'spec' => 'rspec',
         
     | 
| 
      
 109 
     | 
    
         
            +
                      'test' => 'test',
         
     | 
| 
      
 110 
     | 
    
         
            +
                      'features' => 'cucumber',
         
     | 
| 
      
 111 
     | 
    
         
            +
                      'features-spinach' => 'spinach'
         
     | 
| 
      
 112 
     | 
    
         
            +
                    }.fetch(type)
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    type = 'features' if test_framework == 'spinach'
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    # Using the relative path to find the binary allow to run a specific version of it
         
     | 
| 
      
 117 
     | 
    
         
            +
                    executable = File.expand_path('../../bin/parallel_test', __dir__)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    executable = ParallelTests.with_ruby_binary(executable)
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                    command = [*executable, type, '--type', test_framework]
         
     | 
| 
      
 121 
     | 
    
         
            +
                    command += ['-n', count.to_s] if count
         
     | 
| 
      
 122 
     | 
    
         
            +
                    command += ['--pattern', pattern] if pattern
         
     | 
| 
      
 123 
     | 
    
         
            +
                    command += ['--test-options', options] if options
         
     | 
| 
      
 124 
     | 
    
         
            +
                    command += Shellwords.shellsplit pass_through if pass_through
         
     | 
| 
      
 125 
     | 
    
         
            +
                    command
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  private
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  def rails_7_or_greater?
         
     | 
| 
      
 131 
     | 
    
         
            +
                    Gem::Version.new(Rails.version) >= Gem::Version.new('7.0')
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  def rails_61_or_greater?
         
     | 
| 
      
 135 
     | 
    
         
            +
                    Gem::Version.new(Rails.version) >= Gem::Version.new('6.1.0')
         
     | 
| 
       94 
136 
     | 
    
         
             
                  end
         
     | 
| 
       95 
137 
     | 
    
         
             
                end
         
     | 
| 
       96 
138 
     | 
    
         
             
              end
         
     | 
| 
         @@ -99,36 +141,38 @@ end 
     | 
|
| 
       99 
141 
     | 
    
         
             
            namespace :parallel do
         
     | 
| 
       100 
142 
     | 
    
         
             
              desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
         
     | 
| 
       101 
143 
     | 
    
         
             
              task :setup, :count do |_, args|
         
     | 
| 
       102 
     | 
    
         
            -
                command = " 
     | 
| 
      
 144 
     | 
    
         
            +
                command = [$0, "db:setup", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"]
         
     | 
| 
       103 
145 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
         
     | 
| 
       104 
146 
     | 
    
         
             
              end
         
     | 
| 
       105 
147 
     | 
    
         | 
| 
       106 
148 
     | 
    
         
             
              desc "Create test databases via db:create --> parallel:create[num_cpus]"
         
     | 
| 
       107 
149 
     | 
    
         
             
              task :create, :count do |_, args|
         
     | 
| 
       108 
150 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       109 
     | 
    
         
            -
                  " 
     | 
| 
      
 151 
     | 
    
         
            +
                  [$0, "db:create", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
         
     | 
| 
      
 152 
     | 
    
         
            +
                  args
         
     | 
| 
       110 
153 
     | 
    
         
             
                )
         
     | 
| 
       111 
154 
     | 
    
         
             
              end
         
     | 
| 
       112 
155 
     | 
    
         | 
| 
       113 
156 
     | 
    
         
             
              desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
         
     | 
| 
       114 
157 
     | 
    
         
             
              task :drop, :count do |_, args|
         
     | 
| 
       115 
158 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       116 
     | 
    
         
            -
                   
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
      
 159 
     | 
    
         
            +
                  [
         
     | 
| 
      
 160 
     | 
    
         
            +
                    $0,
         
     | 
| 
      
 161 
     | 
    
         
            +
                    "db:drop",
         
     | 
| 
      
 162 
     | 
    
         
            +
                    "RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
         
     | 
| 
      
 163 
     | 
    
         
            +
                    "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
         
     | 
| 
      
 164 
     | 
    
         
            +
                  ],
         
     | 
| 
      
 165 
     | 
    
         
            +
                  args
         
     | 
| 
       118 
166 
     | 
    
         
             
                )
         
     | 
| 
       119 
167 
     | 
    
         
             
              end
         
     | 
| 
       120 
168 
     | 
    
         | 
| 
       121 
169 
     | 
    
         
             
              desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
         
     | 
| 
       122 
170 
     | 
    
         
             
              task(:prepare, [:count]) do |_, args|
         
     | 
| 
       123 
171 
     | 
    
         
             
                ParallelTests::Tasks.check_for_pending_migrations
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                if defined?(ActiveRecord) && [:ruby, :sql].include?(ParallelTests::Tasks.schema_format_based_on_rails_version)
         
     | 
| 
       125 
174 
     | 
    
         
             
                  # fast: dump once, load in parallel
         
     | 
| 
       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
         
     | 
| 
      
 175 
     | 
    
         
            +
                  type = ParallelTests::Tasks.schema_type_based_on_rails_version
         
     | 
| 
       132 
176 
     | 
    
         | 
| 
       133 
177 
     | 
    
         
             
                  Rake::Task["db:#{type}:dump"].invoke
         
     | 
| 
       134 
178 
     | 
    
         | 
| 
         @@ -140,7 +184,7 @@ namespace :parallel do 
     | 
|
| 
       140 
184 
     | 
    
         
             
                  # slow: dump and load in in serial
         
     | 
| 
       141 
185 
     | 
    
         
             
                  args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
         
     | 
| 
       142 
186 
     | 
    
         
             
                  task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
         
     | 
| 
       143 
     | 
    
         
            -
                  ParallelTests::Tasks.run_in_parallel( 
     | 
| 
      
 187 
     | 
    
         
            +
                  ParallelTests::Tasks.run_in_parallel([$0, task_name], args)
         
     | 
| 
       144 
188 
     | 
    
         
             
                  next
         
     | 
| 
       145 
189 
     | 
    
         
             
                end
         
     | 
| 
       146 
190 
     | 
    
         
             
              end
         
     | 
| 
         @@ -149,22 +193,29 @@ namespace :parallel do 
     | 
|
| 
       149 
193 
     | 
    
         
             
              desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
         
     | 
| 
       150 
194 
     | 
    
         
             
              task :migrate, :count do |_, args|
         
     | 
| 
       151 
195 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       152 
     | 
    
         
            -
                  " 
     | 
| 
      
 196 
     | 
    
         
            +
                  [$0, "db:migrate", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
         
     | 
| 
      
 197 
     | 
    
         
            +
                  args
         
     | 
| 
       153 
198 
     | 
    
         
             
                )
         
     | 
| 
       154 
199 
     | 
    
         
             
              end
         
     | 
| 
       155 
200 
     | 
    
         | 
| 
       156 
201 
     | 
    
         
             
              desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
         
     | 
| 
       157 
202 
     | 
    
         
             
              task :rollback, :count do |_, args|
         
     | 
| 
       158 
203 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       159 
     | 
    
         
            -
                  " 
     | 
| 
      
 204 
     | 
    
         
            +
                  [$0, "db:rollback", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
         
     | 
| 
      
 205 
     | 
    
         
            +
                  args
         
     | 
| 
       160 
206 
     | 
    
         
             
                )
         
     | 
| 
       161 
207 
     | 
    
         
             
              end
         
     | 
| 
       162 
208 
     | 
    
         | 
| 
       163 
209 
     | 
    
         
             
              # just load the schema (good for integration server <-> no development db)
         
     | 
| 
       164 
210 
     | 
    
         
             
              desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
         
     | 
| 
       165 
211 
     | 
    
         
             
              task :load_schema, :count do |_, args|
         
     | 
| 
       166 
     | 
    
         
            -
                command =  
     | 
| 
       167 
     | 
    
         
            -
                   
     | 
| 
      
 212 
     | 
    
         
            +
                command = [
         
     | 
| 
      
 213 
     | 
    
         
            +
                  $0,
         
     | 
| 
      
 214 
     | 
    
         
            +
                  ParallelTests::Tasks.purge_before_load,
         
     | 
| 
      
 215 
     | 
    
         
            +
                  "db:schema:load",
         
     | 
| 
      
 216 
     | 
    
         
            +
                  "RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
         
     | 
| 
      
 217 
     | 
    
         
            +
                  "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
         
     | 
| 
      
 218 
     | 
    
         
            +
                ]
         
     | 
| 
       168 
219 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
         
     | 
| 
       169 
220 
     | 
    
         
             
              end
         
     | 
| 
       170 
221 
     | 
    
         | 
| 
         @@ -173,23 +224,34 @@ namespace :parallel do 
     | 
|
| 
       173 
224 
     | 
    
         
             
              desc "Load structure for test databases via db:schema:load --> parallel:load_structure[num_cpus]"
         
     | 
| 
       174 
225 
     | 
    
         
             
              task :load_structure, :count do |_, args|
         
     | 
| 
       175 
226 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       176 
     | 
    
         
            -
                   
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
      
 227 
     | 
    
         
            +
                  [
         
     | 
| 
      
 228 
     | 
    
         
            +
                    $0,
         
     | 
| 
      
 229 
     | 
    
         
            +
                    ParallelTests::Tasks.purge_before_load,
         
     | 
| 
      
 230 
     | 
    
         
            +
                    "db:structure:load",
         
     | 
| 
      
 231 
     | 
    
         
            +
                    "RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
         
     | 
| 
      
 232 
     | 
    
         
            +
                    "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
         
     | 
| 
      
 233 
     | 
    
         
            +
                  ],
         
     | 
| 
      
 234 
     | 
    
         
            +
                  args
         
     | 
| 
       178 
235 
     | 
    
         
             
                )
         
     | 
| 
       179 
236 
     | 
    
         
             
              end
         
     | 
| 
       180 
237 
     | 
    
         | 
| 
       181 
238 
     | 
    
         
             
              desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
         
     | 
| 
       182 
239 
     | 
    
         
             
              task :seed, :count do |_, args|
         
     | 
| 
       183 
240 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       184 
     | 
    
         
            -
                   
     | 
| 
      
 241 
     | 
    
         
            +
                  [
         
     | 
| 
      
 242 
     | 
    
         
            +
                    $0,
         
     | 
| 
      
 243 
     | 
    
         
            +
                    "db:seed",
         
     | 
| 
      
 244 
     | 
    
         
            +
                    "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
         
     | 
| 
      
 245 
     | 
    
         
            +
                  ],
         
     | 
| 
      
 246 
     | 
    
         
            +
                  args
         
     | 
| 
       185 
247 
     | 
    
         
             
                )
         
     | 
| 
       186 
248 
     | 
    
         
             
              end
         
     | 
| 
       187 
249 
     | 
    
         | 
| 
       188 
250 
     | 
    
         
             
              desc "Launch given rake command in parallel"
         
     | 
| 
       189 
251 
     | 
    
         
             
              task :rake, :command, :count do |_, args|
         
     | 
| 
       190 
252 
     | 
    
         
             
                ParallelTests::Tasks.run_in_parallel(
         
     | 
| 
       191 
     | 
    
         
            -
                  "RAILS_ENV=#{ParallelTests::Tasks.rails_env} 
     | 
| 
       192 
     | 
    
         
            -
                   
     | 
| 
      
 253 
     | 
    
         
            +
                  [$0, args.command, "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
         
     | 
| 
      
 254 
     | 
    
         
            +
                  args
         
     | 
| 
       193 
255 
     | 
    
         
             
                )
         
     | 
| 
       194 
256 
     | 
    
         
             
              end
         
     | 
| 
       195 
257 
     | 
    
         | 
| 
         @@ -198,26 +260,9 @@ namespace :parallel do 
     | 
|
| 
       198 
260 
     | 
    
         
             
                task type, [:count, :pattern, :options, :pass_through] do |_t, args|
         
     | 
| 
       199 
261 
     | 
    
         
             
                  ParallelTests::Tasks.check_for_pending_migrations
         
     | 
| 
       200 
262 
     | 
    
         
             
                  ParallelTests::Tasks.load_lib
         
     | 
| 
      
 263 
     | 
    
         
            +
                  command = ParallelTests::Tasks.build_run_command(type, args)
         
     | 
| 
       201 
264 
     | 
    
         | 
| 
       202 
     | 
    
         
            -
                   
     | 
| 
       203 
     | 
    
         
            -
                  test_framework = {
         
     | 
| 
       204 
     | 
    
         
            -
                    'spec' => 'rspec',
         
     | 
| 
       205 
     | 
    
         
            -
                    'test' => 'test',
         
     | 
| 
       206 
     | 
    
         
            -
                    'features' => 'cucumber',
         
     | 
| 
       207 
     | 
    
         
            -
                    'features-spinach' => 'spinach'
         
     | 
| 
       208 
     | 
    
         
            -
                  }[type]
         
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
                  type = 'features' if test_framework == 'spinach'
         
     | 
| 
       211 
     | 
    
         
            -
                  # Using the relative path to find the binary allow to run a specific version of it
         
     | 
| 
       212 
     | 
    
         
            -
                  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
         
     | 
| 
       213 
     | 
    
         
            -
             
     | 
| 
       214 
     | 
    
         
            -
                  command = "#{ParallelTests.with_ruby_binary(Shellwords.escape(executable))} #{type} " \
         
     | 
| 
       215 
     | 
    
         
            -
                    "--type #{test_framework} "        \
         
     | 
| 
       216 
     | 
    
         
            -
                    "-n #{count} "                     \
         
     | 
| 
       217 
     | 
    
         
            -
                    "--pattern '#{pattern}' "          \
         
     | 
| 
       218 
     | 
    
         
            -
                    "--test-options '#{options}' "     \
         
     | 
| 
       219 
     | 
    
         
            -
                    "#{pass_through}"
         
     | 
| 
       220 
     | 
    
         
            -
                  abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
         
     | 
| 
      
 265 
     | 
    
         
            +
                  abort unless system(*command) # allow to chain tasks e.g. rake parallel:spec parallel:features
         
     | 
| 
       221 
266 
     | 
    
         
             
                end
         
     | 
| 
       222 
267 
     | 
    
         
             
              end
         
     | 
| 
       223 
268 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,9 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'shellwords'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'parallel_tests'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            module ParallelTests
         
     | 
| 
       5 
6 
     | 
    
         
             
              module Test
         
     | 
| 
       6 
7 
     | 
    
         
             
                class Runner
         
     | 
| 
      
 8 
     | 
    
         
            +
                  RuntimeLogTooSmallError = Class.new(StandardError)
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       7 
10 
     | 
    
         
             
                  class << self
         
     | 
| 
       8 
11 
     | 
    
         
             
                    # --- usually overwritten by other runners
         
     | 
| 
       9 
12 
     | 
    
         | 
| 
         @@ -25,7 +28,14 @@ module ParallelTests 
     | 
|
| 
       25 
28 
     | 
    
         | 
| 
       26 
29 
     | 
    
         
             
                    def run_tests(test_files, process_number, num_processes, options)
         
     | 
| 
       27 
30 
     | 
    
         
             
                      require_list = test_files.map { |file| file.gsub(" ", "\\ ") }.join(" ")
         
     | 
| 
       28 
     | 
    
         
            -
                      cmd =  
     | 
| 
      
 31 
     | 
    
         
            +
                      cmd = [
         
     | 
| 
      
 32 
     | 
    
         
            +
                        *executable,
         
     | 
| 
      
 33 
     | 
    
         
            +
                        '-Itest',
         
     | 
| 
      
 34 
     | 
    
         
            +
                        '-e',
         
     | 
| 
      
 35 
     | 
    
         
            +
                        "%w[#{require_list}].each { |f| require %{./\#{f}} }",
         
     | 
| 
      
 36 
     | 
    
         
            +
                        '--',
         
     | 
| 
      
 37 
     | 
    
         
            +
                        *options[:test_options]
         
     | 
| 
      
 38 
     | 
    
         
            +
                      ]
         
     | 
| 
       29 
39 
     | 
    
         
             
                      execute_command(cmd, process_number, num_processes, options)
         
     | 
| 
       30 
40 
     | 
    
         
             
                    end
         
     | 
| 
       31 
41 
     | 
    
         | 
| 
         @@ -63,7 +73,7 @@ module ParallelTests 
     | 
|
| 
       63 
73 
     | 
    
         
             
                          []
         
     | 
| 
       64 
74 
     | 
    
         
             
                        end
         
     | 
| 
       65 
75 
     | 
    
         
             
                        if runtimes.size * 1.5 > tests.size
         
     | 
| 
       66 
     | 
    
         
            -
                          puts "Using recorded test runtime"
         
     | 
| 
      
 76 
     | 
    
         
            +
                          puts "Using recorded test runtime" unless options[:quiet]
         
     | 
| 
       67 
77 
     | 
    
         
             
                          sort_by_runtime(tests, runtimes)
         
     | 
| 
       68 
78 
     | 
    
         
             
                        else
         
     | 
| 
       69 
79 
     | 
    
         
             
                          sort_by_filesize(tests)
         
     | 
| 
         @@ -76,22 +86,33 @@ module ParallelTests 
     | 
|
| 
       76 
86 
     | 
    
         
             
                    end
         
     | 
| 
       77 
87 
     | 
    
         | 
| 
       78 
88 
     | 
    
         
             
                    def execute_command(cmd, process_number, num_processes, options)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      number = test_env_number(process_number, options).to_s
         
     | 
| 
       79 
90 
     | 
    
         
             
                      env = (options[:env] || {}).merge(
         
     | 
| 
       80 
     | 
    
         
            -
                        "TEST_ENV_NUMBER" =>  
     | 
| 
      
 91 
     | 
    
         
            +
                        "TEST_ENV_NUMBER" => number,
         
     | 
| 
       81 
92 
     | 
    
         
             
                        "PARALLEL_TEST_GROUPS" => num_processes.to_s,
         
     | 
| 
       82 
93 
     | 
    
         
             
                        "PARALLEL_PID_FILE" => ParallelTests.pid_file_path
         
     | 
| 
       83 
94 
     | 
    
         
             
                      )
         
     | 
| 
       84 
     | 
    
         
            -
                      cmd = "nice  
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
      
 95 
     | 
    
         
            +
                      cmd = ["nice", *cmd] if options[:nice]
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                      # being able to run with for example `-output foo-$TEST_ENV_NUMBER` worked originally and is convenient
         
     | 
| 
      
 98 
     | 
    
         
            +
                      cmd = cmd.map { |c| c.gsub("$TEST_ENV_NUMBER", number).gsub("${TEST_ENV_NUMBER}", number) }
         
     | 
| 
       86 
99 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
                       
     | 
| 
      
 100 
     | 
    
         
            +
                      print_command(cmd, env) if report_process_command?(options) && !options[:serialize_stdout]
         
     | 
| 
       88 
101 
     | 
    
         | 
| 
       89 
102 
     | 
    
         
             
                      execute_command_and_capture_output(env, cmd, options)
         
     | 
| 
       90 
103 
     | 
    
         
             
                    end
         
     | 
| 
       91 
104 
     | 
    
         | 
| 
      
 105 
     | 
    
         
            +
                    def print_command(command, env)
         
     | 
| 
      
 106 
     | 
    
         
            +
                      env_str = ['TEST_ENV_NUMBER', 'PARALLEL_TEST_GROUPS'].map { |e| "#{e}=#{env[e]}" }.join(' ')
         
     | 
| 
      
 107 
     | 
    
         
            +
                      puts [env_str, Shellwords.shelljoin(command)].compact.join(' ')
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
       92 
110 
     | 
    
         
             
                    def execute_command_and_capture_output(env, cmd, options)
         
     | 
| 
      
 111 
     | 
    
         
            +
                      popen_options = {} # do not add `pgroup: true`, it will break `binding.irb` inside the test
         
     | 
| 
      
 112 
     | 
    
         
            +
                      popen_options[:err] = [:child, :out] if options[:combine_stderr]
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
       93 
114 
     | 
    
         
             
                      pid = nil
         
     | 
| 
       94 
     | 
    
         
            -
                      output = IO.popen(env, cmd) do |io|
         
     | 
| 
      
 115 
     | 
    
         
            +
                      output = IO.popen(env, cmd, popen_options) do |io|
         
     | 
| 
       95 
116 
     | 
    
         
             
                        pid = io.pid
         
     | 
| 
       96 
117 
     | 
    
         
             
                        ParallelTests.pids.add(pid)
         
     | 
| 
       97 
118 
     | 
    
         
             
                        capture_output(io, env, options)
         
     | 
| 
         @@ -100,9 +121,9 @@ module ParallelTests 
     | 
|
| 
       100 
121 
     | 
    
         
             
                      exitstatus = $?.exitstatus
         
     | 
| 
       101 
122 
     | 
    
         
             
                      seed = output[/seed (\d+)/, 1]
         
     | 
| 
       102 
123 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
                      output =  
     | 
| 
      
 124 
     | 
    
         
            +
                      output = "#{Shellwords.shelljoin(cmd)}\n#{output}" if report_process_command?(options) && options[:serialize_stdout]
         
     | 
| 
       104 
125 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
                      { stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
         
     | 
| 
      
 126 
     | 
    
         
            +
                      { env: env, stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
         
     | 
| 
       106 
127 
     | 
    
         
             
                    end
         
     | 
| 
       107 
128 
     | 
    
         | 
| 
       108 
129 
     | 
    
         
             
                    def find_results(test_output)
         
     | 
| 
         @@ -129,18 +150,22 @@ module ParallelTests 
     | 
|
| 
       129 
150 
     | 
    
         | 
| 
       130 
151 
     | 
    
         
             
                    # remove old seed and add new seed
         
     | 
| 
       131 
152 
     | 
    
         
             
                    def command_with_seed(cmd, seed)
         
     | 
| 
       132 
     | 
    
         
            -
                      clean = cmd 
     | 
| 
       133 
     | 
    
         
            -
                       
     | 
| 
      
 153 
     | 
    
         
            +
                      clean = remove_command_arguments(cmd, '--seed')
         
     | 
| 
      
 154 
     | 
    
         
            +
                      [*clean, '--seed', seed]
         
     | 
| 
       134 
155 
     | 
    
         
             
                    end
         
     | 
| 
       135 
156 
     | 
    
         | 
| 
       136 
157 
     | 
    
         
             
                    protected
         
     | 
| 
       137 
158 
     | 
    
         | 
| 
       138 
159 
     | 
    
         
             
                    def executable
         
     | 
| 
       139 
     | 
    
         
            -
                      ENV['PARALLEL_TESTS_EXECUTABLE'] 
     | 
| 
      
 160 
     | 
    
         
            +
                      if (executable = ENV['PARALLEL_TESTS_EXECUTABLE'])
         
     | 
| 
      
 161 
     | 
    
         
            +
                        [executable]
         
     | 
| 
      
 162 
     | 
    
         
            +
                      else
         
     | 
| 
      
 163 
     | 
    
         
            +
                        determine_executable
         
     | 
| 
      
 164 
     | 
    
         
            +
                      end
         
     | 
| 
       140 
165 
     | 
    
         
             
                    end
         
     | 
| 
       141 
166 
     | 
    
         | 
| 
       142 
167 
     | 
    
         
             
                    def determine_executable
         
     | 
| 
       143 
     | 
    
         
            -
                      "ruby"
         
     | 
| 
      
 168 
     | 
    
         
            +
                      ["ruby"]
         
     | 
| 
       144 
169 
     | 
    
         
             
                    end
         
     | 
| 
       145 
170 
     | 
    
         | 
| 
       146 
171 
     | 
    
         
             
                    def sum_up_results(results)
         
     | 
| 
         @@ -184,7 +209,7 @@ module ParallelTests 
     | 
|
| 
       184 
209 
     | 
    
         
             
                        allowed_missing -= 1 unless time = runtimes[test]
         
     | 
| 
       185 
210 
     | 
    
         
             
                        if allowed_missing < 0
         
     | 
| 
       186 
211 
     | 
    
         
             
                          log = options[:runtime_log] || runtime_log
         
     | 
| 
       187 
     | 
    
         
            -
                          raise "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update or remove it."
         
     | 
| 
      
 212 
     | 
    
         
            +
                          raise RuntimeLogTooSmallError, "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update or remove it."
         
     | 
| 
       188 
213 
     | 
    
         
             
                        end
         
     | 
| 
       189 
214 
     | 
    
         
             
                        [test, time]
         
     | 
| 
       190 
215 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -237,6 +262,21 @@ module ParallelTests 
     | 
|
| 
       237 
262 
     | 
    
         
             
                      Dir[File.join(folder, pattern)].uniq.sort
         
     | 
| 
       238 
263 
     | 
    
         
             
                    end
         
     | 
| 
       239 
264 
     | 
    
         | 
| 
      
 265 
     | 
    
         
            +
                    def remove_command_arguments(command, *args)
         
     | 
| 
      
 266 
     | 
    
         
            +
                      remove_next = false
         
     | 
| 
      
 267 
     | 
    
         
            +
                      command.select do |arg|
         
     | 
| 
      
 268 
     | 
    
         
            +
                        if remove_next
         
     | 
| 
      
 269 
     | 
    
         
            +
                          remove_next = false
         
     | 
| 
      
 270 
     | 
    
         
            +
                          false
         
     | 
| 
      
 271 
     | 
    
         
            +
                        elsif args.include?(arg)
         
     | 
| 
      
 272 
     | 
    
         
            +
                          remove_next = true
         
     | 
| 
      
 273 
     | 
    
         
            +
                          false
         
     | 
| 
      
 274 
     | 
    
         
            +
                        else
         
     | 
| 
      
 275 
     | 
    
         
            +
                          true
         
     | 
| 
      
 276 
     | 
    
         
            +
                        end
         
     | 
| 
      
 277 
     | 
    
         
            +
                      end
         
     | 
| 
      
 278 
     | 
    
         
            +
                    end
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
       240 
280 
     | 
    
         
             
                    private
         
     | 
| 
       241 
281 
     | 
    
         | 
| 
       242 
282 
     | 
    
         
             
                    # fill gaps with unknown-runtime if given, average otherwise
         
     | 
| 
         @@ -250,7 +290,7 @@ module ParallelTests 
     | 
|
| 
       250 
290 
     | 
    
         
             
                    end
         
     | 
| 
       251 
291 
     | 
    
         | 
| 
       252 
292 
     | 
    
         
             
                    def report_process_command?(options)
         
     | 
| 
       253 
     | 
    
         
            -
                      options[:verbose] || options[: 
     | 
| 
      
 293 
     | 
    
         
            +
                      options[:verbose] || options[:verbose_command]
         
     | 
| 
       254 
294 
     | 
    
         
             
                    end
         
     | 
| 
       255 
295 
     | 
    
         
             
                  end
         
     | 
| 
       256 
296 
     | 
    
         
             
                end
         
     | 
    
        data/lib/parallel_tests.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: parallel_tests
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version:  
     | 
| 
      
 4 
     | 
    
         
            +
              version: 4.2.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Michael Grosser
         
     | 
| 
       8 
     | 
    
         
            -
            autorequire: 
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2023-05-12 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: parallel
         
     | 
| 
         @@ -24,7 +24,7 @@ dependencies: 
     | 
|
| 
       24 
24 
     | 
    
         
             
                - - ">="
         
     | 
| 
       25 
25 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       26 
26 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       27 
     | 
    
         
            -
            description: 
     | 
| 
      
 27 
     | 
    
         
            +
            description:
         
     | 
| 
       28 
28 
     | 
    
         
             
            email: michael@grosser.it
         
     | 
| 
       29 
29 
     | 
    
         
             
            executables:
         
     | 
| 
       30 
30 
     | 
    
         
             
            - parallel_spinach
         
     | 
| 
         @@ -68,10 +68,10 @@ licenses: 
     | 
|
| 
       68 
68 
     | 
    
         
             
            - MIT
         
     | 
| 
       69 
69 
     | 
    
         
             
            metadata:
         
     | 
| 
       70 
70 
     | 
    
         
             
              bug_tracker_uri: https://github.com/grosser/parallel_tests/issues
         
     | 
| 
       71 
     | 
    
         
            -
              documentation_uri: https://github.com/grosser/parallel_tests/blob/ 
     | 
| 
       72 
     | 
    
         
            -
              source_code_uri: https://github.com/grosser/parallel_tests/tree/ 
     | 
| 
      
 71 
     | 
    
         
            +
              documentation_uri: https://github.com/grosser/parallel_tests/blob/v4.2.1/Readme.md
         
     | 
| 
      
 72 
     | 
    
         
            +
              source_code_uri: https://github.com/grosser/parallel_tests/tree/v4.2.1
         
     | 
| 
       73 
73 
     | 
    
         
             
              wiki_uri: https://github.com/grosser/parallel_tests/wiki
         
     | 
| 
       74 
     | 
    
         
            -
            post_install_message: 
     | 
| 
      
 74 
     | 
    
         
            +
            post_install_message:
         
     | 
| 
       75 
75 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       76 
76 
     | 
    
         
             
            require_paths:
         
     | 
| 
       77 
77 
     | 
    
         
             
            - lib
         
     | 
| 
         @@ -79,15 +79,15 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       79 
79 
     | 
    
         
             
              requirements:
         
     | 
| 
       80 
80 
     | 
    
         
             
              - - ">="
         
     | 
| 
       81 
81 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       82 
     | 
    
         
            -
                  version: 2. 
     | 
| 
      
 82 
     | 
    
         
            +
                  version: 2.7.0
         
     | 
| 
       83 
83 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       84 
84 
     | 
    
         
             
              requirements:
         
     | 
| 
       85 
85 
     | 
    
         
             
              - - ">="
         
     | 
| 
       86 
86 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       87 
87 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       88 
88 
     | 
    
         
             
            requirements: []
         
     | 
| 
       89 
     | 
    
         
            -
            rubygems_version: 3. 
     | 
| 
       90 
     | 
    
         
            -
            signing_key: 
     | 
| 
      
 89 
     | 
    
         
            +
            rubygems_version: 3.3.3
         
     | 
| 
      
 90 
     | 
    
         
            +
            signing_key:
         
     | 
| 
       91 
91 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       92 
92 
     | 
    
         
             
            summary: Run Test::Unit / RSpec / Cucumber / Spinach in parallel
         
     | 
| 
       93 
93 
     | 
    
         
             
            test_files: []
         
     |