parallel_tests 3.0.0 → 3.5.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,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
 
@@ -5,7 +6,7 @@ module ParallelTests
5
6
  module Tasks
6
7
  class << self
7
8
  def rails_env
8
- ENV['RAILS_ENV'] || 'test'
9
+ 'test'
9
10
  end
10
11
 
11
12
  def rake_bin
@@ -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,26 +98,28 @@ 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
@@ -128,7 +132,7 @@ namespace :parallel do
128
132
  Rake::Task["parallel:load_#{type}"].invoke(args[:count])
129
133
  else
130
134
  # slow: dump and load in in serial
131
- args = args.to_hash.merge(:non_parallel => true) # normal merge returns nil
135
+ args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
132
136
  task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
133
137
  ParallelTests::Tasks.run_in_parallel("#{ParallelTests::Tasks.rake_bin} #{task_name}", args)
134
138
  next
@@ -137,20 +141,22 @@ namespace :parallel do
137
141
 
138
142
  # when dumping/resetting takes too long
139
143
  desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
140
- task :migrate, :count do |_,args|
144
+ task :migrate, :count do |_, args|
141
145
  ParallelTests::Tasks.run_in_parallel(
142
- "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
146
+ "#{ParallelTests::Tasks.rake_bin} db:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
147
+ )
143
148
  end
144
149
 
145
150
  desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
146
- task :rollback, :count do |_,args|
151
+ task :rollback, :count do |_, args|
147
152
  ParallelTests::Tasks.run_in_parallel(
148
- "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
153
+ "#{ParallelTests::Tasks.rake_bin} db:rollback RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
154
+ )
149
155
  end
150
156
 
151
157
  # just load the schema (good for integration server <-> no development db)
152
158
  desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
153
- task :load_schema, :count do |_,args|
159
+ task :load_schema, :count do |_, args|
154
160
  command = "#{ParallelTests::Tasks.rake_bin} #{ParallelTests::Tasks.purge_before_load} " \
155
161
  "db:schema:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
156
162
  ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
@@ -158,28 +164,31 @@ namespace :parallel do
158
164
 
159
165
  # load the structure from the structure.sql file
160
166
  desc "Load structure for test databases via db:structure:load --> parallel:load_structure[num_cpus]"
161
- task :load_structure, :count do |_,args|
167
+ task :load_structure, :count do |_, args|
162
168
  ParallelTests::Tasks.run_in_parallel(
163
169
  "#{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)
170
+ "db:structure:load RAILS_ENV=#{ParallelTests::Tasks.rails_env} DISABLE_DATABASE_ENVIRONMENT_CHECK=1", args
171
+ )
165
172
  end
166
173
 
167
174
  desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
168
- task :seed, :count do |_,args|
175
+ task :seed, :count do |_, args|
169
176
  ParallelTests::Tasks.run_in_parallel(
170
- "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
177
+ "#{ParallelTests::Tasks.rake_bin} db:seed RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args
178
+ )
171
179
  end
172
180
 
173
181
  desc "Launch given rake command in parallel"
174
182
  task :rake, :command, :count do |_, args|
175
183
  ParallelTests::Tasks.run_in_parallel(
176
184
  "RAILS_ENV=#{ParallelTests::Tasks.rails_env} #{ParallelTests::Tasks.rake_bin} " \
177
- "#{args.command}", args)
185
+ "#{args.command}", args
186
+ )
178
187
  end
179
188
 
180
189
  ['test', 'spec', 'features', 'features-spinach'].each do |type|
181
190
  desc "Run #{type} in parallel with parallel:#{type}[num_cpus]"
182
- task type, [:count, :pattern, :options, :pass_through] do |t, args|
191
+ task type, [:count, :pattern, :options, :pass_through] do |_t, args|
183
192
  ParallelTests::Tasks.check_for_pending_migrations
184
193
  ParallelTests::Tasks.load_lib
185
194
 
@@ -188,12 +197,10 @@ namespace :parallel do
188
197
  'spec' => 'rspec',
189
198
  'test' => 'test',
190
199
  'features' => 'cucumber',
191
- 'features-spinach' => 'spinach',
200
+ 'features-spinach' => 'spinach'
192
201
  }[type]
193
202
 
194
- if test_framework == 'spinach'
195
- type = 'features'
196
- end
203
+ type = 'features' if test_framework == 'spinach'
197
204
  # Using the relative path to find the binary allow to run a specific version of it
198
205
  executable = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'parallel_test')
199
206
 
@@ -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
 
@@ -173,14 +180,12 @@ module ParallelTests
173
180
  allowed_missing -= 1 unless time = runtimes[test]
174
181
  if allowed_missing < 0
175
182
  log = options[:runtime_log] || runtime_log
176
- raise "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update it."
183
+ raise "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update or remove it."
177
184
  end
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