parallel_tests 3.3.0 → 3.6.0

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.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'json'
2
3
 
3
4
  module ParallelTests
@@ -52,8 +53,8 @@ module ParallelTests
52
53
  sync { IO.write(file_path, pids.to_json) }
53
54
  end
54
55
 
55
- def sync
56
- mutex.synchronize { yield }
56
+ def sync(&block)
57
+ mutex.synchronize(&block)
57
58
  end
58
59
  end
59
60
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # rake tasks for Rails 3+
2
3
  module ParallelTests
3
4
  class Railtie < ::Rails::Railtie
@@ -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,11 @@ 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
+ end
28
+
29
+ def default_test_folder
30
+ "spec"
27
31
  end
28
32
 
29
33
  def test_file_name
@@ -48,6 +52,22 @@ module ParallelTests
48
52
  "#{clean} --seed #{seed}"
49
53
  end
50
54
 
55
+ # Summarize results from threads and colorize results based on failure and pending counts.
56
+ #
57
+ def summarize_results(results)
58
+ text = super
59
+ return text unless $stdout.tty?
60
+ sums = sum_up_results(results)
61
+ color =
62
+ if sums['failure'] > 0
63
+ 31 # red
64
+ elsif sums['pending'] > 0
65
+ 33 # yellow
66
+ else
67
+ 32 # green
68
+ end
69
+ "\e[#{color}m#{text}\e[0m"
70
+ end
51
71
 
52
72
  private
53
73
 
@@ -61,7 +81,7 @@ module ParallelTests
61
81
  end
62
82
 
63
83
  def spec_opts
64
- options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect{|f| File.file?(f) }
84
+ options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
65
85
  return unless options_file
66
86
  "-O #{options_file}"
67
87
  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
@@ -8,11 +9,14 @@ module ParallelTests
8
9
  'spinach'
9
10
  end
10
11
 
12
+ def default_test_folder
13
+ 'features'
14
+ end
15
+
11
16
  def runtime_logging
12
- #Not Yet Supported
17
+ # Not Yet Supported
13
18
  ""
14
19
  end
15
-
16
20
  end
17
21
  end
18
22
  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
@@ -14,6 +15,10 @@ module ParallelTests
14
15
  /_(test|spec).rb$/
15
16
  end
16
17
 
18
+ def default_test_folder
19
+ "test"
20
+ end
21
+
17
22
  def test_file_name
18
23
  "test"
19
24
  end
@@ -32,7 +37,7 @@ module ParallelTests
32
37
  # --- usually used by other runners
33
38
 
34
39
  # finds all tests and partitions them into groups
35
- def tests_in_groups(tests, num_groups, options={})
40
+ def tests_in_groups(tests, num_groups, options = {})
36
41
  tests = tests_with_size(tests, options)
37
42
  Grouper.in_even_groups_by_size(tests, num_groups, options)
38
43
  end
@@ -46,10 +51,17 @@ module ParallelTests
46
51
  when :filesize
47
52
  sort_by_filesize(tests)
48
53
  when :runtime
49
- sort_by_runtime(tests, runtimes(tests, options), options.merge(allowed_missing: (options[:allowed_missing_percent] || 50) / 100.0))
54
+ sort_by_runtime(
55
+ tests, runtimes(tests, options),
56
+ options.merge(allowed_missing: (options[:allowed_missing_percent] || 50) / 100.0)
57
+ )
50
58
  when nil
51
59
  # use recorded test runtime if we got enough data
52
- runtimes = runtimes(tests, options) rescue []
60
+ runtimes = begin
61
+ runtimes(tests, options)
62
+ rescue StandardError
63
+ []
64
+ end
53
65
  if runtimes.size * 1.5 > tests.size
54
66
  puts "Using recorded test runtime"
55
67
  sort_by_runtime(tests, runtimes)
@@ -67,7 +79,7 @@ module ParallelTests
67
79
  env = (options[:env] || {}).merge(
68
80
  "TEST_ENV_NUMBER" => test_env_number(process_number, options).to_s,
69
81
  "PARALLEL_TEST_GROUPS" => num_processes.to_s,
70
- "PARALLEL_PID_FILE" => ParallelTests.pid_file_path,
82
+ "PARALLEL_PID_FILE" => ParallelTests.pid_file_path
71
83
  )
72
84
  cmd = "nice #{cmd}" if options[:nice]
73
85
  cmd = "#{cmd} 2>&1" if options[:combine_stderr]
@@ -86,13 +98,11 @@ module ParallelTests
86
98
  end
87
99
  ParallelTests.pids.delete(pid) if pid
88
100
  exitstatus = $?.exitstatus
