parallel_tests 2.28.0 → 3.7.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,17 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  require 'parallel_tests'
2
3
 
3
4
  module ParallelTests
4
5
  module Test
5
6
  class Runner
6
- NAME = 'Test'
7
-
8
7
  class << self
9
8
  # --- usually overwritten by other runners
10
9
 
11
- def name
12
- NAME
13
- end
14
-
15
10
  def runtime_log
16
11
  'tmp/parallel_runtime_test.log'
17
12
  end
@@ -20,6 +15,10 @@ module ParallelTests
20
15
  /_(test|spec).rb$/
21
16
  end
22
17
 
18
+ def default_test_folder
19
+ "test"
20
+ end
21
+
23
22
  def test_file_name
24
23
  "test"
25
24
  end
@@ -38,7 +37,7 @@ module ParallelTests
38
37
  # --- usually used by other runners
39
38
 
40
39
  # finds all tests and partitions them into groups
41
- def tests_in_groups(tests, num_groups, options={})
40
+ def tests_in_groups(tests, num_groups, options = {})
42
41
  tests = tests_with_size(tests, options)
43
42
  Grouper.in_even_groups_by_size(tests, num_groups, options)
44
43
  end
@@ -52,10 +51,17 @@ module ParallelTests
52
51
  when :filesize
53
52
  sort_by_filesize(tests)
54
53
  when :runtime
55
- 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
+ )
56
58
  when nil
57
59
  # use recorded test runtime if we got enough data
58
- runtimes = runtimes(tests, options) rescue []
60
+ runtimes = begin
61
+ runtimes(tests, options)
62
+ rescue StandardError
63
+ []
64
+ end
59
65
  if runtimes.size * 1.5 > tests.size
60
66
  puts "Using recorded test runtime"
61
67
  sort_by_runtime(tests, runtimes)
@@ -73,12 +79,12 @@ module ParallelTests
73
79
  env = (options[:env] || {}).merge(
74
80
  "TEST_ENV_NUMBER" => test_env_number(process_number, options).to_s,
75
81
  "PARALLEL_TEST_GROUPS" => num_processes.to_s,
76
- "PARALLEL_PID_FILE" => ParallelTests.pid_file_path,
82
+ "PARALLEL_PID_FILE" => ParallelTests.pid_file_path
77
83
  )
78
84
  cmd = "nice #{cmd}" if options[:nice]
79
85
  cmd = "#{cmd} 2>&1" if options[:combine_stderr]
80
86
 
81
- puts cmd if options[:verbose] && !options[:serialize_stdout]
87
+ puts cmd if report_process_command?(options) && !options[:serialize_stdout]
82
88
 
83
89
  execute_command_and_capture_output(env, cmd, options)
84
90
  end
@@ -92,11 +98,11 @@ module ParallelTests
92
98
  end
93
99
  ParallelTests.pids.delete(pid) if pid
94
100
  exitstatus = $?.exitstatus
95
- seed = output[/seed (\d+)/,1]
101
+ seed = output[/seed (\d+)/, 1]
96
102
 
97
- output = [cmd, output].join("\n") if options[:verbose] && options[:serialize_stdout]
103
+ output = [cmd, output].join("\n") if report_process_command?(options) && options[:serialize_stdout]
98
104
 
