parallel_tests 3.2.0 → 3.5.2

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