89
- seed = output[/seed (\d+)/,1]
101
+ seed = output[/seed (\d+)/, 1]
90
102
 
91
- if report_process_command?(options) && options[:serialize_stdout]
92
- output = [cmd, output].join("\n")
93
- end
103
+ output = [cmd, output].join("\n") if report_process_command?(options) && options[:serialize_stdout]
94
104
 
95
- {:stdout => output, :exit_status => exitstatus, :command => cmd, :seed => seed}
105
+ { stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
96
106
  end
97
107
 
98
108
  def find_results(test_output)
@@ -104,7 +114,7 @@ module ParallelTests
104
114
  end.compact
105
115
  end
106
116
 
107
- def test_env_number(process_number, options={})
117
+ def test_env_number(process_number, options = {})
108
118
  if process_number == 0 && !options[:first_is_1]
109
119
  ''
110
120
  else
@@ -114,7 +124,7 @@ module ParallelTests
114
124
 
115
125
  def summarize_results(results)
116
126
  sums = sum_up_results(results)
117
- sums.sort.map{|word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ')
127
+ sums.sort.map { |word, number| "#{number} #{word}#{'s' if number != 1}" }.join(', ')
118
128
  end
119
129
 
120
130
  # remove old seed and add new seed
@@ -134,19 +144,18 @@ module ParallelTests
134
144
  end
135
145
 
136
146
  def sum_up_results(results)
137
- results = results.join(' ').gsub(/s\b/,'') # combine and singularize results
147
+ results = results.join(' ').gsub(/s\b/, '') # combine and singularize results
138
148
  counts = results.scan(/(\d+) (\w+)/)
139
- counts.inject(Hash.new(0)) do |sum, (number, word)|
149
+ counts.each_with_object(Hash.new(0)) do |(number, word), sum|
140
150
  sum[word] += number.to_i
141
- sum
142
151
  end
143
152
  end
144
153
 
145
154
  # read output of the process and print it in chunks
146
- def capture_output(out, env, options={})
147
- result = ""
148
- loop do
149
- begin
155
+ def capture_output(out, env, options = {})
156
+ result = +""
157
+ begin
158
+ loop do
150
159
  read = out.readpartial(1000000) # read whatever chunk we can get
151
160
  if Encoding.default_internal
152
161
  read = read.force_encoding(Encoding.default_internal)
@@ -159,11 +168,13 @@ module ParallelTests
159
168
  $stdout.flush
160
169
  end
161
170
  end
162
- end rescue EOFError
171
+ rescue EOFError
172
+ nil
173
+ end
163
174
  result
164
175
  end
165
176
 
166
- def sort_by_runtime(tests, runtimes, options={})
177
+ def sort_by_runtime(tests, runtimes, options = {})
167
178
  allowed_missing = options[:allowed_missing] || 1.0
168
179
  allowed_missing = tests.size * allowed_missing
169
180
 
@@ -178,9 +189,7 @@ module ParallelTests
178
189
  [test, time]
179
190
  end
180
191
 
181
- if options[:verbose]
182
- puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests"
183
- end
192
+ puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests" if options[:verbose]
184
193
 
185
194
  set_unknown_runtime tests, options
186
195
  end
@@ -190,7 +199,7 @@ module ParallelTests
190
199
  lines = File.read(log).split("\n")
191
200
  lines.each_with_object({}) do |line, times|
192
201
  test, _, time = line.rpartition(':')
193
- next unless test and time
202
+ next unless test && time
194
203
  times[test] = time.to_f if tests.include?(test)
195
204
  end
196
205
  end
@@ -217,7 +226,7 @@ module ParallelTests
217
226
  end.uniq
218
227
  end
219
228
 
220
- def files_in_folder(folder, options={})
229
+ def files_in_folder(folder, options = {})
221
230
  pattern = if options[:symlinks] == false # not nil or true
222
231
  "**/*"
223
232
  else
@@ -225,7 +234,7 @@ module ParallelTests
225
234
  # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
226
235
  "**{,/*/**}/*"
227
236
  end
228
- Dir[File.join(folder, pattern)].uniq
237
+ Dir[File.join(folder, pattern)].uniq.sort
229
238
  end
230
239
 
231
240
  private
@@ -236,7 +245,7 @@ module ParallelTests
236
245
  known, unknown = tests.partition(&:last)
237
246
  return if unknown.empty?
238
247
  unknown_runtime = options[:unknown_runtime] ||
239
- (known.empty? ? 1 : known.map!(&:last).inject(:+) / known.size) # average
248
+ (known.empty? ? 1 : known.map!(&:last).sum / known.size) # average
240
249
  unknown.each { |set| set[1] = unknown_runtime }
241
250
  end
242
251