99
- {:stdout => output, :exit_status => exitstatus, :command => cmd, :seed => seed}
105
+ { stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
100
106
  end
101
107
 
102
108
  def find_results(test_output)
@@ -108,7 +114,7 @@ module ParallelTests
108
114
  end.compact
109
115
  end
110
116
 
111
- def test_env_number(process_number, options={})
117
+ def test_env_number(process_number, options = {})
112
118
  if process_number == 0 && !options[:first_is_1]
113
119
  ''
114
120
  else
@@ -118,7 +124,7 @@ module ParallelTests
118
124
 
119
125
  def summarize_results(results)
120
126
  sums = sum_up_results(results)
121
- 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(', ')
122
128
  end
123
129
 
124
130
  # remove old seed and add new seed
@@ -138,19 +144,18 @@ module ParallelTests
138
144
  end
139
145
 
140
146
  def sum_up_results(results)
141
- results = results.join(' ').gsub(/s\b/,'') # combine and singularize results
147
+ results = results.join(' ').gsub(/s\b/, '') # combine and singularize results
142
148
  counts = results.scan(/(\d+) (\w+)/)
143
- counts.inject(Hash.new(0)) do |sum, (number, word)|
149
+ counts.each_with_object(Hash.new(0)) do |(number, word), sum|
144
150
  sum[word] += number.to_i
145
- sum
146
151
  end
147
152
  end
148
153
 
149
154
  # read output of the process and print it in chunks
150
- def capture_output(out, env, options={})
151
- result = ""
152
- loop do
153
- begin
155
+ def capture_output(out, env, options = {})
156
+ result = +""
157
+ begin
158
+ loop do
154
159
  read = out.readpartial(1000000) # read whatever chunk we can get
155
160
  if Encoding.default_internal
156
161
  read = read.force_encoding(Encoding.default_internal)
@@ -163,11 +168,13 @@ module ParallelTests
163
168
  $stdout.flush
164
169
  end
165
170
  end
166
- end rescue EOFError
171
+ rescue EOFError
172
+ nil
173
+ end
167
174
  result
168
175
  end
169
176
 
170
- def sort_by_runtime(tests, runtimes, options={})
177
+ def sort_by_runtime(tests, runtimes, options = {})
171
178
  allowed_missing = options[:allowed_missing] || 1.0
172
179
  allowed_missing = tests.size * allowed_missing
173
180
 
@@ -177,20 +184,14 @@ module ParallelTests
177
184
  allowed_missing -= 1 unless time = runtimes[test]
178
185
  if allowed_missing < 0
179
186
  log = options[:runtime_log] || runtime_log
180
- raise "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update it."
187
+ raise "Runtime log file '#{log}' does not contain sufficient data to sort #{tests.size} test files, please update or remove it."
181
188
  end
182
189
  [test, time]
183
190
  end
184
191
 
185
- if options[:verbose]
186
- puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests"
187
- end
192
+ puts "Runtime found for #{tests.count(&:last)} of #{tests.size} tests" if options[:verbose]
188
193
 
189
- # fill gaps with unknown-runtime if given, average otherwise
190
- known, unknown = tests.partition(&:last)
191
- average = (known.any? ? known.map!(&:last).inject(:+) / known.size : 1)
192
- unknown_runtime = options[:unknown_runtime] || average
193
- unknown.each { |set| set[1] = unknown_runtime }
194
+ set_unknown_runtime tests, options
194
195
  end
195
196
 
196
197
  def runtimes(tests, options)
@@ -198,7 +199,7 @@ module ParallelTests
198
199
  lines = File.read(log).split("\n")
199
200
  lines.each_with_object({}) do |line, times|
200
201
  test, _, time = line.rpartition(':')
201
- next unless test and time
202
+ next unless test && time
202
203
  times[test] = time.to_f if tests.include?(test)
203
204
  end
204
205
  end
@@ -225,7 +226,7 @@ module ParallelTests
225
226
  end.uniq
226
227
  end
227
228
 
228
- def files_in_folder(folder, options={})
229
+ def files_in_folder(folder, options = {})
229
230
  pattern = if options[:symlinks] == false # not nil or true
230
231
  "**/*"
231
232
  else
@@ -233,7 +234,23 @@ module ParallelTests
233
234
  # http://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob
234
235
  "**{,/*/**}/*"
235
236
  end
236
- Dir[File.join(folder, pattern)].uniq
237
+ Dir[File.join(folder, pattern)].uniq.sort
238
+ end
239
+
240
+ private
241
+
242
+ # fill gaps with unknown-runtime if given, average otherwise
243
+ # NOTE: an optimization could be doing runtime by average runtime per file size, but would need file checks
244
+ def set_unknown_runtime(tests, options)
245
+ known, unknown = tests.partition(&:last)
246
+ return if unknown.empty?
247
+ unknown_runtime = options[:unknown_runtime] ||
248
+ (known.empty? ? 1 : known.map!(&:last).sum / known.size) # average
249
+ unknown.each { |set| set[1] = unknown_runtime }
250
+ end
251
+
252
+ def report_process_command?(options)
253
+ options[:verbose] || options[:verbose_process_command]
237
254
  end
238
255
  end
239
256
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'parallel_tests'
2
3
  require 'parallel_tests/test/runner'
3
4
 
@@ -22,7 +23,7 @@ module ParallelTests
22
23
  separator = "\n"
23
24
  groups = logfile.read.split(separator).map { |line| line.split(":") }.group_by(&:first)
24
25
  lines = groups.map do |file, times|
25
- time = "%.2f" % times.map(&:last).map(&:to_f).inject(:+)
26
+ time = "%.2f" % times.map(&:last).map(&:to_f).sum
26
27
  "#{file}:#{time}"
27
28
  end
28
29
  logfile.rewind
@@ -34,7 +35,7 @@ module ParallelTests
34
35
  private
35
36
 
36
37
  def with_locked_log
37
- File.open(logfile, File::RDWR|File::CREAT) do |logfile|
38
+ File.open(logfile, File::RDWR | File::CREAT) do |logfile|
38
39
  logfile.flock(File::LOCK_EX)
39
40
  yield logfile
40
41
  end
@@ -59,7 +60,7 @@ module ParallelTests
59
60
  end
60
61
 
61
62
  def message(test, delta)
62
- return unless method = test.public_instance_methods(true).detect { |method| method =~ /^test_/ }
63
+ return unless method = test.public_instance_methods(true).detect { |m| m =~ /^test_/ }
63
64
  filename = test.instance_method(method).source_location.first.sub("#{Dir.pwd}/", "")
64
65
  "#{filename}:#{delta}"
65
66
  end
@@ -74,22 +75,26 @@ end
74
75
 
75
76
  if defined?(Minitest::Runnable) # Minitest 5
76
77
  class << Minitest::Runnable
77
- prepend(Module.new do
78
- def run(*)
79
- ParallelTests::Test::RuntimeLogger.log_test_run(self) do
80
- super
78
+ prepend(
79
+ Module.new do
80
+ def run(*)
81
+ ParallelTests::Test::RuntimeLogger.log_test_run(self) do
82
+ super
83
+ end
81
84
  end
82
85
  end
83
- end)
86
+ )
84
87
  end
85
88
 
86
89
  class << Minitest
87
- prepend(Module.new do
88
- def run(*args)
89
- result = super
90
- ParallelTests::Test::RuntimeLogger.unique_log
91
- result
90
+ prepend(
91
+ Module.new do
92
+ def run(*args)
93
+ result = super
94
+ ParallelTests::Test::RuntimeLogger.unique_log
95
+ result
96
+ end
92
97
  end
93
- end)
98
+ )
94
99
  end
95
100
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module ParallelTests
2
- VERSION = Version = '2.28.0'
3
+ VERSION = '3.7.0'
3
4
  end
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: 2.28.0
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-07 00:00:00.000000000 Z
11
+ date: 2021-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel
@@ -42,6 +42,7 @@ files:
42
42
  - lib/parallel_tests.rb
43
43
  - lib/parallel_tests/cli.rb
44
44
  - lib/parallel_tests/cucumber/failures_logger.rb
45
+ - lib/parallel_tests/cucumber/features_with_steps.rb
45
46
  - lib/parallel_tests/cucumber/runner.rb
46
47
  - lib/parallel_tests/cucumber/scenario_line_logger.rb
47
48
  - lib/parallel_tests/cucumber/scenarios.rb
@@ -62,10 +63,14 @@ files:
62
63
  - lib/parallel_tests/test/runner.rb
63
64
  - lib/parallel_tests/test/runtime_logger.rb
64
65
  - lib/parallel_tests/version.rb
65
- homepage: http://github.com/grosser/parallel_tests
66
+ homepage: https://github.com/grosser/parallel_tests
66
67
  licenses:
67
68
  - MIT
68
- metadata: {}
69
+ metadata:
70
+ bug_tracker_uri: https://github.com/grosser/parallel_tests/issues
71
+ documentation_uri: https://github.com/grosser/parallel_tests/blob/v3.7.0/Readme.md
72
+ source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.7.0
73
+ wiki_uri: https://github.com/grosser/parallel_tests/wiki
69
74
  post_install_message:
70
75
  rdoc_options: []
71
76
  require_paths:
@@ -74,15 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
79
  requirements:
75
80
  - - ">="
76
81
  - !ruby/object:Gem::Version
77
- version: 2.2.0
82
+ version: 2.5.0
78
83
  required_rubygems_version: !ruby/object:Gem::Requirement
79
84
  requirements:
80
85
  - - ">="
81
86
  - !ruby/object:Gem::Version
82
87
  version: '0'
83
88
  requirements: []
84
- rubyforge_project:
85
- rubygems_version: 2.7.6
89
+ rubygems_version: 3.1.3
86
90
  signing_key:
87
91
  specification_version: 4
88
92
  summary: Run Test::Unit / RSpec / Cucumber / Spinach in parallel